raze/source/common/platform/win32/win32polyvideo.cpp
Christoph Oelckers 84173ee09b - backend update from GZDoom.
The main bulk of this is the new start screen code. To make this work in Raze some more work on the startup procedure is needed.
What this does provide is support for the DOS end-of-game text screens in Duke and SW on non-Windows systems.
2022-06-06 11:45:34 +02:00

198 lines
No EOL
4.5 KiB
C++

#include <assert.h>
#include "hardware.h"
#include "engineerrors.h"
#include <Windows.h>
#include "i_mainwindow.h"
#ifdef HAVE_SOFTPOLY
EXTERN_CVAR(Bool, vid_vsync)
bool ViewportLinearScale();
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#ifndef D3DPRESENT_FORCEIMMEDIATE
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L // MinGW
#endif
namespace
{
int SrcWidth = 0;
int SrcHeight = 0;
int ClientWidth = 0;
int ClientHeight = 0;
bool CurrentVSync = false;
IDirect3D9Ex *d3d9 = nullptr;
IDirect3DDevice9Ex *device = nullptr;
IDirect3DSurface9* surface = nullptr;
}
void I_PolyPresentInit()
{
Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9);
if (!d3d9)
{
I_FatalError("Direct3DCreate9 failed");
}
RECT rect = {};
GetClientRect(mainwindow.GetHandle(), &rect);
ClientWidth = rect.right;
ClientHeight = rect.bottom;
D3DPRESENT_PARAMETERS pp = {};
pp.Windowed = true;
pp.SwapEffect = D3DSWAPEFFECT_FLIPEX;
pp.BackBufferWidth = ClientWidth;
pp.BackBufferHeight = ClientHeight;
pp.BackBufferCount = 1;
pp.hDeviceWindow = mainwindow.GetHandle();
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mainwindow.GetHandle(), D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, nullptr, &device);
if (FAILED(result))
{
I_FatalError("IDirect3D9.CreateDevice failed");
}
}
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch)
{
HRESULT result;
RECT rect = {};
GetClientRect(mainwindow.GetHandle(), &rect);
if (rect.right != ClientWidth || rect.bottom != ClientHeight || CurrentVSync != vsync)
{
if (surface)
{
surface->Release();
surface = nullptr;
}
CurrentVSync = vsync;
ClientWidth = rect.right;
ClientHeight = rect.bottom;
D3DPRESENT_PARAMETERS pp = {};
pp.Windowed = true;
pp.SwapEffect = D3DSWAPEFFECT_FLIPEX;
pp.BackBufferWidth = ClientWidth;
pp.BackBufferHeight = ClientHeight;
pp.BackBufferCount = 1;
pp.hDeviceWindow = mainwindow.GetHandle();
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
device->Reset(&pp);
}
if (SrcWidth != w || SrcHeight != h || !surface)
{
if (surface)
{
surface->Release();
surface = nullptr;
}
SrcWidth = w;
SrcHeight = h;
result = device->CreateOffscreenPlainSurface(SrcWidth, SrcHeight, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, 0);
if (FAILED(result))
{
I_FatalError("IDirect3DDevice9.CreateOffscreenPlainSurface failed");
}
}
D3DLOCKED_RECT lockrect = {};
result = surface->LockRect(&lockrect, nullptr, D3DLOCK_DISCARD);
if (FAILED(result))
{
pitch = 0;
return nullptr;
}
pitch = lockrect.Pitch;
return (uint8_t*)lockrect.pBits;
}
void I_PolyPresentUnlock(int x, int y, int width, int height)
{
surface->UnlockRect();
IDirect3DSurface9 *backbuffer = nullptr;
HRESULT result = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
if (FAILED(result))
return;
result = device->BeginScene();
if (SUCCEEDED(result))
{
int count = 0;
D3DRECT clearrects[4];
if (y > 0)
{
clearrects[count].x1 = 0;
clearrects[count].y1 = 0;
clearrects[count].x2 = ClientWidth;
clearrects[count].y2 = y;
count++;
}
if (y + height < ClientHeight)
{
clearrects[count].x1 = 0;
clearrects[count].y1 = y + height;
clearrects[count].x2 = ClientWidth;
clearrects[count].y2 = ClientHeight;
count++;
}
if (x > 0)
{
clearrects[count].x1 = 0;
clearrects[count].y1 = y;
clearrects[count].x2 = x;
clearrects[count].y2 = y + height;
count++;
}
if (x + width < ClientWidth)
{
clearrects[count].x1 = x + width;
clearrects[count].y1 = y;
clearrects[count].x2 = ClientWidth;
clearrects[count].y2 = y + height;
count++;
}
if (count > 0)
device->Clear(count, clearrects, D3DCLEAR_TARGET, 0, 0.0f, 0);
RECT srcrect = {}, dstrect = {};
srcrect.right = SrcWidth;
srcrect.bottom = SrcHeight;
dstrect.left = x;
dstrect.top = y;
dstrect.right = x + width;
dstrect.bottom = y + height;
if (ViewportLinearScale())
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_LINEAR);
else
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_POINT);
result = device->EndScene();
if (SUCCEEDED(result))
device->PresentEx(nullptr, nullptr, 0, nullptr, CurrentVSync ? 0 : D3DPRESENT_FORCEIMMEDIATE);
}
backbuffer->Release();
}
void I_PolyPresentDeinit()
{
if (surface) surface->Release();
if (device) device->Release();
if (d3d9) d3d9->Release();
}
#endif