Path: blob/master/RSDKv5/RSDK/Graphics/DX9/DX9RenderDevice.cpp
1163 views
#include "resource.h"1#if !RETRO_USE_ORIGINAL_CODE2#include <D3Dcompiler.h>3#endif45#include "Ks.h" // used for KSCATEGORY_AUDIO6#include "Ksmedia.h" // used for KSCATEGORY_AUDIO78// for some reason this seems to be applying "thick frame" instead of thin frame (intended)9// it is for this reason that I'm unable to get the cool mini window toolbar that og mania has :(10// tldr: microsoft sucks again11#define DX9_WINDOWFLAGS_BORDERED (WS_POPUP | (WS_BORDER | WS_DLGFRAME) | (WS_SYSMENU | WS_GROUP))1213#define DX9_WINDOWFLAGS_BORDERLESS (WS_POPUP)1415HWND RenderDevice::windowHandle;1617HDEVNOTIFY RenderDevice::deviceNotif = 0;18PAINTSTRUCT RenderDevice::Paint;1920IDirect3D9 *RenderDevice::dx9Context;21IDirect3DDevice9 *RenderDevice::dx9Device;22UINT RenderDevice::dxAdapter;23IDirect3DVertexDeclaration9 *RenderDevice::dx9VertexDeclare;24IDirect3DVertexBuffer9 *RenderDevice::dx9VertexBuffer;25IDirect3DTexture9 *RenderDevice::screenTextures[SCREEN_COUNT];26IDirect3DTexture9 *RenderDevice::imageTexture;27D3DVIEWPORT9 RenderDevice::dx9ViewPort;2829int32 RenderDevice::adapterCount = 0;30RECT RenderDevice::monitorDisplayRect;31GUID RenderDevice::deviceIdentifier;3233bool RenderDevice::useFrequency = false;3435LARGE_INTEGER RenderDevice::performanceCount;36LARGE_INTEGER RenderDevice::frequency;37LARGE_INTEGER RenderDevice::initialFrequency;38LARGE_INTEGER RenderDevice::curFrequency;3940// WinMain args41HINSTANCE RenderDevice::hInstance;42HINSTANCE RenderDevice::hPrevInstance;43INT RenderDevice::nShowCmd;4445bool RenderDevice::Init()46{47#if _UNICODE48// shoddy workaround to get the title into wide chars in UNICODE mode49std::string str = gameVerInfo.gameTitle;50std::wstring temp = std::wstring(str.begin(), str.end());51LPCWSTR gameTitle = temp.c_str();52#else53std::string str = gameVerInfo.gameTitle;54LPCSTR gameTitle = str.c_str();55#endif5657HMODULE handle = GetModuleHandle(NULL);5859WNDCLASS wndClass = {};60wndClass.style = CS_VREDRAW | CS_HREDRAW;61wndClass.lpfnWndProc = WindowEventCallback;62wndClass.cbClsExtra = 0;63wndClass.cbWndExtra = sizeof(LONG);64wndClass.hInstance = hInstance;65wndClass.hIcon = LoadIcon(handle, IDI_APPLICATION);66wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);67wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);68wndClass.lpszMenuName = NULL;69wndClass.lpszClassName = gameTitle;70if (!RegisterClass(&wndClass))71return false;7273ShowCursor(false);7475tagRECT winRect;76if (videoSettings.windowed) {77winRect.left = (GetSystemMetrics(SM_CXSCREEN) - videoSettings.windowWidth) / 2;78winRect.top = (GetSystemMetrics(SM_CYSCREEN) - videoSettings.windowHeight) / 2;79winRect.right = winRect.left + videoSettings.windowWidth;80winRect.bottom = winRect.top + videoSettings.windowHeight;81}82else if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {83winRect.left = 0;84winRect.top = 0;85winRect.right = GetSystemMetrics(SM_CXSCREEN);86winRect.bottom = GetSystemMetrics(SM_CYSCREEN);87}88else {89winRect.left = (GetSystemMetrics(SM_CXSCREEN) - videoSettings.fsWidth) / 2;90winRect.top = (GetSystemMetrics(SM_CYSCREEN) - videoSettings.fsHeight) / 2;91winRect.right = winRect.left + videoSettings.fsWidth;92winRect.bottom = winRect.top + videoSettings.fsHeight;93}9495uint32 windowFlags = 0;96if (videoSettings.bordered && videoSettings.windowed)97windowFlags = DX9_WINDOWFLAGS_BORDERED;98else99windowFlags = DX9_WINDOWFLAGS_BORDERLESS;100101AdjustWindowRect(&winRect, windowFlags, false);102windowHandle = CreateWindowEx(WS_EX_LEFT, gameTitle, gameTitle, windowFlags, winRect.left, winRect.top, winRect.right - winRect.left,103winRect.bottom - winRect.top, NULL, NULL, hInstance, NULL);104105PrintLog(PRINT_NORMAL, "w: %d h: %d windowed: %d", winRect.right - winRect.left, winRect.bottom - winRect.top, videoSettings.windowed);106107if (!windowHandle)108return false;109110ShowWindow(windowHandle, nShowCmd);111UpdateWindow(windowHandle);112113if (!SetupRendering() || !AudioDevice::Init())114return false;115116InitInputDevices();117return true;118}119120void RenderDevice::CopyFrameBuffer()121{122dx9Device->SetTexture(0, NULL);123124for (int32 s = 0; s < videoSettings.screenCount; ++s) {125D3DLOCKED_RECT rect;126127if (SUCCEEDED(screenTextures[s]->LockRect(0, &rect, NULL, D3DLOCK_DISCARD))) {128WORD *pixels = (WORD *)rect.pBits;129uint16 *frameBuffer = screens[s].frameBuffer;130131int32 screenPitch = screens[s].pitch;132int32 pitch = (rect.Pitch >> 1) - screenPitch;133134for (int32 y = 0; y < SCREEN_YSIZE; ++y) {135int32 pixelCount = screenPitch >> 4;136for (int32 x = 0; x < pixelCount; ++x) {137pixels[0] = frameBuffer[0];138pixels[1] = frameBuffer[1];139pixels[2] = frameBuffer[2];140pixels[3] = frameBuffer[3];141pixels[4] = frameBuffer[4];142pixels[5] = frameBuffer[5];143pixels[6] = frameBuffer[6];144pixels[7] = frameBuffer[7];145pixels[8] = frameBuffer[8];146pixels[9] = frameBuffer[9];147pixels[10] = frameBuffer[10];148pixels[11] = frameBuffer[11];149pixels[12] = frameBuffer[12];150pixels[13] = frameBuffer[13];151pixels[14] = frameBuffer[14];152pixels[15] = frameBuffer[15];153154frameBuffer += 16;155pixels += 16;156}157158pixels += pitch;159}160161screenTextures[s]->UnlockRect(0);162}163}164}165166void RenderDevice::FlipScreen()167{168if (windowRefreshDelay > 0) {169if (!--windowRefreshDelay)170UpdateGameWindow();171172return;173}174175dx9Device->SetViewport(&displayInfo.viewport);176dx9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);177dx9Device->SetViewport(&dx9ViewPort);178179if (SUCCEEDED(dx9Device->BeginScene())) {180// reload shader if needed181if (lastShaderID != videoSettings.shaderID) {182lastShaderID = videoSettings.shaderID;183184if (shaderList[videoSettings.shaderID].linear) {185dx9Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);186dx9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);187}188else {189dx9Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);190dx9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);191}192193if (videoSettings.shaderSupport) {194dx9Device->SetVertexShader(shaderList[videoSettings.shaderID].vertexShaderObject);195dx9Device->SetPixelShader(shaderList[videoSettings.shaderID].pixelShaderObject);196dx9Device->SetVertexDeclaration(dx9VertexDeclare);197dx9Device->SetStreamSource(0, dx9VertexBuffer, 0, sizeof(RenderVertex));198}199else {200dx9Device->SetStreamSource(0, dx9VertexBuffer, 0, sizeof(RenderVertex));201dx9Device->SetFVF(D3DFVF_TEX1 | D3DFVF_DIFFUSE | D3DFVF_XYZ);202}203}204205if (videoSettings.shaderSupport) {206float2 screenDim = { videoSettings.dimMax * videoSettings.dimPercent, 0 };207208dx9Device->SetPixelShaderConstantF(0, &pixelSize.x, 1); // pixelSize209dx9Device->SetPixelShaderConstantF(1, &textureSize.x, 1); // textureSize210dx9Device->SetPixelShaderConstantF(2, &viewSize.x, 1); // viewSize211dx9Device->SetPixelShaderConstantF(3, &screenDim.x, 1); // screenDim212}213214int32 startVert = 0;215switch (videoSettings.screenCount) {216default:217case 0:218#if RETRO_REV02219startVert = 54;220#else221startVert = 18;222#endif223dx9Device->SetTexture(0, imageTexture);224dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, startVert, 2);225dx9Device->EndScene();226break;227228case 1:229dx9Device->SetTexture(0, screenTextures[0]);230dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);231break;232233case 2:234#if RETRO_REV02235startVert = startVertex_2P[0];236#else237startVert = 6;238#endif239dx9Device->SetTexture(0, screenTextures[0]);240dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, startVert, 2);241242#if RETRO_REV02243startVert = startVertex_2P[1];244#else245startVert = 12;246#endif247dx9Device->SetTexture(0, screenTextures[1]);248dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, startVert, 2);249break;250251#if RETRO_REV02252case 3:253dx9Device->SetTexture(0, screenTextures[0]);254dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, startVertex_3P[0], 2);255256dx9Device->SetTexture(0, screenTextures[1]);257dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, startVertex_3P[1], 2);258259dx9Device->SetTexture(0, screenTextures[2]);260dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, startVertex_3P[2], 2);261break;262263case 4:264dx9Device->SetTexture(0, screenTextures[0]);265dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, 30, 2);266267dx9Device->SetTexture(0, screenTextures[1]);268dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, 36, 2);269270dx9Device->SetTexture(0, screenTextures[2]);271dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, 42, 2);272273dx9Device->SetTexture(0, screenTextures[3]);274dx9Device->DrawPrimitive(D3DPT_TRIANGLELIST, 48, 2);275break;276#endif277}278279dx9Device->EndScene();280}281282if (FAILED(dx9Device->Present(NULL, NULL, NULL, NULL)))283windowRefreshDelay = 8;284}285286void RenderDevice::Release(bool32 isRefresh)287{288if (videoSettings.shaderSupport) {289for (int32 i = 0; i < shaderCount; ++i) {290if (shaderList[i].vertexShaderObject)291shaderList[i].vertexShaderObject->Release();292shaderList[i].vertexShaderObject = NULL;293294if (shaderList[i].pixelShaderObject)295shaderList[i].pixelShaderObject->Release();296shaderList[i].pixelShaderObject = NULL;297}298299shaderCount = 0;300#if RETRO_USE_MOD_LOADER301userShaderCount = 0;302#endif303}304305if (imageTexture) {306imageTexture->Release();307imageTexture = NULL;308}309310for (int32 i = 0; i < SCREEN_COUNT; ++i) {311if (screenTextures[i])312screenTextures[i]->Release();313314screenTextures[i] = NULL;315}316317if (!isRefresh && displayInfo.displays) {318free(displayInfo.displays);319displayInfo.displays = NULL;320}321322if (dx9VertexBuffer) {323dx9VertexBuffer->Release();324dx9VertexBuffer = NULL;325}326327if (isRefresh && dx9VertexDeclare) {328dx9VertexDeclare->Release();329dx9VertexDeclare = NULL;330}331332if (dx9Device) {333dx9Device->Release();334dx9Device = NULL;335}336337if (!isRefresh && dx9Context) {338dx9Context->Release();339dx9Context = NULL;340}341342if (!isRefresh && scanlines) {343free(scanlines);344scanlines = NULL;345}346}347348void RenderDevice::RefreshWindow()349{350videoSettings.windowState = WINDOWSTATE_UNINITIALIZED;351352Release(true);353354ShowWindow(windowHandle, SW_HIDE);355356if (videoSettings.windowed && videoSettings.bordered)357SetWindowLong(windowHandle, GWL_STYLE, DX9_WINDOWFLAGS_BORDERED);358else359SetWindowLong(windowHandle, GWL_STYLE, DX9_WINDOWFLAGS_BORDERLESS);360361Sleep(250); // zzzz.. mimimimi..362363GetDisplays();364365tagRECT rect;366if (videoSettings.windowed || !videoSettings.exclusiveFS) {367tagRECT winRect;368GetClientRect(windowHandle, &winRect);369370tagPOINT topLeft, bottomRight;371topLeft.x = winRect.left;372topLeft.y = winRect.top;373bottomRight.x = winRect.right;374bottomRight.y = winRect.bottom;375376ClientToScreen(windowHandle, &topLeft);377ClientToScreen(windowHandle, &bottomRight);378379if (videoSettings.windowed) {380D3DDISPLAYMODE displayMode;381dx9Context->GetAdapterDisplayMode(dxAdapter, &displayMode);382383if (videoSettings.windowWidth >= displayMode.Width || videoSettings.windowHeight >= displayMode.Height) {384videoSettings.windowWidth = (displayMode.Height / 480 * videoSettings.pixWidth);385videoSettings.windowHeight = displayMode.Height / 480 * videoSettings.pixHeight;386}387388rect.left = (topLeft.x + bottomRight.x) / 2 - videoSettings.windowWidth / 2;389rect.top = (topLeft.y + bottomRight.y) / 2 - videoSettings.windowHeight / 2;390rect.right = (topLeft.x + bottomRight.x) / 2 + videoSettings.windowWidth / 2;391rect.bottom = (topLeft.y + bottomRight.y) / 2 + videoSettings.windowHeight / 2;392393if (videoSettings.bordered)394AdjustWindowRect(&rect, DX9_WINDOWFLAGS_BORDERED, false);395else396AdjustWindowRect(&rect, DX9_WINDOWFLAGS_BORDERLESS, false);397398if (rect.left < monitorDisplayRect.left || rect.right > monitorDisplayRect.right || rect.top < monitorDisplayRect.top399|| rect.bottom > monitorDisplayRect.bottom) {400rect.left = (monitorDisplayRect.right + monitorDisplayRect.left) / 2 - videoSettings.windowWidth / 2;401rect.top = (monitorDisplayRect.top + monitorDisplayRect.bottom) / 2 - videoSettings.windowHeight / 2;402rect.right = (monitorDisplayRect.right + monitorDisplayRect.left) / 2 + videoSettings.windowWidth / 2;403rect.bottom = (monitorDisplayRect.top + monitorDisplayRect.bottom) / 2 + videoSettings.windowHeight / 2;404405if (videoSettings.bordered)406AdjustWindowRect(&rect, DX9_WINDOWFLAGS_BORDERED, false);407else408AdjustWindowRect(&rect, DX9_WINDOWFLAGS_BORDERLESS, false);409}410}411else {412rect = monitorDisplayRect;413AdjustWindowRect(&monitorDisplayRect, DX9_WINDOWFLAGS_BORDERLESS, 0);414}415416SetWindowPos(windowHandle, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW);417}418419ShowWindow(windowHandle, SW_SHOW);420RedrawWindow(windowHandle, NULL, NULL, RDW_UPDATENOW | RDW_INVALIDATE);421422if (!InitGraphicsAPI() || !InitShaders())423return;424425videoSettings.windowState = WINDOWSTATE_ACTIVE;426}427428void RenderDevice::InitFPSCap()429{430if (QueryPerformanceFrequency(&frequency)) {431useFrequency = true;432initialFrequency.QuadPart = frequency.QuadPart / videoSettings.refreshRate;433QueryPerformanceCounter(&performanceCount);434}435else {436useFrequency = false;437performanceCount.QuadPart = timeGetTime();438}439}440bool RenderDevice::CheckFPSCap()441{442if (useFrequency)443QueryPerformanceCounter(&curFrequency);444else445curFrequency.QuadPart = timeGetTime();446447if (curFrequency.QuadPart > performanceCount.QuadPart)448return true;449450return false;451}452void RenderDevice::UpdateFPSCap() { performanceCount.QuadPart = curFrequency.QuadPart + initialFrequency.LowPart; }453454void RenderDevice::InitVertexBuffer()455{456RenderVertex vertBuffer[sizeof(rsdkVertexBuffer) / sizeof(RenderVertex)];457memcpy(vertBuffer, rsdkVertexBuffer, sizeof(rsdkVertexBuffer));458459float x = 0.5 / (float)viewSize.x;460float y = 0.5 / (float)viewSize.y;461462// ignore the last 6 verts, they're scaled to the 1024x512 textures already!463int32 vertCount = (RETRO_REV02 ? 60 : 24) - 6;464for (int32 v = 0; v < vertCount; ++v) {465RenderVertex *vertex = &vertBuffer[v];466vertex->pos.x = vertex->pos.x - x;467vertex->pos.y = vertex->pos.y + y;468469if (vertex->tex.x)470vertex->tex.x = screens[0].size.x * (1.0 / textureSize.x);471472if (vertex->tex.y)473vertex->tex.y = screens[0].size.y * (1.0 / textureSize.y);474}475476RenderVertex *vertBufferPtr;477if (SUCCEEDED(dx9VertexBuffer->Lock(0, 0, (void **)&vertBufferPtr, 0))) {478memcpy(vertBufferPtr, vertBuffer, sizeof(vertBuffer));479dx9VertexBuffer->Unlock();480}481}482483bool RenderDevice::InitGraphicsAPI()484{485videoSettings.shaderSupport = false;486487D3DCAPS9 pCaps;488if (SUCCEEDED(dx9Context->GetDeviceCaps(0, D3DDEVTYPE_HAL, &pCaps)) && (pCaps.PixelShaderVersion & 0xFF00) >= 0x300)489videoSettings.shaderSupport = true;490491viewSize.x = 0;492viewSize.y = 0;493494D3DPRESENT_PARAMETERS presentParams;495ZeroMemory(&presentParams, sizeof(presentParams));496if (videoSettings.windowed || !videoSettings.exclusiveFS) {497presentParams.BackBufferWidth = 0;498presentParams.BackBufferHeight = 0;499presentParams.BackBufferFormat = D3DFMT_UNKNOWN;500presentParams.BackBufferCount = 1;501502presentParams.MultiSampleType = D3DMULTISAMPLE_NONE;503presentParams.MultiSampleQuality = 0;504505presentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;506presentParams.hDeviceWindow = windowHandle;507presentParams.Windowed = true;508presentParams.EnableAutoDepthStencil = false;509presentParams.AutoDepthStencilFormat = D3DFMT_UNKNOWN;510presentParams.Flags = 0;511512presentParams.FullScreen_RefreshRateInHz = 0;513presentParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;514515if (videoSettings.windowed) {516viewSize.x = (float)videoSettings.windowWidth;517viewSize.y = (float)videoSettings.windowHeight;518}519else {520viewSize.x = (float)displayWidth[dxAdapter];521viewSize.y = (float)displayHeight[dxAdapter];522}523}524else {525int32 bufferWidth = videoSettings.fsWidth;526int32 bufferHeight = videoSettings.fsHeight;527if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {528bufferWidth = displayWidth[dxAdapter];529bufferHeight = displayHeight[dxAdapter];530}531532presentParams.BackBufferWidth = bufferWidth;533presentParams.BackBufferHeight = bufferHeight;534// for some reason this seems to force the window to have permanent top focus after coming out of fullscreen535// despite this being 1:1 with the original code and it not having that behaviour536// tldr: microsoft sucks537presentParams.BackBufferFormat = D3DFMT_X8R8G8B8;538presentParams.BackBufferCount = videoSettings.tripleBuffered ? 2 : 1;539540presentParams.MultiSampleType = D3DMULTISAMPLE_NONE;541presentParams.MultiSampleQuality = 0;542543presentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;544presentParams.hDeviceWindow = windowHandle;545presentParams.Windowed = false;546presentParams.EnableAutoDepthStencil = false;547presentParams.AutoDepthStencilFormat = D3DFMT_UNKNOWN;548presentParams.Flags = 0;549550presentParams.FullScreen_RefreshRateInHz = videoSettings.refreshRate;551presentParams.PresentationInterval = videoSettings.vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;552553viewSize.x = (float)bufferWidth;554viewSize.y = (float)bufferHeight;555}556557if (FAILED(dx9Context->CreateDevice(dxAdapter, D3DDEVTYPE_HAL, windowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &dx9Device)))558return false;559560if (videoSettings.shaderSupport) {561D3DVERTEXELEMENT9 elements[4];562563elements[0].Type = D3DDECLTYPE_FLOAT3;564elements[0].Method = 0;565elements[0].Stream = 0;566elements[0].Offset = 0;567elements[0].Usage = D3DDECLUSAGE_POSITION;568elements[0].UsageIndex = 0;569570elements[1].Type = D3DDECLTYPE_D3DCOLOR;571elements[1].Method = 0;572elements[1].Stream = 0;573elements[1].Offset = offsetof(RenderVertex, color);574elements[1].Usage = D3DDECLUSAGE_COLOR;575elements[1].UsageIndex = 0;576577elements[2].Type = D3DDECLTYPE_FLOAT2;578elements[2].Method = 0;579elements[2].Stream = 0;580elements[2].Offset = offsetof(RenderVertex, tex);581elements[2].Usage = D3DDECLUSAGE_TEXCOORD;582elements[2].UsageIndex = 0;583584elements[3].Type = D3DDECLTYPE_UNUSED;585elements[3].Method = 0;586elements[3].Stream = 0xFF;587elements[3].Offset = 0;588elements[3].Usage = 0;589elements[3].UsageIndex = 0;590591if (FAILED(dx9Device->CreateVertexDeclaration(elements, &dx9VertexDeclare)))592return false;593594if (FAILED(dx9Device->CreateVertexBuffer(sizeof(rsdkVertexBuffer), 0, 0, D3DPOOL_DEFAULT, &dx9VertexBuffer, NULL)))595return false;596}597else {598if (FAILED(dx9Device->CreateVertexBuffer(sizeof(rsdkVertexBuffer), 0, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1, D3DPOOL_DEFAULT,599&dx9VertexBuffer, NULL)))600return false;601}602603int32 maxPixHeight = 0;604#if !RETRO_USE_ORIGINAL_CODE605int32 screenWidth = 0;606#endif607for (int32 s = 0; s < SCREEN_COUNT; ++s) {608if (videoSettings.pixHeight > maxPixHeight)609maxPixHeight = videoSettings.pixHeight;610611screens[s].size.y = videoSettings.pixHeight;612613float viewAspect = viewSize.x / viewSize.y;614#if !RETRO_USE_ORIGINAL_CODE615screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;616#else617int32 screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;618#endif619if (screenWidth < videoSettings.pixWidth)620screenWidth = videoSettings.pixWidth;621622#if !RETRO_USE_ORIGINAL_CODE623if (customSettings.maxPixWidth && screenWidth > customSettings.maxPixWidth)624screenWidth = customSettings.maxPixWidth;625#else626if (screenWidth > DEFAULT_PIXWIDTH)627screenWidth = DEFAULT_PIXWIDTH;628#endif629630memset(&screens[s].frameBuffer, 0, sizeof(screens[s].frameBuffer));631SetScreenSize(s, screenWidth, screens[s].size.y);632}633634pixelSize.x = (float)screens[0].size.x;635pixelSize.y = (float)screens[0].size.y;636float pixAspect = pixelSize.x / pixelSize.y;637638dx9Device->GetViewport(&displayInfo.viewport);639dx9ViewPort = displayInfo.viewport;640641if ((viewSize.x / viewSize.y) <= ((pixelSize.x / pixelSize.y) + 0.1)) {642if ((pixAspect - 0.1) > (viewSize.x / viewSize.y)) {643viewSize.y = (pixelSize.y / pixelSize.x) * viewSize.x;644dx9ViewPort.Y = (DWORD)((displayInfo.viewport.Height >> 1) - (viewSize.y * 0.5));645dx9ViewPort.Height = (DWORD)viewSize.y;646647dx9Device->SetViewport(&dx9ViewPort);648}649}650else {651viewSize.x = pixAspect * viewSize.y;652dx9ViewPort.X = (DWORD)((displayInfo.viewport.Width >> 1) - (viewSize.x * 0.5));653dx9ViewPort.Width = (DWORD)viewSize.x;654655dx9Device->SetViewport(&dx9ViewPort);656}657658#if !RETRO_USE_ORIGINAL_CODE659if (screenWidth <= 512 && maxPixHeight <= 256) {660#else661if (maxPixHeight <= 256) {662#endif663textureSize.x = 512.0;664textureSize.y = 256.0;665}666else {667textureSize.x = 1024.0;668textureSize.y = 512.0;669}670671for (int32 s = 0; s < SCREEN_COUNT; ++s) {672if (FAILED(dx9Device->CreateTexture((UINT)textureSize.x, (UINT)textureSize.y, 1, D3DUSAGE_DYNAMIC, D3DFMT_R5G6B5, D3DPOOL_DEFAULT,673&screenTextures[s], NULL)))674return false;675}676677if (FAILED(dx9Device->CreateTexture(RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,678&imageTexture, NULL)))679return false;680681lastShaderID = -1;682InitVertexBuffer();683engine.inFocus = 1;684videoSettings.viewportX = (float)dx9ViewPort.X;685videoSettings.viewportY = (float)dx9ViewPort.Y;686videoSettings.viewportW = 1.0 / viewSize.x;687videoSettings.viewportH = 1.0 / viewSize.y;688689return true;690}691692void RenderDevice::LoadShader(const char *fileName, bool32 linear)693{694char fullFilePath[0x100];695FileInfo info;696697for (int32 i = 0; i < shaderCount; ++i) {698if (strcmp(shaderList[i].name, fileName) == 0)699return;700}701702if (shaderCount == SHADER_COUNT)703return;704705ShaderEntry *shader = &shaderList[shaderCount];706shader->linear = linear;707sprintf_s(shader->name, sizeof(shader->name), "%s", fileName);708709const D3D_SHADER_MACRO defines[] = {710#if RETRO_REV02711{ "RETRO_REV02" },712{ "1" },713#endif714{ NULL },715{ NULL }716};717718#if !RETRO_USE_ORIGINAL_CODE719// Try to compile the vertex shader source if it exists720sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/DX9/%s.hlsl", fileName);721InitFileInfo(&info);722if (LoadFile(&info, fullFilePath, FMODE_RB)) {723uint8 *fileData = NULL;724AllocateStorage((void **)&fileData, info.fileSize, DATASET_TMP, false);725ReadBytes(&info, fileData, info.fileSize);726CloseFile(&info);727728UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;729if (engine.devMenu) {730flags |= D3DCOMPILE_DEBUG;731flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0;732flags |= D3DCOMPILE_WARNINGS_ARE_ERRORS;733}734else {735flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;736}737738ID3DBlob *shaderBlob = nullptr;739ID3DBlob *errorBlob = nullptr;740HRESULT result = D3DCompile(fileData, info.fileSize, fullFilePath, defines, NULL, "VSMain", "vs_3_0", flags, 0, &shaderBlob, &errorBlob);741742RemoveStorageEntry((void **)&fileData);743744if (FAILED(result)) {745if (errorBlob) {746PrintLog(PRINT_NORMAL, "ERROR COMPILING VERTEX SHADER: %s", (char *)errorBlob->GetBufferPointer());747errorBlob->Release();748}749750if (shaderBlob)751shaderBlob->Release();752753return;754}755else {756PrintLog(PRINT_NORMAL, "Successfully compiled vertex shader!");757if (errorBlob)758PrintLog(PRINT_NORMAL, "Vertex shader warnings:\n%s", (char *)errorBlob->GetBufferPointer());759760if (FAILED(dx9Device->CreateVertexShader((DWORD *)shaderBlob->GetBufferPointer(), &shader->vertexShaderObject))) {761if (shader->vertexShaderObject) {762shader->vertexShaderObject->Release();763shader->vertexShaderObject = NULL;764}765766return;767}768}769}770else {771#endif772// if the vertex shader source doesn't exist, fall back and try to load the vertex shader bytecode773sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/CSO-DX9/%s.vso", fileName);774InitFileInfo(&info);775if (LoadFile(&info, fullFilePath, FMODE_RB)) {776uint8 *fileData = NULL;777AllocateStorage((void **)&fileData, info.fileSize, DATASET_TMP, false);778ReadBytes(&info, fileData, info.fileSize);779CloseFile(&info);780781if (FAILED(dx9Device->CreateVertexShader((DWORD *)fileData, &shader->vertexShaderObject))) {782if (shader->vertexShaderObject) {783shader->vertexShaderObject->Release();784shader->vertexShaderObject = NULL;785}786787RemoveStorageEntry((void **)&fileData);788return;789}790791RemoveStorageEntry((void **)&fileData);792}793794#if !RETRO_USE_ORIGINAL_CODE795}796#endif797798#if !RETRO_USE_ORIGINAL_CODE799// Try to compile the pixel shader source if it exists800sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/DX9/%s.hlsl", fileName);801InitFileInfo(&info);802if (LoadFile(&info, fullFilePath, FMODE_RB)) {803uint8 *fileData = NULL;804AllocateStorage((void **)&fileData, info.fileSize, DATASET_TMP, false);805ReadBytes(&info, fileData, info.fileSize);806CloseFile(&info);807808UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;809if (engine.devMenu) {810flags |= D3DCOMPILE_DEBUG;811flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0;812flags |= D3DCOMPILE_WARNINGS_ARE_ERRORS;813}814else {815flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;816}817818ID3DBlob *shaderBlob = nullptr;819ID3DBlob *errorBlob = nullptr;820HRESULT result = D3DCompile(fileData, info.fileSize, fullFilePath, defines, NULL, "PSMain", "ps_3_0", flags, 0, &shaderBlob, &errorBlob);821822RemoveStorageEntry((void **)&fileData);823824if (FAILED(result)) {825if (errorBlob) {826PrintLog(PRINT_NORMAL, "ERROR COMPILING PIXEL SHADER:\n%s", (char *)errorBlob->GetBufferPointer());827errorBlob->Release();828}829830if (shaderBlob)831shaderBlob->Release();832}833else {834PrintLog(PRINT_NORMAL, "Successfully compiled pixel shader!");835if (errorBlob)836PrintLog(PRINT_NORMAL, "Pixel shader warnings:\n%s", (char *)errorBlob->GetBufferPointer());837838if (FAILED(dx9Device->CreatePixelShader((DWORD *)shaderBlob->GetBufferPointer(), &shader->pixelShaderObject))) {839if (shader->vertexShaderObject) {840shader->vertexShaderObject->Release();841shader->vertexShaderObject = NULL;842}843844return;845}846}847}848else {849#endif850// if the pixel shader source doesn't exist, fall back and try to load the pixel shader bytecode851sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/CSO-DX9/%s.fso", fileName);852InitFileInfo(&info);853if (LoadFile(&info, fullFilePath, FMODE_RB)) {854uint8 *fileData = NULL;855AllocateStorage((void **)&fileData, info.fileSize, DATASET_TMP, false);856ReadBytes(&info, fileData, info.fileSize);857CloseFile(&info);858859if (FAILED(dx9Device->CreatePixelShader((DWORD *)fileData, &shader->pixelShaderObject))) {860if (shader->pixelShaderObject) {861shader->pixelShaderObject->Release();862shader->pixelShaderObject = NULL;863}864865RemoveStorageEntry((void **)&fileData);866return;867}868869RemoveStorageEntry((void **)&fileData);870}871872#if !RETRO_USE_ORIGINAL_CODE873}874#endif875876shaderCount++;877}878879bool RenderDevice::InitShaders()880{881dx9Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);882dx9Device->SetRenderState(D3DRS_LIGHTING, false);883dx9Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);884dx9Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);885dx9Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);886dx9Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);887dx9Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);888dx9Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);889890int32 maxShaders = 0;891#if RETRO_USE_MOD_LOADER892// this causes small memleaks here and in other render devices, as we never close the existing shaders893// TODO: fix? 🤨894shaderCount = 0;895#endif896if (videoSettings.shaderSupport) {897LoadShader("None", false);898LoadShader("Clean", true);899LoadShader("CRT-Yeetron", true);900LoadShader("CRT-Yee64", true);901902#if RETRO_USE_MOD_LOADER903// a place for mods to load custom shaders904RunModCallbacks(MODCB_ONSHADERLOAD, NULL);905userShaderCount = shaderCount;906#endif907908LoadShader("YUV-420", true);909LoadShader("YUV-422", true);910LoadShader("YUV-444", true);911LoadShader("RGB-Image", true);912maxShaders = shaderCount;913}914else {915for (int32 s = 0; s < SHADER_COUNT; ++s) shaderList[s].linear = true;916917shaderList[0].linear = videoSettings.windowed ? false : shaderList[0].linear;918maxShaders = 1;919shaderCount = 1;920}921922// no shaders == no support923if (!maxShaders) {924videoSettings.shaderSupport = false;925926for (int32 s = 0; s < SHADER_COUNT; ++s) shaderList[s].linear = true;927928shaderList[0].linear = videoSettings.windowed ? false : shaderList[0].linear;929maxShaders = 1;930shaderCount = 1;931}932933videoSettings.shaderID = videoSettings.shaderID >= maxShaders ? 0 : videoSettings.shaderID;934935if (shaderList[videoSettings.shaderID].linear || videoSettings.screenCount > 1) {936dx9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);937dx9Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);938}939else {940dx9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);941dx9Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);942}943944dx9Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);945946return true;947}948949bool RenderDevice::SetupRendering()950{951dx9Context = Direct3DCreate9(D3D_SDK_VERSION);952if (!dx9Context)953return false;954955ZeroMemory(&deviceIdentifier, sizeof(deviceIdentifier));956957GetDisplays();958959if (!InitGraphicsAPI() || !InitShaders())960return false;961962int32 size = videoSettings.pixWidth >= SCREEN_YSIZE ? videoSettings.pixWidth : SCREEN_YSIZE;963scanlines = (ScanlineInfo *)malloc(size * sizeof(ScanlineInfo));964memset(scanlines, 0, size * sizeof(ScanlineInfo));965966videoSettings.windowState = WINDOWSTATE_ACTIVE;967videoSettings.dimMax = 1.0;968videoSettings.dimPercent = 1.0;969970return true;971}972973void RenderDevice::GetDisplays()974{975adapterCount = dx9Context->GetAdapterCount();976977UINT prevAdapter = dxAdapter;978979HMONITOR windowMonitor = MonitorFromWindow(windowHandle, MONITOR_DEFAULTTOPRIMARY);980dxAdapter = 0;981for (int32 a = 0; a < adapterCount; ++a) {982D3DDISPLAYMODE displayMode;983984HMONITOR monitor = dx9Context->GetAdapterMonitor(a);985dx9Context->GetAdapterDisplayMode(a, &displayMode);986displayWidth[a] = displayMode.Width;987displayHeight[a] = displayMode.Height;988989if (windowMonitor == monitor) {990MONITORINFO lpmi;991ZeroMemory(&lpmi, sizeof(lpmi));992lpmi.cbSize = sizeof(MONITORINFO);993994GetMonitorInfo(windowMonitor, &lpmi);995dxAdapter = a;996monitorDisplayRect = lpmi.rcMonitor;997}998}9991000D3DADAPTER_IDENTIFIER9 adapterIdentifier;1001ZeroMemory(&adapterIdentifier, sizeof(adapterIdentifier));1002dx9Context->GetAdapterIdentifier(dxAdapter, 0, &adapterIdentifier);10031004// no change, don't reload anything1005if (memcmp(&deviceIdentifier, &adapterIdentifier.DeviceIdentifier, sizeof(deviceIdentifier)) == 0 && dxAdapter == prevAdapter)1006return;10071008deviceIdentifier = adapterIdentifier.DeviceIdentifier;10091010displayCount = dx9Context->GetAdapterModeCount(dxAdapter, D3DFMT_X8R8G8B8);1011if (displayInfo.displays)1012free(displayInfo.displays);10131014displayInfo.displays = (decltype(displayInfo.displays))malloc(sizeof(D3DDISPLAYMODE) * displayCount);1015int32 newDisplayCount = 0;1016bool32 foundFullScreenDisplay = false;10171018for (int32 d = 0; d < displayCount; ++d) {1019dx9Context->EnumAdapterModes(dxAdapter, D3DFMT_X8R8G8B8, d, &displayInfo.displays[newDisplayCount].internal);10201021int32 refreshRate = displayInfo.displays[newDisplayCount].refresh_rate;1022if (refreshRate >= 59 && (refreshRate <= 60 || refreshRate >= 120) && displayInfo.displays[newDisplayCount].height >= (SCREEN_YSIZE * 2)) {1023if (d && refreshRate == 60 && displayInfo.displays[newDisplayCount - 1].refresh_rate == 59) {1024memcpy(&displayInfo.displays[newDisplayCount - 1], &displayInfo.displays[newDisplayCount], sizeof(displayInfo.displays[0]));1025--newDisplayCount;1026}10271028if (videoSettings.fsWidth == displayInfo.displays[newDisplayCount].width1029&& videoSettings.fsHeight == displayInfo.displays[newDisplayCount].height)1030foundFullScreenDisplay = true;10311032++newDisplayCount;1033}1034}10351036displayCount = newDisplayCount;1037if (!foundFullScreenDisplay) {1038videoSettings.fsWidth = 0;1039videoSettings.fsHeight = 0;1040videoSettings.refreshRate = 60; // 0;1041}1042}10431044void RenderDevice::GetWindowSize(int32 *width, int32 *height)1045{1046D3DDISPLAYMODE display;1047dx9Context->GetAdapterDisplayMode(dxAdapter, &display);10481049if (width)1050*width = display.Width;10511052if (height)1053*height = display.Height;1054}10551056void RenderDevice::ProcessEvent(MSG Msg)1057{1058bool handledMsg = false;10591060switch (Msg.message) {1061case WM_QUIT:1062isRunning = false;1063handledMsg = true;1064break;10651066// called when holding "ALT" down1067case WM_SYSKEYDOWN: {1068WPARAM activeButtons = Msg.wParam;1069switch (Msg.wParam) {1070// shift key1071case VK_SHIFT:1072activeButtons = MapVirtualKey(((Msg.lParam >> 16) & 0xFF), MAPVK_VSC_TO_VK_EX);1073break;10741075// CTRL key1076case VK_CONTROL:1077activeButtons = VK_LCONTROL + (((Msg.lParam >> 24) & 0xFF) & 1);1078break;10791080// ALT key1081case VK_MENU: activeButtons = VK_LMENU + (((Msg.lParam >> 24) & 0xFF) & 1); break;1082}10831084switch (Msg.wParam) {1085default:1086#if RETRO_INPUTDEVICE_KEYBOARD1087SKU::UpdateKeyState(activeButtons);1088handledMsg = true;1089#endif1090break;10911092case VK_RETURN: // alt + enter1093if (GetAsyncKeyState(VK_MENU)) {1094videoSettings.windowed ^= 1;1095UpdateGameWindow();1096changedVideoSettings = false;1097handledMsg = true;1098}10991100#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1101RSDK::SKU::specialKeyStates[1] = true;1102#endif1103break;11041105case VK_F4: // alt + f41106if (GetAsyncKeyState(VK_MENU))1107isRunning = false;11081109handledMsg = true;1110break;1111}1112}11131114// regular keydown1115case WM_KEYDOWN: {1116WPARAM activeButtons = Msg.wParam;1117switch (Msg.wParam) {1118// shift key1119case VK_SHIFT:1120activeButtons = MapVirtualKey(((Msg.lParam >> 16) & 0xFF), MAPVK_VSC_TO_VK_EX);1121break;11221123// CTRL key1124case VK_CONTROL:1125activeButtons = VK_LCONTROL + (((Msg.lParam >> 24) & 0xFF) & 1);1126break;11271128// ALT key1129case VK_MENU: activeButtons = VK_LMENU + (((Msg.lParam >> 24) & 0xFF) & 1); break;1130}11311132// handledMsg = true;1133switch (Msg.wParam) {1134default:1135#if RETRO_INPUTDEVICE_KEYBOARD1136SKU::UpdateKeyState(activeButtons);1137#endif1138break;11391140case VK_BACK:1141if (engine.devMenu) {1142engine.gameSpeed = engine.fastForwardSpeed;11431144handledMsg = true;1145}1146break;11471148case VK_ESCAPE:1149if (engine.devMenu) {1150#if RETRO_REV0U1151if (sceneInfo.state == ENGINESTATE_DEVMENU || RSDK::Legacy::gameMode == RSDK::Legacy::ENGINE_DEVMENU)1152#else1153if (sceneInfo.state == ENGINESTATE_DEVMENU)1154#endif1155CloseDevMenu();1156else1157OpenDevMenu();11581159handledMsg = true;1160}1161else {1162#if RETRO_INPUTDEVICE_KEYBOARD1163SKU::UpdateKeyState(activeButtons);1164#endif1165}11661167#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1168RSDK::SKU::specialKeyStates[0] = true;1169#endif1170break;11711172#if !RETRO_USE_ORIGINAL_CODE1173case VK_F1:1174if (engine.devMenu) {1175sceneInfo.listPos--;1176while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart1177|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd1178|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {1179sceneInfo.activeCategory--;1180if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {1181sceneInfo.activeCategory = sceneInfo.categoryCount - 1;1182}1183sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd;1184}11851186#if RETRO_REV0U1187switch (engine.version) {1188default: break;1189case 5: LoadScene(); break;1190case 4:1191case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;1192}1193#else1194LoadScene();1195#endif11961197handledMsg = true;1198}1199break;12001201case VK_F2:1202if (engine.devMenu) {1203sceneInfo.listPos++;1204while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart1205|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd1206|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {1207sceneInfo.activeCategory++;1208if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {1209sceneInfo.activeCategory = 0;1210}1211sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart;1212}12131214#if RETRO_REV0U1215switch (engine.version) {1216default: break;1217case 5: LoadScene(); break;1218case 4:1219case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;1220}1221#else1222LoadScene();1223#endif12241225handledMsg = true;1226}1227break;1228#endif12291230case VK_F3:1231if (userShaderCount) {1232videoSettings.shaderID = (videoSettings.shaderID + 1) % userShaderCount;12331234handledMsg = true;1235}1236break;12371238#if !RETRO_USE_ORIGINAL_CODE1239case VK_F4:1240if (engine.devMenu) {1241engine.showEntityInfo ^= 1;12421243handledMsg = true;1244}1245break;12461247case VK_F5:1248if (engine.devMenu) {1249// Quick-Reload1250#if RETRO_USE_MOD_LOADER1251if (GetAsyncKeyState(VK_CONTROL))1252RefreshModFolders();1253#endif12541255#if RETRO_REV0U1256switch (engine.version) {1257default: break;1258case 5: LoadScene(); break;1259case 4:1260case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;1261}1262#else1263LoadScene();1264#endif12651266handledMsg = true;1267}1268break;12691270case VK_F6:1271if (engine.devMenu && videoSettings.screenCount > 1) {1272videoSettings.screenCount--;12731274handledMsg = true;1275}1276break;12771278case VK_F7:1279if (engine.devMenu && videoSettings.screenCount < SCREEN_COUNT) {1280videoSettings.screenCount++;12811282handledMsg = true;1283}1284break;12851286case VK_F8:1287if (engine.devMenu) {1288engine.showUpdateRanges ^= 1;12891290handledMsg = true;1291}1292break;12931294case VK_F9:1295if (engine.devMenu) {1296showHitboxes ^= 1;12971298handledMsg = true;1299}1300break;13011302case VK_F10:1303if (engine.devMenu) {1304engine.showPaletteOverlay ^= 1;13051306handledMsg = true;1307}1308break;1309#endif13101311case VK_INSERT:1312case VK_F11:1313if (engine.devMenu) {1314engine.frameStep = true;13151316handledMsg = true;1317}1318break;13191320case VK_PAUSE:1321case VK_F12:1322if (engine.devMenu) {1323#if RETRO_REV0U1324switch (engine.version) {1325default: break;1326case 5:1327if (sceneInfo.state != ENGINESTATE_NONE)1328sceneInfo.state ^= ENGINESTATE_STEPOVER;1329break;1330case 4:1331case 3:1332if (RSDK::Legacy::stageMode != ENGINESTATE_NONE)1333RSDK::Legacy::stageMode ^= RSDK::Legacy::STAGEMODE_STEPOVER;1334break;1335}1336#else1337if (sceneInfo.state != ENGINESTATE_NONE)1338sceneInfo.state ^= ENGINESTATE_STEPOVER;1339#endif13401341handledMsg = true;1342}1343break;1344}1345break;1346}13471348case WM_KEYUP:1349case WM_SYSKEYUP: {1350WPARAM activeButtons = Msg.wParam;1351switch (Msg.wParam) {1352case VK_SHIFT: activeButtons = MapVirtualKey(((Msg.lParam >> 16) & 0xFF), MAPVK_VSC_TO_VK_EX); break;13531354case VK_CONTROL: activeButtons = VK_LCONTROL + ((Msg.lParam >> 24) & 1); break;13551356case VK_MENU: // ALT key1357activeButtons = VK_LMENU + ((Msg.lParam >> 24) & 1);1358break;1359}13601361switch (Msg.wParam) {1362default:1363#if RETRO_INPUTDEVICE_KEYBOARD1364SKU::ClearKeyState(activeButtons);1365#endif1366break;13671368#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1369case VK_ESCAPE:1370RSDK::SKU::specialKeyStates[0] = false;1371SKU::ClearKeyState(activeButtons);1372break;13731374case VK_RETURN:1375RSDK::SKU::specialKeyStates[1] = false;1376SKU::ClearKeyState(activeButtons);1377break;1378#endif13791380case VK_BACK:1381engine.gameSpeed = 1;13821383handledMsg = true;1384break;1385}13861387break;1388}13891390case WM_LBUTTONDOWN: touchInfo.down[0] = 1; touchInfo.count = 1;13911392#if !RETRO_REV021393RSDK::SKU::buttonDownCount++;1394#endif13951396handledMsg = true;1397break;13981399case WM_LBUTTONUP: touchInfo.down[0] = 0; touchInfo.count = 0;14001401#if !RETRO_REV021402RSDK::SKU::buttonDownCount--;1403#endif14041405handledMsg = true;1406break;14071408case WM_MBUTTONDOWN: handledMsg = true; break;14091410case WM_RBUTTONDOWN: handledMsg = true;1411#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1412RSDK::SKU::specialKeyStates[3] = true;1413RSDK::SKU::buttonDownCount++;1414#endif1415break;14161417case WM_RBUTTONUP: handledMsg = true;1418#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1419RSDK::SKU::specialKeyStates[3] = false;1420RSDK::SKU::buttonDownCount--;1421#endif1422break;1423}14241425if (!handledMsg)1426DispatchMessage(&Msg);1427}14281429bool RenderDevice::ProcessEvents()1430{1431MSG Msg = {};1432while (PeekMessage(&Msg, NULL, 0, 0, true)) {1433ProcessEvent(Msg);14341435if (!isRunning)1436return false;1437}14381439return isRunning;1440}14411442LRESULT CALLBACK RenderDevice::WindowEventCallback(HWND hRecipient, UINT message, WPARAM wParam, LPARAM lParam)1443{1444bool32 forceExit = false;1445GUID deviceGUID = KSCATEGORY_AUDIO;14461447switch (message) {1448case WM_CREATE: {1449if (deviceNotif)1450return 0;14511452DEV_BROADCAST_DEVICEINTERFACE filter;1453filter.dbcc_name[0] = 0;1454filter.dbcc_reserved = 0;1455filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);1456filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;1457filter.dbcc_classguid = deviceGUID;14581459deviceNotif = RegisterDeviceNotification(hRecipient, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);14601461forceExit = true;1462break;1463}14641465case WM_DESTROY:1466if (deviceNotif) {1467UnregisterDeviceNotification(deviceNotif);1468deviceNotif = 0;1469}14701471isRunning = false;1472forceExit = true;1473break;14741475case WM_MOVE:1476case WM_SIZE: forceExit = true; break;14771478case WM_ACTIVATE:1479if (wParam) {1480if (!videoSettings.windowState)1481return 0;14821483if (AudioDevice::audioFocus == 1) {1484AudioDevice::audioFocus = 0;1485if (AudioDevice::sourceVoice)1486AudioDevice::sourceVoice->Start(0, 0);1487}14881489GetDisplays();1490videoSettings.windowState = WINDOWSTATE_ACTIVE;1491}1492else {1493touchInfo.down[0] = false;1494touchInfo.count = 0;1495if (!videoSettings.windowState)1496return 0;1497#if !RETRO_USE_ORIGINAL_CODE1498if (customSettings.disableFocusPause)1499return 0;1500#endif15011502if (!AudioDevice::audioFocus) {1503AudioDevice::audioFocus = 1;1504if (AudioDevice::sourceVoice)1505AudioDevice::sourceVoice->Stop(0, 0);1506}15071508videoSettings.windowState = WINDOWSTATE_INACTIVE;1509}15101511forceExit = true;1512break;15131514case WM_PAINT:1515BeginPaint(hRecipient, &Paint);1516EndPaint(hRecipient, &Paint);15171518forceExit = true;1519break;15201521case WM_DEVICECHANGE: {1522DEV_BROADCAST_DEVICEINTERFACE *deviceInterace = (DEV_BROADCAST_DEVICEINTERFACE *)lParam;15231524if ((wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE) && deviceInterace1525&& deviceInterace->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {15261527if (memcmp(&deviceInterace->dbcc_classguid, &deviceGUID, sizeof(deviceGUID)) == 0) {1528AudioDevice::audioState = 30;1529}1530}15311532#if RETRO_INPUTDEVICE_XINPUT1533SKU::UpdateXInputDevices();1534#endif15351536#if RETRO_INPUTDEVICE_RAWINPUT1537SKU::InitHIDAPI();1538#endif15391540#if RETRO_INPUTDEVICE_XINPUT1541SKU::InitXInputAPI();1542#endif15431544forceExit = true;1545break;1546}15471548#if RETRO_INPUTDEVICE_RAWINPUT1549case WM_INPUT:1550SKU::UpdateHIDButtonStates((HRAWINPUT)lParam);15511552forceExit = true;1553break;1554#endif15551556case WM_SYSCOMMAND: {1557int32 param = wParam & 0xFFF0;1558if (param == SC_MINIMIZE) {1559touchInfo.down[0] = 0;1560touchInfo.count = 0;1561if (videoSettings.windowState) {1562PauseSound();1563videoSettings.windowState = WINDOWSTATE_INACTIVE;1564}1565}1566else if (param == SC_MAXIMIZE && videoSettings.windowState != WINDOWSTATE_UNINITIALIZED) {1567ResumeSound();1568videoSettings.windowState = WINDOWSTATE_ACTIVE;1569}15701571break;1572}15731574case WM_MENUSELECT:1575case WM_ENTERSIZEMOVE:1576touchInfo.down[0] = 0;1577touchInfo.count = 0;15781579forceExit = true;1580break;15811582case WM_EXITSIZEMOVE:1583GetDisplays();15841585forceExit = true;1586break;15871588default: break;1589}15901591if (forceExit)1592return 0;1593else1594return DefWindowProc(hRecipient, message, wParam, lParam);1595}15961597void RenderDevice::SetupImageTexture(int32 width, int32 height, uint8 *imagePixels)1598{1599if (!imagePixels)1600return;16011602dx9Device->SetTexture(0, NULL);16031604D3DLOCKED_RECT rect;1605if (imageTexture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD) == 0) {1606DWORD *pixels = (DWORD *)rect.pBits;1607int32 pitch = (rect.Pitch >> 2) - width;16081609uint32 *imagePixels32 = (uint32 *)imagePixels;1610for (int32 y = 0; y < height; ++y) {1611for (int32 x = 0; x < width; ++x) {1612*pixels++ = *imagePixels32++;1613}16141615pixels += pitch;1616}16171618imageTexture->UnlockRect(0);1619}1620}16211622void RenderDevice::SetupVideoTexture_YUV420(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,1623int32 strideV)1624{1625dx9Device->SetTexture(0, NULL);16261627D3DLOCKED_RECT rect;1628if (imageTexture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD) == 0) {1629DWORD *pixels = (DWORD *)rect.pBits;1630int32 pitch = (rect.Pitch >> 2) - width;16311632if (videoSettings.shaderSupport) {1633// Shaders are supported! lets watch this video in full color!1634for (int32 y = 0; y < height; ++y) {1635for (int32 x = 0; x < width; ++x) {1636*pixels++ = (yPlane[x] << 16) | 0xFF000000;1637}16381639pixels += pitch;1640yPlane += strideY;1641}16421643pixels = (DWORD *)rect.pBits;1644pitch = (rect.Pitch >> 2) - (width >> 1);1645for (int32 y = 0; y < (height >> 1); ++y) {1646for (int32 x = 0; x < (width >> 1); ++x) {1647*pixels++ |= (vPlane[x] << 0) | (uPlane[x] << 8) | 0xFF000000;1648}16491650pixels += pitch;1651uPlane += strideU;1652vPlane += strideV;1653}1654}1655else {1656// No shader support means no YUV support! at least use the brightness to show it in grayscale!1657for (int32 y = 0; y < height; ++y) {1658for (int32 x = 0; x < width; ++x) {1659int32 brightness = yPlane[x];1660*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;1661}16621663pixels += pitch;1664yPlane += strideY;1665}1666}16671668imageTexture->UnlockRect(0);1669}1670}1671void RenderDevice::SetupVideoTexture_YUV422(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,1672int32 strideV)1673{1674dx9Device->SetTexture(0, NULL);16751676D3DLOCKED_RECT rect;1677if (imageTexture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD) == 0) {1678DWORD *pixels = (DWORD *)rect.pBits;1679int32 pitch = (rect.Pitch >> 2) - width;16801681if (videoSettings.shaderSupport) {1682// Shaders are supported! lets watch this video in full color!1683for (int32 y = 0; y < height; ++y) {1684for (int32 x = 0; x < width; ++x) {1685*pixels++ = (yPlane[x] << 16) | 0xFF000000;1686}16871688pixels += pitch;1689yPlane += strideY;1690}16911692pixels = (DWORD *)rect.pBits;1693pitch = (rect.Pitch >> 2) - (width >> 1);1694for (int32 y = 0; y < height; ++y) {1695for (int32 x = 0; x < (width >> 1); ++x) {1696*pixels++ |= (vPlane[x] << 0) | (uPlane[x] << 8) | 0xFF000000;1697}16981699pixels += pitch;1700uPlane += strideU;1701vPlane += strideV;1702}1703}1704else {1705// No shader support means no YUV support! at least use the brightness to show it in grayscale!1706for (int32 y = 0; y < height; ++y) {1707for (int32 x = 0; x < width; ++x) {1708int32 brightness = yPlane[x];1709*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;1710}17111712pixels += pitch;1713yPlane += strideY;1714}1715}17161717imageTexture->UnlockRect(0);1718}1719}1720void RenderDevice::SetupVideoTexture_YUV444(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,1721int32 strideV)1722{1723dx9Device->SetTexture(0, NULL);17241725D3DLOCKED_RECT rect;1726if (imageTexture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD) == 0) {1727DWORD *pixels = (DWORD *)rect.pBits;1728int32 pitch = (rect.Pitch >> 2) - width;17291730if (videoSettings.shaderSupport) {1731// Shaders are supported! lets watch this video in full color!1732for (int32 y = 0; y < height; ++y) {1733int32 pos1 = yPlane - vPlane;1734int32 pos2 = uPlane - vPlane;1735uint8 *pixV = vPlane;1736for (int32 x = 0; x < width; ++x) {1737*pixels++ = pixV[0] | (pixV[pos2] << 8) | (pixV[pos1] << 16) | 0xFF000000;1738pixV++;1739}17401741pixels += pitch;1742yPlane += strideY;1743uPlane += strideU;1744vPlane += strideV;1745}1746}1747else {1748// No shader support means no YUV support! at least use the brightness to show it in grayscale!1749for (int32 y = 0; y < height; ++y) {1750for (int32 x = 0; x < width; ++x) {1751int32 brightness = yPlane[x];1752*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;1753}17541755pixels += pitch;1756yPlane += strideY;1757}1758}17591760imageTexture->UnlockRect(0);1761}1762}17631764