1
0
mirror of https://github.com/FunkyFr3sh/cnc-ddraw.git synced 2025-03-20 16:09:12 +01:00
cnc-ddraw/src/render_d3d9.c

378 lines
11 KiB
C
Raw Normal View History

2018-09-28 22:40:44 +02:00
#include <windows.h>
#include <stdio.h>
#include <d3d9.h>
#include "main.h"
#include "surface.h"
#include "d3d9shader.h"
2018-10-15 03:31:57 +02:00
#include "render_d3d9.h"
2018-09-28 22:40:44 +02:00
#define TEXTURE_COUNT 2
2018-10-01 13:10:10 +02:00
2018-10-15 00:57:05 +02:00
HMODULE Direct3D9_hModule;
2018-10-07 16:49:35 +02:00
static D3DPRESENT_PARAMETERS D3dpp;
2018-10-01 13:10:10 +02:00
static LPDIRECT3D9 D3d;
static LPDIRECT3DDEVICE9 D3dDev;
static LPDIRECT3DVERTEXBUFFER9 VertexBuf;
static IDirect3DTexture9 *SurfaceTex[TEXTURE_COUNT];
static IDirect3DTexture9 *PaletteTex[TEXTURE_COUNT];
2018-10-01 13:10:10 +02:00
static IDirect3DPixelShader9 *PixelShader;
static float ScaleW;
static float ScaleH;
2018-10-02 03:25:34 +02:00
static int MaxFPS;
static DWORD FrameLength;
2018-10-09 11:46:40 +02:00
static int BitsPerPixel;
2018-10-02 03:25:34 +02:00
static BOOL CreateResources();
static BOOL SetStates();
2018-10-09 08:56:58 +02:00
static BOOL UpdateVertices(BOOL inCutscene);
static void SetMaxFPS();
2018-09-28 22:40:44 +02:00
2018-10-15 00:57:05 +02:00
BOOL Direct3D9_Create()
2018-09-28 22:40:44 +02:00
{
2018-10-15 00:57:05 +02:00
if (!Direct3D9_Release())
return FALSE;
2018-10-15 00:57:05 +02:00
if (!Direct3D9_hModule)
Direct3D9_hModule = LoadLibrary("d3d9.dll");
2018-10-15 00:57:05 +02:00
if (Direct3D9_hModule)
2018-09-28 22:40:44 +02:00
{
2018-10-02 03:25:34 +02:00
IDirect3D9 *(WINAPI *D3DCreate9)(UINT) =
2018-10-15 00:57:05 +02:00
(IDirect3D9 *(WINAPI *)(UINT))GetProcAddress(Direct3D9_hModule, "Direct3DCreate9");
2018-09-28 22:40:44 +02:00
if (D3DCreate9 && (D3d = D3DCreate9(D3D_SDK_VERSION)))
{
2018-10-09 11:46:40 +02:00
BitsPerPixel = ddraw->render.bpp ? ddraw->render.bpp : ddraw->mode.dmBitsPerPel;
D3dpp.Windowed = ddraw->windowed;
2018-09-28 22:40:44 +02:00
D3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
D3dpp.hDeviceWindow = ddraw->hWnd;
2018-09-28 23:10:58 +02:00
D3dpp.PresentationInterval = ddraw->vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
D3dpp.BackBufferWidth = D3dpp.Windowed ? 0 : ddraw->render.width;
D3dpp.BackBufferHeight = D3dpp.Windowed ? 0 : ddraw->render.height;
2018-10-09 11:46:40 +02:00
D3dpp.BackBufferFormat = BitsPerPixel == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
2018-09-28 22:40:44 +02:00
D3dpp.BackBufferCount = 1;
2018-10-02 03:25:34 +02:00
DWORD behaviorFlags[] = {
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
D3DCREATE_MIXED_VERTEXPROCESSING,
2018-09-28 22:40:44 +02:00
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
};
int i;
2018-10-02 03:25:34 +02:00
for (i = 0; i < sizeof(behaviorFlags) / sizeof(behaviorFlags[0]); i++)
{
2018-10-09 08:56:58 +02:00
if (SUCCEEDED(
2018-11-12 00:39:47 +01:00
IDirect3D9_CreateDevice(
2018-10-09 08:56:58 +02:00
D3d,
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
ddraw->hWnd,
D3DCREATE_MULTITHREADED | behaviorFlags[i],
2018-10-09 08:56:58 +02:00
&D3dpp,
&D3dDev)))
return D3dDev && CreateResources() && SetStates();
}
2018-09-28 22:40:44 +02:00
}
}
2018-10-09 08:56:58 +02:00
return FALSE;
2018-10-02 03:25:34 +02:00
}
2018-11-12 00:39:47 +01:00
BOOL Direct3D9_OnDeviceLost()
2018-10-15 00:57:05 +02:00
{
2018-11-12 00:39:47 +01:00
if (D3dDev && IDirect3DDevice9_TestCooperativeLevel(D3dDev) == D3DERR_DEVICENOTRESET)
2018-10-15 00:57:05 +02:00
return Direct3D9_Reset();
return FALSE;
}
BOOL Direct3D9_Reset()
{
D3dpp.Windowed = ddraw->windowed;
D3dpp.BackBufferWidth = D3dpp.Windowed ? 0 : ddraw->render.width;
D3dpp.BackBufferHeight = D3dpp.Windowed ? 0 : ddraw->render.height;
D3dpp.BackBufferFormat = BitsPerPixel == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
2018-11-12 00:39:47 +01:00
if (D3dDev && SUCCEEDED(IDirect3DDevice9_Reset(D3dDev, &D3dpp)))
2018-10-15 00:57:05 +02:00
return SetStates();
return FALSE;
}
BOOL Direct3D9_Release()
{
if (VertexBuf)
{
2018-11-12 00:39:47 +01:00
IDirect3DVertexBuffer9_Release(VertexBuf);
2018-10-15 00:57:05 +02:00
VertexBuf = NULL;
}
2018-11-12 00:39:47 +01:00
int i;
for (i = 0; i < TEXTURE_COUNT; i++)
2018-10-15 00:57:05 +02:00
{
if (SurfaceTex[i])
{
2018-11-12 00:39:47 +01:00
IDirect3DTexture9_Release(SurfaceTex[i]);
SurfaceTex[i] = NULL;
}
2018-10-15 00:57:05 +02:00
if (PaletteTex[i])
{
2018-11-12 00:39:47 +01:00
IDirect3DTexture9_Release(PaletteTex[i]);
PaletteTex[i] = NULL;
}
2018-10-15 00:57:05 +02:00
}
2018-11-12 00:39:47 +01:00
2018-10-15 00:57:05 +02:00
if (PixelShader)
{
2018-11-12 00:39:47 +01:00
IDirect3DPixelShader9_Release(PixelShader);
2018-10-15 00:57:05 +02:00
PixelShader = NULL;
}
if (D3dDev)
{
2018-11-12 00:39:47 +01:00
IDirect3DDevice9_Release(D3dDev);
2018-10-15 00:57:05 +02:00
D3dDev = NULL;
}
if (D3d)
{
2018-11-12 00:39:47 +01:00
IDirect3D9_Release(D3d);
2018-10-15 00:57:05 +02:00
D3d = NULL;
}
return TRUE;
}
2018-10-02 03:25:34 +02:00
static BOOL CreateResources()
{
2018-10-09 08:56:58 +02:00
BOOL err = FALSE;
2018-10-02 03:25:34 +02:00
int width = ddraw->width;
int height = ddraw->height;
int texWidth =
width <= 1024 ? 1024 : width <= 2048 ? 2048 : width <= 4096 ? 4096 : width;
int texHeight =
height <= texWidth ? texWidth : height <= 2048 ? 2048 : height <= 4096 ? 4096 : height;
texWidth = texWidth > texHeight ? texWidth : texHeight;
ScaleW = (float)width / texWidth;;
ScaleH = (float)height / texHeight;
2018-10-09 08:56:58 +02:00
err = err || FAILED(
2018-11-12 00:39:47 +01:00
IDirect3DDevice9_CreateVertexBuffer(
2018-10-09 08:56:58 +02:00
D3dDev, sizeof(CUSTOMVERTEX) * 4, 0, D3DFVF_XYZRHW | D3DFVF_TEX1, D3DPOOL_MANAGED, &VertexBuf, NULL));
err = err || !UpdateVertices(InterlockedExchangeAdd(&ddraw->incutscene, 0));
int i;
for (i = 0; i < TEXTURE_COUNT; i++)
{
err = err || FAILED(
2018-11-12 00:39:47 +01:00
IDirect3DDevice9_CreateTexture(D3dDev, texWidth, texHeight, 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, &SurfaceTex[i], 0));
2018-10-02 03:25:34 +02:00
err = err || !SurfaceTex[i];
err = err || FAILED(
2018-11-12 00:39:47 +01:00
IDirect3DDevice9_CreateTexture(D3dDev, 256, 256, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &PaletteTex[i], 0));
err = err || !PaletteTex[i];
}
2018-10-02 03:25:34 +02:00
2018-10-09 08:56:58 +02:00
err = err || FAILED(
2018-11-12 00:39:47 +01:00
IDirect3DDevice9_CreatePixelShader(D3dDev, (DWORD *)PalettePixelShaderSrc, &PixelShader));
2018-10-09 08:56:58 +02:00
return VertexBuf && PixelShader && !err;
2018-10-02 03:25:34 +02:00
}
static BOOL SetStates()
2018-10-02 03:25:34 +02:00
{
BOOL err = FALSE;
2018-11-12 00:39:47 +01:00
err = err || FAILED(IDirect3DDevice9_SetFVF(D3dDev, D3DFVF_XYZRHW | D3DFVF_TEX1));
err = err || FAILED(IDirect3DDevice9_SetStreamSource(D3dDev, 0, VertexBuf, 0, sizeof(CUSTOMVERTEX)));
err = err || FAILED(IDirect3DDevice9_SetTexture(D3dDev, 0, (IDirect3DBaseTexture9 *)SurfaceTex[0]));
err = err || FAILED(IDirect3DDevice9_SetTexture(D3dDev, 1, (IDirect3DBaseTexture9 *)PaletteTex[0]));
err = err || FAILED(IDirect3DDevice9_SetPixelShader(D3dDev, PixelShader));
2018-10-02 03:25:34 +02:00
D3DVIEWPORT9 viewData = {
ddraw->render.viewport.x,
ddraw->render.viewport.y,
ddraw->render.viewport.width,
ddraw->render.viewport.height,
0.0f,
1.0f };
2018-11-12 00:39:47 +01:00
err = err || FAILED(IDirect3DDevice9_SetViewport(D3dDev, &viewData));
return !err;
2018-10-02 03:25:34 +02:00
}
2018-10-09 08:56:58 +02:00
static BOOL UpdateVertices(BOOL inCutscene)
2018-10-02 03:25:34 +02:00
{
float vpX = (float)ddraw->render.viewport.x;
float vpY = (float)ddraw->render.viewport.y;
float vpW = (float)(ddraw->render.viewport.width + ddraw->render.viewport.x);
float vpH = (float)(ddraw->render.viewport.height + ddraw->render.viewport.y);
float sH = inCutscene ? ScaleH * ((float)CUTSCENE_HEIGHT / ddraw->height) : ScaleH;
float sW = inCutscene ? ScaleW * ((float)CUTSCENE_WIDTH / ddraw->width) : ScaleW;
CUSTOMVERTEX vertices[] =
{
{ vpX - 0.5f, vpH - 0.5f, 0.0f, 1.0f, 0.0f, sH },
{ vpX - 0.5f, vpY - 0.5f, 0.0f, 1.0f, 0.0f, 0.0f },
{ vpW - 0.5f, vpH - 0.5f, 0.0f, 1.0f, sW, sH },
{ vpW - 0.5f, vpY - 0.5f, 0.0f, 1.0f, sW, 0.0f }
};
void *data;
2018-11-12 00:39:47 +01:00
if (VertexBuf && SUCCEEDED(IDirect3DVertexBuffer9_Lock(VertexBuf, 0, 0, (void**)&data, 0)))
2018-10-02 03:25:34 +02:00
{
memcpy(data, vertices, sizeof(vertices));
2018-10-09 08:56:58 +02:00
2018-11-12 00:39:47 +01:00
IDirect3DVertexBuffer9_Unlock(VertexBuf);
2018-10-09 08:56:58 +02:00
return TRUE;
2018-10-02 03:25:34 +02:00
}
2018-10-09 08:56:58 +02:00
return FALSE;
2018-10-02 03:25:34 +02:00
}
static void SetMaxFPS()
2018-10-02 03:25:34 +02:00
{
MaxFPS = ddraw->render.maxfps;
2018-10-02 03:25:34 +02:00
if (MaxFPS < 0)
MaxFPS = ddraw->mode.dmDisplayFrequency;
if (MaxFPS >= 1000 || ddraw->vsync)
MaxFPS = 0;
if (MaxFPS > 0)
FrameLength = 1000.0f / MaxFPS;
}
2018-10-16 07:07:49 +02:00
DWORD WINAPI render_d3d9_main(void)
2018-10-02 03:25:34 +02:00
{
2018-10-16 07:07:49 +02:00
Sleep(500);
SetMaxFPS();
2018-10-07 16:49:35 +02:00
DWORD tickStart = 0;
DWORD tickEnd = 0;
2018-10-02 03:25:34 +02:00
while (ddraw->render.run && WaitForSingleObject(ddraw->render.sem, 200) != WAIT_FAILED)
2018-09-28 22:40:44 +02:00
{
2018-10-15 00:01:31 +02:00
if (InterlockedExchangeAdd(&ddraw->minimized, 0))
{
2018-10-08 14:11:58 +02:00
Sleep(500);
continue;
}
2018-09-28 22:40:44 +02:00
#if _DEBUG
2018-10-02 11:38:38 +02:00
DrawFrameInfoStart();
2018-09-28 22:40:44 +02:00
#endif
static int texIndex = 0, palIndex = 0;
2018-10-02 03:25:34 +02:00
if (MaxFPS > 0)
2018-10-07 16:49:35 +02:00
tickStart = timeGetTime();
2018-09-28 22:40:44 +02:00
EnterCriticalSection(&ddraw->cs);
if (ddraw->primary && ddraw->primary->palette && ddraw->primary->palette->data_rgb)
{
2018-10-01 13:10:10 +02:00
if (ddraw->vhack)
{
if (detect_cutscene())
{
if (!InterlockedExchange(&ddraw->incutscene, TRUE))
UpdateVertices(TRUE);
}
else
{
if (InterlockedExchange(&ddraw->incutscene, FALSE))
UpdateVertices(FALSE);
}
}
2018-09-28 22:40:44 +02:00
D3DLOCKED_RECT lock_rc;
if (InterlockedExchange(&ddraw->render.surfaceUpdated, FALSE))
{
if (++texIndex >= TEXTURE_COUNT)
texIndex = 0;
2018-09-28 22:40:44 +02:00
RECT rc = { 0,0,ddraw->width,ddraw->height };
2018-11-12 00:39:47 +01:00
if (SUCCEEDED(IDirect3DDevice9_SetTexture(D3dDev, 0, (IDirect3DBaseTexture9 *)SurfaceTex[texIndex])) &&
SUCCEEDED(IDirect3DTexture9_LockRect(SurfaceTex[texIndex], 0, &lock_rc, &rc, 0)))
2018-09-28 22:40:44 +02:00
{
unsigned char *src = (unsigned char *)ddraw->primary->surface;
unsigned char *dst = (unsigned char *)lock_rc.pBits;
int i;
for (i = 0; i < ddraw->height; i++)
{
memcpy(dst, src, ddraw->width);
2018-10-02 03:25:34 +02:00
2018-09-28 22:40:44 +02:00
src += ddraw->width;
dst += lock_rc.Pitch;
}
2018-11-12 00:39:47 +01:00
IDirect3DTexture9_UnlockRect(SurfaceTex[texIndex], 0);
2018-09-28 22:40:44 +02:00
}
}
if (InterlockedExchange(&ddraw->render.paletteUpdated, FALSE))
{
if (++palIndex >= TEXTURE_COUNT)
palIndex = 0;
2018-09-28 22:40:44 +02:00
RECT rc = { 0,0,256,1 };
2018-11-12 00:39:47 +01:00
if (SUCCEEDED(IDirect3DDevice9_SetTexture(D3dDev, 1, (IDirect3DBaseTexture9 *)PaletteTex[palIndex])) &&
SUCCEEDED(IDirect3DTexture9_LockRect(PaletteTex[palIndex], 0, &lock_rc, &rc, 0)))
2018-09-28 22:40:44 +02:00
{
memcpy(lock_rc.pBits, ddraw->primary->palette->data_rgb, 256 * sizeof(int));
2018-11-12 00:39:47 +01:00
IDirect3DTexture9_UnlockRect(PaletteTex[palIndex], 0);
2018-09-28 22:40:44 +02:00
}
}
}
LeaveCriticalSection(&ddraw->cs);
2018-11-12 00:39:47 +01:00
IDirect3DDevice9_BeginScene(D3dDev);
IDirect3DDevice9_DrawPrimitive(D3dDev, D3DPT_TRIANGLESTRIP, 0, 2);
IDirect3DDevice9_EndScene(D3dDev);
2018-09-28 22:40:44 +02:00
2018-11-12 00:39:47 +01:00
if (IDirect3DDevice9_Present(D3dDev, NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST)
{
2018-10-15 00:01:31 +02:00
DWORD_PTR dwResult;
SendMessageTimeout(ddraw->hWnd, WM_D3D9DEVICELOST, 0, 0, 0, 1000, &dwResult);
2018-09-28 22:40:44 +02:00
}
#if _DEBUG
2018-10-02 11:38:38 +02:00
DrawFrameInfoEnd();
2018-09-28 22:40:44 +02:00
#endif
2018-10-02 03:25:34 +02:00
if (MaxFPS > 0)
2018-09-28 22:40:44 +02:00
{
2018-10-07 16:49:35 +02:00
tickEnd = timeGetTime();
2018-09-28 22:40:44 +02:00
2018-10-07 16:49:35 +02:00
if (tickEnd - tickStart < FrameLength)
Sleep(FrameLength - (tickEnd - tickStart));
2018-09-28 22:40:44 +02:00
}
}
2018-10-16 07:07:49 +02:00
return 0;
2018-10-02 03:25:34 +02:00
}