From 917d6d679e129ad40c921db0c2b071224e82050a Mon Sep 17 00:00:00 2001 From: Daniel Kollmann Date: Sun, 14 May 2023 15:58:08 +0200 Subject: [PATCH 01/25] Added support for transforming homogenous W geometry into world geometry. --- Settings/Settings.h | 14 +++ ddraw/DebugOverlay.cpp | 3 +- ddraw/DebugOverlay.h | 2 +- ddraw/IDirect3DDeviceX.cpp | 188 +++++++++++++++++++++++++++++++++++-- ddraw/IDirect3DDeviceX.h | 4 + ddraw/RenderData.h | 37 ++++++++ dxwrapper.vcxproj | 1 + dxwrapper.vcxproj.filters | 5 +- 8 files changed, 245 insertions(+), 9 deletions(-) create mode 100644 ddraw/RenderData.h diff --git a/Settings/Settings.h b/Settings/Settings.h index 0ef68a40..30e33503 100644 --- a/Settings/Settings.h +++ b/Settings/Settings.h @@ -43,6 +43,13 @@ visit(DdrawOverrideStencilFormat) \ visit(DdrawResolutionHack) \ visit(DdrawUseDirect3D9Ex) \ + visit(DdrawConvertHomogeneousW) \ + visit(DdrawConvertHomogeneousToWorld) \ + visit(DdrawConvertHomogeneousToWorldUseGameCamera) \ + visit(DdrawConvertHomogeneousToWorldFOV) \ + visit(DdrawConvertHomogeneousToWorldNearPlane) \ + visit(DdrawConvertHomogeneousToWorldFarPlane) \ + visit(DdrawConvertHomogeneousToWorldDepthOffset) \ visit(DdrawUseNativeResolution) \ visit(DdrawEnableMouseHook) \ visit(DdrawHookSystem32) \ @@ -209,6 +216,13 @@ struct CONFIG bool DdrawIntegerScalingClamp = false; // Scales the screen by an integer value to help preserve video quality bool DdrawMaintainAspectRatio = false; // Keeps the current DirectDraw aspect ratio when overriding the game's resolution bool DdrawUseDirect3D9Ex = false; // Use Direct3D9Ex extensions for Dd7to9 + bool DdrawConvertHomogeneousW = false; // Convert primites using D3DFVF_XYZRHW to D3DFVF_XYZW. + bool DdrawConvertHomogeneousToWorld = false; // Convert primitives back into a world space. Needed for RTX. + bool DdrawConvertHomogeneousToWorldUseGameCamera = false; // Use the game's view matrix instead of replacing it with our own. + float DdrawConvertHomogeneousToWorldFOV = 90.0f; // The field of view of the camera used to reconstruct the original 3D world. + float DdrawConvertHomogeneousToWorldNearPlane = 1.0f; // The near plane of the camera used to reconstruct the original 3D world. + float DdrawConvertHomogeneousToWorldFarPlane = 1000.0f; // The far plane of the camera used to reconstruct the original 3D world. + float DdrawConvertHomogeneousToWorldDepthOffset = 0.0f; // The offset to add to the geometry so it does not clip into the near plane. bool DdrawUseNativeResolution = false; // Uses the current screen resolution for Dd7to9 DWORD DdrawClippedWidth = 0; // Used to scaled Direct3d9 to use this width when using Dd7to9 DWORD DdrawClippedHeight = 0; // Used to scaled Direct3d9 to use this height when using Dd7to9 diff --git a/ddraw/DebugOverlay.cpp b/ddraw/DebugOverlay.cpp index 2a52154f..d5763cd5 100644 --- a/ddraw/DebugOverlay.cpp +++ b/ddraw/DebugOverlay.cpp @@ -15,6 +15,7 @@ */ #include "DebugOverlay.h" +#include "RenderData.h" #include #define IMGUI_DEFINE_MATH_OPERATORS @@ -98,7 +99,7 @@ void DebugOverlay::BeginScene() ImGui::NewFrame(); } -void DebugOverlay::EndScene() +void DebugOverlay::EndScene(const RenderData &RenderData) { static bool ShowDebugUI = false; if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftAlt)) && diff --git a/ddraw/DebugOverlay.h b/ddraw/DebugOverlay.h index f7e948f2..a0f2c34f 100644 --- a/ddraw/DebugOverlay.h +++ b/ddraw/DebugOverlay.h @@ -48,7 +48,7 @@ class DebugOverlay // Frame functions void BeginScene(); - void EndScene(); + void EndScene(const class RenderData &RenderData); // Functions void SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix); diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index f820a444..db07013e 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -16,9 +16,10 @@ #include "ddraw.h" #include +#include // Enable for testing only -//#define ENABLE_DEBUGOVERLAY +#define ENABLE_DEBUGOVERLAY #ifdef ENABLE_DEBUGOVERLAY #include "DebugOverlay.h" @@ -338,15 +339,103 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat break; } - HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix); - - if (SUCCEEDED(hr)) + if(Config.DdrawConvertHomogeneousW) { #ifdef ENABLE_DEBUGOVERLAY + // Set the original matrix DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix); #endif + + if(dtstTransformStateType == D3DTS_VIEW) + { + D3DVIEWPORT9 Viewport9; + if(SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9))) + { + const float width = (float)Viewport9.Width; + const float height = (float)Viewport9.Height; + const float ratio = width / height; + + // Replace the matrix with one that handles D3DFVF_XYZRHW geometry + _D3DMATRIX view; + ZeroMemory(&view, sizeof(_D3DMATRIX)); + view._11 = 2.0f / width; + view._22 = -2.0f / height; + view._33 = 1.0f; + view._41 = -1.0f; // translate X + view._42 = 1.0f; // translate Y + view._44 = 1.0f; + + if(!Config.DdrawConvertHomogeneousToWorld) + { + // Override the original matrix + std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); + } + else + { + // Override the original matrix + std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); + + // Store the original matrix so it can be restored + std::memcpy(&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &view, sizeof(_D3DMATRIX)); + + // The Black & White matrix is an ortho camera, so create a perspective one matching the game + const float fov = Config.DdrawConvertHomogeneousToWorldFOV; + const float nearplane = Config.DdrawConvertHomogeneousToWorldNearPlane; + const float farplane = Config.DdrawConvertHomogeneousToWorldFarPlane; + DirectX::XMMATRIX proj = DirectX::XMMatrixPerspectiveFovLH(fov * (3.14159265359f / 180.0f), ratio, nearplane, farplane); + + DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix, proj); + + DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + + DirectX::XMMATRIX viewMatrix; + if(Config.DdrawConvertHomogeneousToWorldUseGameCamera) + { + // To reconstruct the 3D world, we need to know where the camera is and where it is looking + DirectX::XMVECTOR position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); + DirectX::XMVECTOR direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34); + + viewMatrix = DirectX::XMMatrixLookToLH(position, direction, up); + } + else + { + const float cameradir = 1.0f; + + DirectX::XMVECTOR pos = DirectX::XMVectorSet(0.0f, 0.0f, -cameradir, 0.0f); + DirectX::XMVECTOR direction = DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f); + + viewMatrix = DirectX::XMMatrixLookToLH(pos, direction, up); + } + + // Store the 3D view matrix so it can be set later + DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix, viewMatrix); + + // Store the view inverse matrix of the game, so we can transform the geometry with it + DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)lpD3DMatrix); + DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj); + DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp); + + DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, Config.DdrawConvertHomogeneousToWorldDepthOffset); + + RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); + } + } + } + else + { + return D3D_OK; + } } + HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix); + +#ifdef ENABLE_DEBUGOVERLAY + if (SUCCEEDED(hr) && !Config.DdrawConvertHomogeneousW) + { + DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix); + } +#endif + return hr; } @@ -1617,7 +1706,7 @@ HRESULT m_IDirect3DDeviceX::EndScene() } #ifdef ENABLE_DEBUGOVERLAY - DOverlay.EndScene(); + DOverlay.EndScene(RenderData); #endif // The IDirect3DDevice7::EndScene method ends a scene that was begun by calling the IDirect3DDevice7::BeginScene method. @@ -2453,11 +2542,98 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy } else { + const UINT stride = GetVertexStride(dwVertexTypeDesc); + + // Handle PositionT + if((dwVertexTypeDesc & D3DFVF_XYZRHW) != 0 && Config.DdrawConvertHomogeneousW) + { + if(!Config.DdrawConvertHomogeneousToWorld) + { + UINT8 *vertex = (UINT8*)lpVertices; + + for (UINT x = 0; x < dwVertexCount; x++) + { + float *pos = (float*) vertex; + + pos[3] = 1.0f; + + vertex += stride; + } + + // Update the FVF + dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; + } + else + { + const UINT newstride = stride - sizeof(float); + const UINT restSize = stride - sizeof(float) * 4; + + RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.resize(newstride * dwVertexCount); + + UINT8 *sourceVertex = (UINT8*)lpVertices; + UINT8 *targetVertex = (UINT8*)RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.data(); + + lpVertices = targetVertex; + + for (UINT x = 0; x < dwVertexCount; x++) + { + // Transform the vertices into world space + float *srcpos = (float*) sourceVertex; + float *trgtpos = (float*) targetVertex; + + DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]); + + DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixInverse); + + xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global)); + + trgtpos[0] = DirectX::XMVectorGetX(xpos_global); + trgtpos[1] = DirectX::XMVectorGetY(xpos_global); + trgtpos[2] = DirectX::XMVectorGetZ(xpos_global); + + // Copy the rest + std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize); + + // Move to next vertex + sourceVertex += stride; + targetVertex += newstride; + } + + // Set transform + (*d3d9Device)->SetTransform(D3DTS_VIEW, &RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix); + + // Update the FVF + const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; + + // Set fixed function vertex type + (*d3d9Device)->SetFVF(newVertexTypeDesc); + + // Draw indexed primitive UP + hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, newstride); + + // Restore transform + _D3DMATRIX identityMatrix; + ZeroMemory(&identityMatrix, sizeof(_D3DMATRIX)); + identityMatrix._11 = 1.0f; + identityMatrix._22 = 1.0f; + identityMatrix._33 = 1.0f; + + (*d3d9Device)->SetTransform(D3DTS_VIEW, &RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); + + // Handle dwFlags + UnSetDrawFlags(rsClipping, rsLighting, rsExtents, newVertexTypeDesc, dwFlags, DirectXVersion); + + return hr; + } + } + // Set fixed function vertex type (*d3d9Device)->SetFVF(dwVertexTypeDesc); // Draw indexed primitive UP - hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, GetVertexStride(dwVertexTypeDesc)); + hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, stride); } // Handle dwFlags diff --git a/ddraw/IDirect3DDeviceX.h b/ddraw/IDirect3DDeviceX.h index 792d893a..ed8f73a8 100644 --- a/ddraw/IDirect3DDeviceX.h +++ b/ddraw/IDirect3DDeviceX.h @@ -1,6 +1,7 @@ #pragma once #include "IDirectDrawX.h" +#include "RenderData.h" class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject { @@ -27,6 +28,9 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject // SetTexture array LPDIRECTDRAWSURFACE7 AttachedTexture[8] = {}; + // The data used for rendering + RenderData RenderData; + // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { diff --git a/ddraw/RenderData.h b/ddraw/RenderData.h new file mode 100644 index 00000000..a758070e --- /dev/null +++ b/ddraw/RenderData.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +class RenderData +{ +public: + + // Store the projection matrix used to transform the geometry on the gpu + _D3DMATRIX DdrawConvertHomogeneousToWorld_ProjectionMatrix; + + // Store the view matrix used to transform the geometry on the gpu + _D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrix; + + // Store the original view matrix, so we can restore it + _D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixOriginal; + + // Store the inverse view matrix to transform the geometry on the cpu + DirectX::XMMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixInverse; + + // Intermediate buffer for the geometry conversion + std::vector DdrawConvertHomogeneousToWorld_IntermediateGeometry; + + RenderData() + { + ZeroMemory(&DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX)); + DdrawConvertHomogeneousToWorld_ViewMatrix._11 = 1.0f; + DdrawConvertHomogeneousToWorld_ViewMatrix._22 = 1.0f; + DdrawConvertHomogeneousToWorld_ViewMatrix._33 = 1.0f; + DdrawConvertHomogeneousToWorld_ViewMatrix._44 = 1.0f; + + std::memcpy(&DdrawConvertHomogeneousToWorld_ProjectionMatrix, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX)); + std::memcpy(&DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX)); + } +}; diff --git a/dxwrapper.vcxproj b/dxwrapper.vcxproj index 3854925f..3eac7208 100644 --- a/dxwrapper.vcxproj +++ b/dxwrapper.vcxproj @@ -588,6 +588,7 @@ cmd /q /c "cd /D ""$(ProjectDir)d3d8\"" && del build.bat" + diff --git a/dxwrapper.vcxproj.filters b/dxwrapper.vcxproj.filters index e65b9e64..8c18b85b 100644 --- a/dxwrapper.vcxproj.filters +++ b/dxwrapper.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -1868,6 +1868,9 @@ ddraw + + ddraw + From e8ff88ddcfe646f2d344bfc3d2edf141051a1351 Mon Sep 17 00:00:00 2001 From: Daniel Kollmann Date: Wed, 17 May 2023 00:13:14 +0200 Subject: [PATCH 02/25] Fixed incorrect game camera position and orientation. Added option to disable lighting. Commented out unneeded XYZW code. --- Settings/Settings.h | 2 ++ ddraw/IDirect3DDeviceX.cpp | 53 ++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Settings/Settings.h b/Settings/Settings.h index 30e33503..8c6001ea 100644 --- a/Settings/Settings.h +++ b/Settings/Settings.h @@ -52,6 +52,7 @@ visit(DdrawConvertHomogeneousToWorldDepthOffset) \ visit(DdrawUseNativeResolution) \ visit(DdrawEnableMouseHook) \ + visit(DdrawDisableLighting) \ visit(DdrawHookSystem32) \ visit(D3d8HookSystem32) \ visit(D3d9HookSystem32) \ @@ -233,6 +234,7 @@ struct CONFIG DWORD DdrawOverrideRefreshRate = 0; // Force Direct3d9 to use this refresh rate when using Dd7to9 DWORD DdrawOverrideStencilFormat = 0; // Force Direct3d9 to use this AutoStencilFormat when using Dd7to9 bool DdrawEnableMouseHook = true; // Allow to hook into mouse to limit it to the chosen resolution + bool DdrawDisableLighting = false; // Allow to disable lighting DWORD DdrawHookSystem32 = 0; // Hooks the ddraw.dll file in the Windows System32 folder DWORD D3d8HookSystem32 = 0; // Hooks the d3d8.dll file in the Windows System32 folder DWORD D3d9HookSystem32 = 0; // Hooks the d3d9.dll file in the Windows System32 folder diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index db07013e..eea98e7d 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -372,6 +372,21 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat } else { + DirectX::XMVECTOR position, direction; + if(Config.DdrawConvertHomogeneousToWorldUseGameCamera) + { + // To reconstruct the 3D world, we need to know where the camera is and where it is looking + position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); + direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34); + } + else + { + const float cameradir = 1.0f; + + position = DirectX::XMVectorSet(0.0f, 0.0f, -cameradir, 0.0f); + DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f); + } + // Override the original matrix std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); @@ -387,25 +402,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix, proj); DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); - - DirectX::XMMATRIX viewMatrix; - if(Config.DdrawConvertHomogeneousToWorldUseGameCamera) - { - // To reconstruct the 3D world, we need to know where the camera is and where it is looking - DirectX::XMVECTOR position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); - DirectX::XMVECTOR direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34); - - viewMatrix = DirectX::XMMatrixLookToLH(position, direction, up); - } - else - { - const float cameradir = 1.0f; - - DirectX::XMVECTOR pos = DirectX::XMVectorSet(0.0f, 0.0f, -cameradir, 0.0f); - DirectX::XMVECTOR direction = DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f); - - viewMatrix = DirectX::XMMatrixLookToLH(pos, direction, up); - } + DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, up); // Store the 3D view matrix so it can be set later DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix, viewMatrix); @@ -2139,6 +2136,12 @@ HRESULT m_IDirect3DDeviceX::SetRenderState(D3DRENDERSTATETYPE dwRenderStateType, dwRenderStateType = D3DRS_DEPTHBIAS; break; } + case D3DRS_LIGHTING: + if(Config.DdrawDisableLighting) + { + dwRenderState = FALSE; + } + break; case D3DRENDERSTATE_TEXTUREPERSPECTIVE: return D3D_OK; // As long as the device's D3DPTEXTURECAPS_PERSPECTIVE is enabled, the correction will be applied automatically. case D3DRENDERSTATE_LINEPATTERN: @@ -2549,7 +2552,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy { if(!Config.DdrawConvertHomogeneousToWorld) { - UINT8 *vertex = (UINT8*)lpVertices; + /*UINT8 *vertex = (UINT8*)lpVertices; for (UINT x = 0; x < dwVertexCount; x++) { @@ -2558,17 +2561,17 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy pos[3] = 1.0f; vertex += stride; - } + }*/ // Update the FVF dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; } else { - const UINT newstride = stride - sizeof(float); + const UINT targetStride = stride - sizeof(float); const UINT restSize = stride - sizeof(float) * 4; - RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.resize(newstride * dwVertexCount); + RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); UINT8 *sourceVertex = (UINT8*)lpVertices; UINT8 *targetVertex = (UINT8*)RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.data(); @@ -2596,7 +2599,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy // Move to next vertex sourceVertex += stride; - targetVertex += newstride; + targetVertex += targetStride; } // Set transform @@ -2610,7 +2613,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy (*d3d9Device)->SetFVF(newVertexTypeDesc); // Draw indexed primitive UP - hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, newstride); + hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); // Restore transform _D3DMATRIX identityMatrix; From 17ba9b6a368199dd34f1aed6880cdd6d4e4aae3e Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Tue, 16 May 2023 17:43:35 -0700 Subject: [PATCH 03/25] Fix comments from pull request --- ddraw/DebugOverlay.cpp | 3 +-- ddraw/DebugOverlay.h | 2 +- ddraw/IDirect3DDeviceX.cpp | 34 +++++++++++++++------------------- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/ddraw/DebugOverlay.cpp b/ddraw/DebugOverlay.cpp index d5763cd5..2a52154f 100644 --- a/ddraw/DebugOverlay.cpp +++ b/ddraw/DebugOverlay.cpp @@ -15,7 +15,6 @@ */ #include "DebugOverlay.h" -#include "RenderData.h" #include #define IMGUI_DEFINE_MATH_OPERATORS @@ -99,7 +98,7 @@ void DebugOverlay::BeginScene() ImGui::NewFrame(); } -void DebugOverlay::EndScene(const RenderData &RenderData) +void DebugOverlay::EndScene() { static bool ShowDebugUI = false; if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftAlt)) && diff --git a/ddraw/DebugOverlay.h b/ddraw/DebugOverlay.h index a0f2c34f..f7e948f2 100644 --- a/ddraw/DebugOverlay.h +++ b/ddraw/DebugOverlay.h @@ -48,7 +48,7 @@ class DebugOverlay // Frame functions void BeginScene(); - void EndScene(const class RenderData &RenderData); + void EndScene(); // Functions void SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix); diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index eea98e7d..f445997f 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -19,7 +19,7 @@ #include // Enable for testing only -#define ENABLE_DEBUGOVERLAY +//#define ENABLE_DEBUGOVERLAY #ifdef ENABLE_DEBUGOVERLAY #include "DebugOverlay.h" @@ -339,17 +339,17 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat break; } - if(Config.DdrawConvertHomogeneousW) + if (Config.DdrawConvertHomogeneousW) { #ifdef ENABLE_DEBUGOVERLAY // Set the original matrix DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix); #endif - if(dtstTransformStateType == D3DTS_VIEW) + if (dtstTransformStateType == D3DTS_VIEW) { D3DVIEWPORT9 Viewport9; - if(SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9))) + if (SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9))) { const float width = (float)Viewport9.Width; const float height = (float)Viewport9.Height; @@ -365,15 +365,13 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat view._42 = 1.0f; // translate Y view._44 = 1.0f; - if(!Config.DdrawConvertHomogeneousToWorld) - { - // Override the original matrix - std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); - } - else + // Override the original matrix + std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); + + if (Config.DdrawConvertHomogeneousToWorld) { DirectX::XMVECTOR position, direction; - if(Config.DdrawConvertHomogeneousToWorldUseGameCamera) + if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) { // To reconstruct the 3D world, we need to know where the camera is and where it is looking position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); @@ -384,12 +382,9 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat const float cameradir = 1.0f; position = DirectX::XMVectorSet(0.0f, 0.0f, -cameradir, 0.0f); - DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f); + direction = DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f); } - // Override the original matrix - std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); - // Store the original matrix so it can be restored std::memcpy(&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &view, sizeof(_D3DMATRIX)); @@ -1703,7 +1698,7 @@ HRESULT m_IDirect3DDeviceX::EndScene() } #ifdef ENABLE_DEBUGOVERLAY - DOverlay.EndScene(RenderData); + DOverlay.EndScene(); #endif // The IDirect3DDevice7::EndScene method ends a scene that was begun by calling the IDirect3DDevice7::BeginScene method. @@ -2137,7 +2132,7 @@ HRESULT m_IDirect3DDeviceX::SetRenderState(D3DRENDERSTATETYPE dwRenderStateType, break; } case D3DRS_LIGHTING: - if(Config.DdrawDisableLighting) + if (Config.DdrawDisableLighting) { dwRenderState = FALSE; } @@ -2548,9 +2543,10 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy const UINT stride = GetVertexStride(dwVertexTypeDesc); // Handle PositionT - if((dwVertexTypeDesc & D3DFVF_XYZRHW) != 0 && Config.DdrawConvertHomogeneousW) + if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) { - if(!Config.DdrawConvertHomogeneousToWorld) + D3DFVF_XYZB1; + if (!Config.DdrawConvertHomogeneousToWorld) { /*UINT8 *vertex = (UINT8*)lpVertices; From dbc8e10fc23bbf9875b1eac319b54e9d132f47c7 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Tue, 16 May 2023 18:12:13 -0700 Subject: [PATCH 04/25] Don't override matrix memory, just the pointer --- ddraw/IDirect3DDeviceX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index f445997f..72432c3e 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -339,6 +339,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat break; } + _D3DMATRIX view; if (Config.DdrawConvertHomogeneousW) { #ifdef ENABLE_DEBUGOVERLAY @@ -356,7 +357,6 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat const float ratio = width / height; // Replace the matrix with one that handles D3DFVF_XYZRHW geometry - _D3DMATRIX view; ZeroMemory(&view, sizeof(_D3DMATRIX)); view._11 = 2.0f / width; view._22 = -2.0f / height; @@ -365,8 +365,8 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat view._42 = 1.0f; // translate Y view._44 = 1.0f; - // Override the original matrix - std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX)); + // Override original matrix pointer + lpD3DMatrix = &view; if (Config.DdrawConvertHomogeneousToWorld) { From 14632efcad03be9b2fdcf8487cc626387d7d6d52 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Wed, 17 May 2023 11:04:55 -0700 Subject: [PATCH 05/25] Fix disable lighting and a couple typos --- Settings/AllSettings.ini | 7 +++++++ ddraw/IDirect3DDeviceX.cpp | 16 ++++++++++------ ddraw/RenderData.h | 12 ++++++------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Settings/AllSettings.ini b/Settings/AllSettings.ini index 871f306a..b44ac0e5 100644 --- a/Settings/AllSettings.ini +++ b/Settings/AllSettings.ini @@ -73,6 +73,13 @@ DdrawOverrideRefreshRate = 0 DdrawOverrideStencilFormat = 0 DdrawIntegerScalingClamp = 0 DdrawMaintainAspectRatio = 0 +DdrawConvertHomogeneousW = 0 +DdrawConvertHomogeneousToWorld = 0 +DdrawConvertHomogeneousToWorldUseGameCamera = 0 +DdrawConvertHomogeneousToWorldFOV = 90.0f +DdrawConvertHomogeneousToWorldNearPlane = 1.0f +DdrawConvertHomogeneousToWorldFarPlane = 1000.0f +DdrawConvertHomogeneousToWorldDepthOffset = 0.0f [d3d9] AnisotropicFiltering = 0 diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 72432c3e..5c8e0518 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -339,7 +339,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat break; } - _D3DMATRIX view; + D3DMATRIX view; if (Config.DdrawConvertHomogeneousW) { #ifdef ENABLE_DEBUGOVERLAY @@ -357,7 +357,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat const float ratio = width / height; // Replace the matrix with one that handles D3DFVF_XYZRHW geometry - ZeroMemory(&view, sizeof(_D3DMATRIX)); + ZeroMemory(&view, sizeof(D3DMATRIX)); view._11 = 2.0f / width; view._22 = -2.0f / height; view._33 = 1.0f; @@ -386,7 +386,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat } // Store the original matrix so it can be restored - std::memcpy(&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &view, sizeof(_D3DMATRIX)); + std::memcpy(&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &view, sizeof(D3DMATRIX)); // The Black & White matrix is an ortho camera, so create a perspective one matching the game const float fov = Config.DdrawConvertHomogeneousToWorldFOV; @@ -1665,6 +1665,11 @@ HRESULT m_IDirect3DDeviceX::BeginScene() DOverlay.BeginScene(); #endif + if (Config.DdrawDisableLighting) + { + (*d3d9Device)->SetRenderState(D3DRS_LIGHTING, FALSE); + } + return hr; } @@ -2545,7 +2550,6 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy // Handle PositionT if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) { - D3DFVF_XYZB1; if (!Config.DdrawConvertHomogeneousToWorld) { /*UINT8 *vertex = (UINT8*)lpVertices; @@ -2612,8 +2616,8 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); // Restore transform - _D3DMATRIX identityMatrix; - ZeroMemory(&identityMatrix, sizeof(_D3DMATRIX)); + D3DMATRIX identityMatrix; + ZeroMemory(&identityMatrix, sizeof(D3DMATRIX)); identityMatrix._11 = 1.0f; identityMatrix._22 = 1.0f; identityMatrix._33 = 1.0f; diff --git a/ddraw/RenderData.h b/ddraw/RenderData.h index a758070e..28f91af6 100644 --- a/ddraw/RenderData.h +++ b/ddraw/RenderData.h @@ -9,13 +9,13 @@ class RenderData public: // Store the projection matrix used to transform the geometry on the gpu - _D3DMATRIX DdrawConvertHomogeneousToWorld_ProjectionMatrix; + D3DMATRIX DdrawConvertHomogeneousToWorld_ProjectionMatrix; // Store the view matrix used to transform the geometry on the gpu - _D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrix; + D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrix; // Store the original view matrix, so we can restore it - _D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixOriginal; + D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixOriginal; // Store the inverse view matrix to transform the geometry on the cpu DirectX::XMMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixInverse; @@ -25,13 +25,13 @@ class RenderData RenderData() { - ZeroMemory(&DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX)); + ZeroMemory(&DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(D3DMATRIX)); DdrawConvertHomogeneousToWorld_ViewMatrix._11 = 1.0f; DdrawConvertHomogeneousToWorld_ViewMatrix._22 = 1.0f; DdrawConvertHomogeneousToWorld_ViewMatrix._33 = 1.0f; DdrawConvertHomogeneousToWorld_ViewMatrix._44 = 1.0f; - std::memcpy(&DdrawConvertHomogeneousToWorld_ProjectionMatrix, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX)); - std::memcpy(&DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX)); + std::memcpy(&DdrawConvertHomogeneousToWorld_ProjectionMatrix, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(D3DMATRIX)); + std::memcpy(&DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(D3DMATRIX)); } }; From de8fcbc6f88ba2c9d1b1b34fdc57d3021fb02812 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Wed, 17 May 2023 11:47:17 -0700 Subject: [PATCH 06/25] Set transform if not set by game --- Settings/AllSettings.ini | 1 + ddraw/IDirect3DDeviceX.cpp | 13 +++++++++++++ ddraw/RenderData.h | 3 +++ 3 files changed, 17 insertions(+) diff --git a/Settings/AllSettings.ini b/Settings/AllSettings.ini index b44ac0e5..4a73db67 100644 --- a/Settings/AllSettings.ini +++ b/Settings/AllSettings.ini @@ -73,6 +73,7 @@ DdrawOverrideRefreshRate = 0 DdrawOverrideStencilFormat = 0 DdrawIntegerScalingClamp = 0 DdrawMaintainAspectRatio = 0 +DdrawDisableLighting = 0 DdrawConvertHomogeneousW = 0 DdrawConvertHomogeneousToWorld = 0 DdrawConvertHomogeneousToWorldUseGameCamera = 0 diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 5c8e0518..79c00d36 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -368,6 +368,9 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat // Override original matrix pointer lpD3DMatrix = &view; + // Set flag + RenderData.IsDdrawConvertHomogeneousTransformViewSet = true; + if (Config.DdrawConvertHomogeneousToWorld) { DirectX::XMVECTOR position, direction; @@ -2563,6 +2566,13 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy vertex += stride; }*/ + if (!RenderData.IsDdrawConvertHomogeneousTransformViewSet) + { + D3DMATRIX Matrix = {}; + GetTransform(D3DTS_VIEW, &Matrix); + SetTransform(D3DTS_VIEW, &Matrix); + } + // Update the FVF dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; } @@ -3083,6 +3093,9 @@ HRESULT m_IDirect3DDeviceX::CheckInterface(char *FunctionName, bool CheckD3DDevi void m_IDirect3DDeviceX::ResetDevice() { + // Reset flags + RenderData.IsDdrawConvertHomogeneousTransformViewSet = false; + // Reset textures after device reset for (UINT x = 0; x < 8; x++) { diff --git a/ddraw/RenderData.h b/ddraw/RenderData.h index 28f91af6..b86218b3 100644 --- a/ddraw/RenderData.h +++ b/ddraw/RenderData.h @@ -8,6 +8,9 @@ class RenderData { public: + // Flags + bool IsDdrawConvertHomogeneousTransformViewSet = false; + // Store the projection matrix used to transform the geometry on the gpu D3DMATRIX DdrawConvertHomogeneousToWorld_ProjectionMatrix; From a0ddc3d0352ec41a61f5f4745921b595b89886fd Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Wed, 17 May 2023 13:57:03 -0700 Subject: [PATCH 07/25] Remove RenderData --- ddraw/IDirect3DDeviceX.cpp | 44 +++++++++++++++++++++++--------------- ddraw/IDirect3DDeviceX.h | 16 +++++++++++--- ddraw/RenderData.h | 40 ---------------------------------- dxwrapper.vcxproj | 1 - dxwrapper.vcxproj.filters | 3 --- 5 files changed, 40 insertions(+), 64 deletions(-) delete mode 100644 ddraw/RenderData.h diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 79c00d36..6f4c2caf 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -16,7 +16,6 @@ #include "ddraw.h" #include -#include // Enable for testing only //#define ENABLE_DEBUGOVERLAY @@ -354,7 +353,6 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat { const float width = (float)Viewport9.Width; const float height = (float)Viewport9.Height; - const float ratio = width / height; // Replace the matrix with one that handles D3DFVF_XYZRHW geometry ZeroMemory(&view, sizeof(D3DMATRIX)); @@ -369,7 +367,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat lpD3DMatrix = &view; // Set flag - RenderData.IsDdrawConvertHomogeneousTransformViewSet = true; + ConvertHomogeneous.IsTransformViewSet = true; if (Config.DdrawConvertHomogeneousToWorld) { @@ -389,21 +387,22 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat } // Store the original matrix so it can be restored - std::memcpy(&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &view, sizeof(D3DMATRIX)); + ConvertHomogeneous.ToWorld_ViewMatrixOriginal = view; // The Black & White matrix is an ortho camera, so create a perspective one matching the game const float fov = Config.DdrawConvertHomogeneousToWorldFOV; const float nearplane = Config.DdrawConvertHomogeneousToWorldNearPlane; const float farplane = Config.DdrawConvertHomogeneousToWorldFarPlane; + const float ratio = width / height; DirectX::XMMATRIX proj = DirectX::XMMatrixPerspectiveFovLH(fov * (3.14159265359f / 180.0f), ratio, nearplane, farplane); - DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix, proj); + DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ProjectionMatrix, proj); DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, up); // Store the 3D view matrix so it can be set later - DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix, viewMatrix); + DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ViewMatrix, viewMatrix); // Store the view inverse matrix of the game, so we can transform the geometry with it DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)lpD3DMatrix); @@ -412,7 +411,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, Config.DdrawConvertHomogeneousToWorldDepthOffset); - RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); + ConvertHomogeneous.ToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); } } } @@ -2566,7 +2565,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy vertex += stride; }*/ - if (!RenderData.IsDdrawConvertHomogeneousTransformViewSet) + if (!ConvertHomogeneous.IsTransformViewSet) { D3DMATRIX Matrix = {}; GetTransform(D3DTS_VIEW, &Matrix); @@ -2581,10 +2580,10 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy const UINT targetStride = stride - sizeof(float); const UINT restSize = stride - sizeof(float) * 4; - RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); + ConvertHomogeneous.ToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); UINT8 *sourceVertex = (UINT8*)lpVertices; - UINT8 *targetVertex = (UINT8*)RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.data(); + UINT8 *targetVertex = (UINT8*)ConvertHomogeneous.ToWorld_IntermediateGeometry.data(); lpVertices = targetVertex; @@ -2596,7 +2595,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]); - DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixInverse); + DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, ConvertHomogeneous.ToWorld_ViewMatrixInverse); xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global)); @@ -2613,8 +2612,8 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy } // Set transform - (*d3d9Device)->SetTransform(D3DTS_VIEW, &RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix); - (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix); + (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix); // Update the FVF const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; @@ -2626,13 +2625,12 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); // Restore transform - D3DMATRIX identityMatrix; - ZeroMemory(&identityMatrix, sizeof(D3DMATRIX)); + D3DMATRIX identityMatrix = {}; identityMatrix._11 = 1.0f; identityMatrix._22 = 1.0f; identityMatrix._33 = 1.0f; - (*d3d9Device)->SetTransform(D3DTS_VIEW, &RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal); + (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal); (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); // Handle dwFlags @@ -3032,6 +3030,18 @@ void m_IDirect3DDeviceX::InitDevice(DWORD DirectXVersion) return; } + if (Config.DdrawConvertHomogeneousW) + { + ZeroMemory(&ConvertHomogeneous.ToWorld_ViewMatrix, sizeof(D3DMATRIX)); + ConvertHomogeneous.ToWorld_ViewMatrix._11 = 1.0f; + ConvertHomogeneous.ToWorld_ViewMatrix._22 = 1.0f; + ConvertHomogeneous.ToWorld_ViewMatrix._33 = 1.0f; + ConvertHomogeneous.ToWorld_ViewMatrix._44 = 1.0f; + + ConvertHomogeneous.ToWorld_ProjectionMatrix = ConvertHomogeneous.ToWorld_ViewMatrix; + ConvertHomogeneous.ToWorld_ViewMatrixOriginal = ConvertHomogeneous.ToWorld_ViewMatrix; + } + AddRef(DirectXVersion); } @@ -3094,7 +3104,7 @@ HRESULT m_IDirect3DDeviceX::CheckInterface(char *FunctionName, bool CheckD3DDevi void m_IDirect3DDeviceX::ResetDevice() { // Reset flags - RenderData.IsDdrawConvertHomogeneousTransformViewSet = false; + ConvertHomogeneous.IsTransformViewSet = false; // Reset textures after device reset for (UINT x = 0; x < 8; x++) diff --git a/ddraw/IDirect3DDeviceX.h b/ddraw/IDirect3DDeviceX.h index ed8f73a8..5df4f3ef 100644 --- a/ddraw/IDirect3DDeviceX.h +++ b/ddraw/IDirect3DDeviceX.h @@ -1,7 +1,17 @@ #pragma once #include "IDirectDrawX.h" -#include "RenderData.h" +#include + +struct CONVERTHOMOGENEOUS +{ + bool IsTransformViewSet = false; // Remembers if game sets the view matrix + D3DMATRIX ToWorld_ProjectionMatrix; // Store the projection matrix used to transform the geometry on the gpu + D3DMATRIX ToWorld_ViewMatrix; // Store the view matrix used to transform the geometry on the gpu + D3DMATRIX ToWorld_ViewMatrixOriginal; // Store the original view matrix, so we can restore it + DirectX::XMMATRIX ToWorld_ViewMatrixInverse; // Store the inverse view matrix to transform the geometry on the cpu + std::vector ToWorld_IntermediateGeometry; // Intermediate buffer for the geometry conversion +}; class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject { @@ -28,8 +38,8 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject // SetTexture array LPDIRECTDRAWSURFACE7 AttachedTexture[8] = {}; - // The data used for rendering - RenderData RenderData; + // The data used for rendering Homogeneous + CONVERTHOMOGENEOUS ConvertHomogeneous; // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) diff --git a/ddraw/RenderData.h b/ddraw/RenderData.h deleted file mode 100644 index b86218b3..00000000 --- a/ddraw/RenderData.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include -#include - -class RenderData -{ -public: - - // Flags - bool IsDdrawConvertHomogeneousTransformViewSet = false; - - // Store the projection matrix used to transform the geometry on the gpu - D3DMATRIX DdrawConvertHomogeneousToWorld_ProjectionMatrix; - - // Store the view matrix used to transform the geometry on the gpu - D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrix; - - // Store the original view matrix, so we can restore it - D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixOriginal; - - // Store the inverse view matrix to transform the geometry on the cpu - DirectX::XMMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixInverse; - - // Intermediate buffer for the geometry conversion - std::vector DdrawConvertHomogeneousToWorld_IntermediateGeometry; - - RenderData() - { - ZeroMemory(&DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(D3DMATRIX)); - DdrawConvertHomogeneousToWorld_ViewMatrix._11 = 1.0f; - DdrawConvertHomogeneousToWorld_ViewMatrix._22 = 1.0f; - DdrawConvertHomogeneousToWorld_ViewMatrix._33 = 1.0f; - DdrawConvertHomogeneousToWorld_ViewMatrix._44 = 1.0f; - - std::memcpy(&DdrawConvertHomogeneousToWorld_ProjectionMatrix, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(D3DMATRIX)); - std::memcpy(&DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(D3DMATRIX)); - } -}; diff --git a/dxwrapper.vcxproj b/dxwrapper.vcxproj index 3eac7208..3854925f 100644 --- a/dxwrapper.vcxproj +++ b/dxwrapper.vcxproj @@ -588,7 +588,6 @@ cmd /q /c "cd /D ""$(ProjectDir)d3d8\"" && del build.bat" - diff --git a/dxwrapper.vcxproj.filters b/dxwrapper.vcxproj.filters index 8c18b85b..2e3ec3cd 100644 --- a/dxwrapper.vcxproj.filters +++ b/dxwrapper.vcxproj.filters @@ -1868,9 +1868,6 @@ ddraw - - ddraw - From c715c6185c00f6aade5e071eed47f4c51bab6a86 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Wed, 17 May 2023 14:37:10 -0700 Subject: [PATCH 08/25] Fix default settings --- Settings/AllSettings.ini | 8 ++++---- Settings/Settings.cpp | 4 +++- Settings/Settings.h | 10 +++++----- ddraw/IDirect3DDeviceX.cpp | 14 +++++++------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Settings/AllSettings.ini b/Settings/AllSettings.ini index 4a73db67..d71474fe 100644 --- a/Settings/AllSettings.ini +++ b/Settings/AllSettings.ini @@ -77,10 +77,10 @@ DdrawDisableLighting = 0 DdrawConvertHomogeneousW = 0 DdrawConvertHomogeneousToWorld = 0 DdrawConvertHomogeneousToWorldUseGameCamera = 0 -DdrawConvertHomogeneousToWorldFOV = 90.0f -DdrawConvertHomogeneousToWorldNearPlane = 1.0f -DdrawConvertHomogeneousToWorldFarPlane = 1000.0f -DdrawConvertHomogeneousToWorldDepthOffset = 0.0f +DdrawConvertHomogeneousToWorldFOV = 90.0 +DdrawConvertHomogeneousToWorldNearPlane = 1.0 +DdrawConvertHomogeneousToWorldFarPlane = 1000.0 +DdrawConvertHomogeneousToWorldDepthOffset = 0.0 [d3d9] AnisotropicFiltering = 0 diff --git a/Settings/Settings.cpp b/Settings/Settings.cpp index 1a722a53..f47cea4f 100644 --- a/Settings/Settings.cpp +++ b/Settings/Settings.cpp @@ -449,12 +449,14 @@ void Settings::SetDefaultConfigSettings() Config.FixSpeakerConfigType = true; // Set other default values - Config.LoopSleepTime = 120; Config.WindowSleepTime = 500; Config.PrimaryBufferBits = 16; Config.PrimaryBufferSamples = 44100; Config.PrimaryBufferChannels = 2; Config.AudioFadeOutDelayMS = 20; + Config.DdrawConvertHomogeneousToWorldFOV = 90.0f; + Config.DdrawConvertHomogeneousToWorldNearPlane = 1.0f; + Config.DdrawConvertHomogeneousToWorldFarPlane = 1000.0f; SetValue("ExcludeProcess", "dxwnd.exe", &Config.ExcludeProcess); SetValue("ExcludeProcess", "dgVoodooSetup.exe", &Config.ExcludeProcess); } diff --git a/Settings/Settings.h b/Settings/Settings.h index 8c6001ea..a239aaf2 100644 --- a/Settings/Settings.h +++ b/Settings/Settings.h @@ -218,12 +218,12 @@ struct CONFIG bool DdrawMaintainAspectRatio = false; // Keeps the current DirectDraw aspect ratio when overriding the game's resolution bool DdrawUseDirect3D9Ex = false; // Use Direct3D9Ex extensions for Dd7to9 bool DdrawConvertHomogeneousW = false; // Convert primites using D3DFVF_XYZRHW to D3DFVF_XYZW. - bool DdrawConvertHomogeneousToWorld = false; // Convert primitives back into a world space. Needed for RTX. + bool DdrawConvertHomogeneousToWorld = false; // Convert primitives back into a world space. Needed for RTX. bool DdrawConvertHomogeneousToWorldUseGameCamera = false; // Use the game's view matrix instead of replacing it with our own. - float DdrawConvertHomogeneousToWorldFOV = 90.0f; // The field of view of the camera used to reconstruct the original 3D world. - float DdrawConvertHomogeneousToWorldNearPlane = 1.0f; // The near plane of the camera used to reconstruct the original 3D world. - float DdrawConvertHomogeneousToWorldFarPlane = 1000.0f; // The far plane of the camera used to reconstruct the original 3D world. - float DdrawConvertHomogeneousToWorldDepthOffset = 0.0f; // The offset to add to the geometry so it does not clip into the near plane. + float DdrawConvertHomogeneousToWorldFOV = 0.0f; // The field of view of the camera used to reconstruct the original 3D world. + float DdrawConvertHomogeneousToWorldNearPlane = 0.0f; // The near plane of the camera used to reconstruct the original 3D world. + float DdrawConvertHomogeneousToWorldFarPlane = 0.0f; // The far plane of the camera used to reconstruct the original 3D world. + float DdrawConvertHomogeneousToWorldDepthOffset = 0.0f; // The offset to add to the geometry so it does not clip into the near plane. bool DdrawUseNativeResolution = false; // Uses the current screen resolution for Dd7to9 DWORD DdrawClippedWidth = 0; // Used to scaled Direct3d9 to use this width when using Dd7to9 DWORD DdrawClippedHeight = 0; // Used to scaled Direct3d9 to use this height when using Dd7to9 diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 6f4c2caf..d036643f 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -2552,6 +2552,13 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy // Handle PositionT if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) { + if (!ConvertHomogeneous.IsTransformViewSet) + { + D3DMATRIX Matrix = {}; + GetTransform(D3DTS_VIEW, &Matrix); + SetTransform(D3DTS_VIEW, &Matrix); + } + if (!Config.DdrawConvertHomogeneousToWorld) { /*UINT8 *vertex = (UINT8*)lpVertices; @@ -2565,13 +2572,6 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy vertex += stride; }*/ - if (!ConvertHomogeneous.IsTransformViewSet) - { - D3DMATRIX Matrix = {}; - GetTransform(D3DTS_VIEW, &Matrix); - SetTransform(D3DTS_VIEW, &Matrix); - } - // Update the FVF dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; } From d7dff145fcf252b586ceb84c643595018c7dcf2a Mon Sep 17 00:00:00 2001 From: Daniel Kollmann Date: Thu, 18 May 2023 01:01:46 +0200 Subject: [PATCH 09/25] Fixed that DdrawConvertHomogeneousToWorldUseGameCamera did not actually use the game camera transform. Simplified the opposite case. --- ddraw/IDirect3DDeviceX.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index d036643f..5ea295e6 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -369,7 +369,12 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat // Set flag ConvertHomogeneous.IsTransformViewSet = true; - if (Config.DdrawConvertHomogeneousToWorld) + if (!Config.DdrawConvertHomogeneousToWorld) + { + // Override original matrix pointer + lpD3DMatrix = &view; + } + else { DirectX::XMVECTOR position, direction; if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) @@ -380,12 +385,13 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat } else { - const float cameradir = 1.0f; - - position = DirectX::XMVectorSet(0.0f, 0.0f, -cameradir, 0.0f); - direction = DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f); + position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); + direction = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); } + // Override original matrix pointer + lpD3DMatrix = &view; + // Store the original matrix so it can be restored ConvertHomogeneous.ToWorld_ViewMatrixOriginal = view; From 575bd6f1fd56c820e8e42ca0a426722d25bff46f Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Thu, 18 May 2023 09:10:27 -0700 Subject: [PATCH 10/25] Remove unneeded matrix assignment --- ddraw/IDirect3DDeviceX.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 5ea295e6..f0838206 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -369,12 +369,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat // Set flag ConvertHomogeneous.IsTransformViewSet = true; - if (!Config.DdrawConvertHomogeneousToWorld) - { - // Override original matrix pointer - lpD3DMatrix = &view; - } - else + if (Config.DdrawConvertHomogeneousToWorld) { DirectX::XMVECTOR position, direction; if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) @@ -389,9 +384,6 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat direction = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); } - // Override original matrix pointer - lpD3DMatrix = &view; - // Store the original matrix so it can be restored ConvertHomogeneous.ToWorld_ViewMatrixOriginal = view; From 44d43381e096a1fbff974f593ef68abc4d5c7efd Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Thu, 18 May 2023 09:15:13 -0700 Subject: [PATCH 11/25] Fix DdrawConvertHomogeneousToWorldUseGameCamera --- ddraw/IDirect3DDeviceX.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index f0838206..cc0255a0 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -363,7 +363,8 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat view._42 = 1.0f; // translate Y view._44 = 1.0f; - // Override original matrix pointer + // Backup pointer before overriding original matrix pointer + LPD3DMATRIX lpOriginalD3DMatrix = lpD3DMatrix; lpD3DMatrix = &view; // Set flag @@ -375,8 +376,8 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) { // To reconstruct the 3D world, we need to know where the camera is and where it is looking - position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); - direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34); + position = DirectX::XMVectorSet(lpOriginalD3DMatrix->_41, lpOriginalD3DMatrix->_42, lpOriginalD3DMatrix->_43, lpOriginalD3DMatrix->_44); + direction = DirectX::XMVectorSet(lpOriginalD3DMatrix->_31, lpOriginalD3DMatrix->_32, lpOriginalD3DMatrix->_33, lpOriginalD3DMatrix->_34); } else { From f823ec3dc0235cecfc21e6c3b1d36ad58d3b319b Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Thu, 18 May 2023 10:38:45 -0700 Subject: [PATCH 12/25] Move matrix override code to the end --- ddraw/IDirect3DDeviceX.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index cc0255a0..6d76b9d7 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -363,10 +363,6 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat view._42 = 1.0f; // translate Y view._44 = 1.0f; - // Backup pointer before overriding original matrix pointer - LPD3DMATRIX lpOriginalD3DMatrix = lpD3DMatrix; - lpD3DMatrix = &view; - // Set flag ConvertHomogeneous.IsTransformViewSet = true; @@ -376,8 +372,8 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) { // To reconstruct the 3D world, we need to know where the camera is and where it is looking - position = DirectX::XMVectorSet(lpOriginalD3DMatrix->_41, lpOriginalD3DMatrix->_42, lpOriginalD3DMatrix->_43, lpOriginalD3DMatrix->_44); - direction = DirectX::XMVectorSet(lpOriginalD3DMatrix->_31, lpOriginalD3DMatrix->_32, lpOriginalD3DMatrix->_33, lpOriginalD3DMatrix->_34); + position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); + direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34); } else { @@ -404,7 +400,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ViewMatrix, viewMatrix); // Store the view inverse matrix of the game, so we can transform the geometry with it - DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)lpD3DMatrix); + DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)&view); DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj); DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp); @@ -412,6 +408,9 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat ConvertHomogeneous.ToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); } + + // Override original matrix pointer + lpD3DMatrix = &view; } } else From e79c2049df7415fd6f18e86b5d9d85aad1a26de7 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Tue, 6 Jun 2023 16:59:54 -0700 Subject: [PATCH 13/25] Fix DdrawConvertHomogeneousToWorldUseGameCamera --- ddraw/IDirect3DDeviceX.cpp | 42 +++++++++++++++++++++++++++++++++----- ddraw/IDirect3DDeviceX.h | 2 ++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 6d76b9d7..1bf870fd 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -369,11 +369,43 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat if (Config.DdrawConvertHomogeneousToWorld) { DirectX::XMVECTOR position, direction; + float depthOffset = 0.0f; if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) { // To reconstruct the 3D world, we need to know where the camera is and where it is looking - position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44); - direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34); + position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); + + const float x = lpD3DMatrix->_11; + const float y = lpD3DMatrix->_12; + const float z = lpD3DMatrix->_13; + + float pitch = std::atan2(y, z); + if (pitch < 0.0f && y * z > 0.0f) // check if y and z have the same sign + { + // handle flipping of the pitch. This is not because the camera is looking up. + pitch += DirectX::XM_PI; + } + + float yaw = std::asin(x); + if (yaw < 0.0f) + { + yaw += DirectX::XM_2PI; + } + + // mirror the transform + float pitchneg = -pitch; + + float pitch_cos = std::cos(pitchneg); + float x2 = 0.0f; //std::cos(yaw) * pitch_cos; + float y2 = std::sin(pitchneg); + float z2 = /*std::sin(yaw) **/ pitch_cos; + + direction = DirectX::XMVectorSet(x2, y2, z2, 0.0f); + + depthOffset = Config.DdrawConvertHomogeneousToWorldDepthOffset; + + ConvertHomogeneous.ToWorld_GameCameraYaw = yaw; + ConvertHomogeneous.ToWorld_GameCameraPitch = pitch; } else { @@ -393,8 +425,8 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ProjectionMatrix, proj); - DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); - DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, up); + DirectX::XMVECTOR upVector = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, upVector); // Store the 3D view matrix so it can be set later DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ViewMatrix, viewMatrix); @@ -404,7 +436,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj); DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp); - DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, Config.DdrawConvertHomogeneousToWorldDepthOffset); + DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, depthOffset); ConvertHomogeneous.ToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); } diff --git a/ddraw/IDirect3DDeviceX.h b/ddraw/IDirect3DDeviceX.h index 5df4f3ef..1efc94d8 100644 --- a/ddraw/IDirect3DDeviceX.h +++ b/ddraw/IDirect3DDeviceX.h @@ -11,6 +11,8 @@ struct CONVERTHOMOGENEOUS D3DMATRIX ToWorld_ViewMatrixOriginal; // Store the original view matrix, so we can restore it DirectX::XMMATRIX ToWorld_ViewMatrixInverse; // Store the inverse view matrix to transform the geometry on the cpu std::vector ToWorld_IntermediateGeometry; // Intermediate buffer for the geometry conversion + float ToWorld_GameCameraYaw = 0.0f; + float ToWorld_GameCameraPitch = 0.0f; }; class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject From 1a8607e8ba4deea769b0dae182a7e3ff0c6b8fab Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Mon, 19 Jun 2023 21:36:52 -0700 Subject: [PATCH 14/25] Fix merge conflict with main --- ddraw/IDirect3DDeviceX.cpp | 150 ++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 78 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 0b42f538..c9308f38 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -2779,102 +2779,102 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy return DDERR_GENERIC; } - // Handle PositionT - if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) - { - if (!ConvertHomogeneous.IsTransformViewSet) - { - D3DMATRIX Matrix = {}; - GetTransform(D3DTS_VIEW, &Matrix); - SetTransform(D3DTS_VIEW, &Matrix); - } + const UINT stride = GetVertexStride(dwVertexTypeDesc); - const UINT stride = GetVertexStride(dwVertexTypeDesc); + // Handle PositionT + if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) + { + if (!ConvertHomogeneous.IsTransformViewSet) + { + D3DMATRIX Matrix = {}; + GetTransform(D3DTS_VIEW, &Matrix); + SetTransform(D3DTS_VIEW, &Matrix); + } - if (!Config.DdrawConvertHomogeneousToWorld) - { - /*UINT8 *vertex = (UINT8*)lpVertices; + if (!Config.DdrawConvertHomogeneousToWorld) + { + /*UINT8 *vertex = (UINT8*)lpVertices; - for (UINT x = 0; x < dwVertexCount; x++) - { - float *pos = (float*) vertex; + for (UINT x = 0; x < dwVertexCount; x++) + { + float *pos = (float*) vertex; - pos[3] = 1.0f; + pos[3] = 1.0f; - vertex += stride; - }*/ + vertex += stride; + }*/ - // Update the FVF - dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; - } - else - { - const UINT targetStride = stride - sizeof(float); - const UINT restSize = stride - sizeof(float) * 4; + // Update the FVF + dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; + } + else + { + const UINT targetStride = stride - sizeof(float); + const UINT restSize = stride - sizeof(float) * 4; - ConvertHomogeneous.ToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); + ConvertHomogeneous.ToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); - UINT8 *sourceVertex = (UINT8*)lpVertices; - UINT8 *targetVertex = (UINT8*)ConvertHomogeneous.ToWorld_IntermediateGeometry.data(); + UINT8* sourceVertex = (UINT8*)lpVertices; + UINT8* targetVertex = (UINT8*)ConvertHomogeneous.ToWorld_IntermediateGeometry.data(); - lpVertices = targetVertex; + lpVertices = targetVertex; - for (UINT x = 0; x < dwVertexCount; x++) - { - // Transform the vertices into world space - float *srcpos = (float*) sourceVertex; - float *trgtpos = (float*) targetVertex; + for (UINT x = 0; x < dwVertexCount; x++) + { + // Transform the vertices into world space + float* srcpos = (float*)sourceVertex; + float* trgtpos = (float*)targetVertex; - DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]); + DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]); - DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, ConvertHomogeneous.ToWorld_ViewMatrixInverse); + DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, ConvertHomogeneous.ToWorld_ViewMatrixInverse); - xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global)); + xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global)); - trgtpos[0] = DirectX::XMVectorGetX(xpos_global); - trgtpos[1] = DirectX::XMVectorGetY(xpos_global); - trgtpos[2] = DirectX::XMVectorGetZ(xpos_global); + trgtpos[0] = DirectX::XMVectorGetX(xpos_global); + trgtpos[1] = DirectX::XMVectorGetY(xpos_global); + trgtpos[2] = DirectX::XMVectorGetZ(xpos_global); - // Copy the rest - std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize); + // Copy the rest + std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize); - // Move to next vertex - sourceVertex += stride; - targetVertex += targetStride; - } + // Move to next vertex + sourceVertex += stride; + targetVertex += targetStride; + } - // Handle dwFlags - DWORD rsClipping = 0, rsLighting = 0, rsExtents = 0; - SetDrawFlags(rsClipping, rsLighting, rsExtents, dwVertexTypeDesc, dwFlags, DirectXVersion); + // Handle dwFlags + DWORD rsClipping = 0, rsLighting = 0, rsExtents = 0; + SetDrawFlags(rsClipping, rsLighting, rsExtents, dwVertexTypeDesc, dwFlags, DirectXVersion); - // Set transform - (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); - (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix); + // Set transform + (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix); - // Update the FVF - const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; + // Update the FVF + const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; - // Set fixed function vertex type - (*d3d9Device)->SetFVF(newVertexTypeDesc); + // Set fixed function vertex type + (*d3d9Device)->SetFVF(newVertexTypeDesc); - // Draw indexed primitive UP - hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); + // Draw indexed primitive UP + HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); - // Restore transform - D3DMATRIX identityMatrix = {}; - identityMatrix._11 = 1.0f; - identityMatrix._22 = 1.0f; - identityMatrix._33 = 1.0f; + // Restore transform + D3DMATRIX identityMatrix = {}; + identityMatrix._11 = 1.0f; + identityMatrix._22 = 1.0f; + identityMatrix._33 = 1.0f; - (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal); - (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); + (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); - // Handle dwFlags - UnSetDrawFlags(rsClipping, rsLighting, rsExtents, newVertexTypeDesc, dwFlags, DirectXVersion); + // Handle dwFlags + UnSetDrawFlags(rsClipping, rsLighting, rsExtents, newVertexTypeDesc, dwFlags, DirectXVersion); - return hr; - } - } + return hr; + } + } // Update vertices for Direct3D9 (needs to be first) UpdateVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); @@ -2896,13 +2896,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy // Handle dwFlags UnSetDrawFlags(rsClipping, rsLighting, rsExtents, dwVertexTypeDesc, dwFlags, DirectXVersion); - // Set fixed function vertex type - (*d3d9Device)->SetFVF(dwVertexTypeDesc); - - // Draw indexed primitive UP - hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, stride); - - if (FAILED(hr)) + if (FAILED(hr)) { LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawIndexedPrimitiveUP' call failed: " << (D3DERR)hr); } From f82ae80ef034a5dd10646500deef534c93ee095e Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Tue, 20 Jun 2023 09:07:30 -0700 Subject: [PATCH 15/25] Minor update --- ddraw/IDirect3DDeviceX.cpp | 4 ++-- ddraw/IDirect3DDeviceX.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index c9308f38..dbedc6dd 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -2779,8 +2779,6 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy return DDERR_GENERIC; } - const UINT stride = GetVertexStride(dwVertexTypeDesc); - // Handle PositionT if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) { @@ -2809,6 +2807,8 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy } else { + const UINT stride = GetVertexStride(dwVertexTypeDesc); + const UINT targetStride = stride - sizeof(float); const UINT restSize = stride - sizeof(float) * 4; diff --git a/ddraw/IDirect3DDeviceX.h b/ddraw/IDirect3DDeviceX.h index 451e897b..035e526b 100644 --- a/ddraw/IDirect3DDeviceX.h +++ b/ddraw/IDirect3DDeviceX.h @@ -47,6 +47,9 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject // Vector temporary buffer cache std::vector VertexCache; + // The data used for rendering Homogeneous + CONVERTHOMOGENEOUS ConvertHomogeneous; + // Viewport array std::vector AttachedViewports; @@ -75,9 +78,6 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject return false; } - // The data used for rendering Homogeneous - CONVERTHOMOGENEOUS ConvertHomogeneous; - // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { From fac874bdaa3d9622e987d626a0ee70ea4d0aafc6 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Mon, 26 Jun 2023 14:29:38 -0700 Subject: [PATCH 16/25] Fix formatting --- ddraw/IDirect3DDeviceX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 48ef672c..53aa16c0 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -3474,7 +3474,7 @@ void m_IDirect3DDeviceX::InitDevice(DWORD DirectXVersion) return; } - if (ddrawParent) + if (ddrawParent) { d3d9Device = ddrawParent->GetDirect3D9Device(); } @@ -3500,9 +3500,9 @@ void m_IDirect3DDeviceX::InitDevice(DWORD DirectXVersion) ConvertHomogeneous.ToWorld_ProjectionMatrix = ConvertHomogeneous.ToWorld_ViewMatrix; ConvertHomogeneous.ToWorld_ViewMatrixOriginal = ConvertHomogeneous.ToWorld_ViewMatrix; - } + } - AddRef(DirectXVersion); + AddRef(DirectXVersion); } void m_IDirect3DDeviceX::ReleaseDevice() From 8b54596f1c94eb4f9c4fca9ae692db7b8934a294 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Mon, 26 Jun 2023 14:31:45 -0700 Subject: [PATCH 17/25] Fix defaults --- Settings/Settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Settings/Settings.cpp b/Settings/Settings.cpp index 85f4d9e1..218c7821 100644 --- a/Settings/Settings.cpp +++ b/Settings/Settings.cpp @@ -450,6 +450,7 @@ void Settings::SetDefaultConfigSettings() Config.DdrawEnableMouseHook = true; // Set other default values + Config.LoopSleepTime = 120; Config.WindowSleepTime = 500; Config.PrimaryBufferBits = 16; Config.PrimaryBufferSamples = 44100; From 3ee34d494440b11b8d11c02908e4e097dabe68fe Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Thu, 13 Jul 2023 11:49:35 -0700 Subject: [PATCH 18/25] Fix PR to work with master branch changes --- ddraw/IDirect3DDeviceX.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 4a017675..10d0298b 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -2819,9 +2819,11 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy targetVertex += targetStride; } + // Check for color key + UpdateDrawFlags(dwFlags); + // Handle dwFlags - DWORD rsClipping = 0, rsLighting = 0, rsExtents = 0; - SetDrawFlags(rsClipping, rsLighting, rsExtents, dwVertexTypeDesc, dwFlags, DirectXVersion); + SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); // Set transform (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); @@ -2846,7 +2848,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); // Handle dwFlags - UnSetDrawFlags(rsClipping, rsLighting, rsExtents, newVertexTypeDesc, dwFlags, DirectXVersion); + RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); return hr; } From 0d9bb503cabadf603258052f1098885657be3208 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Thu, 13 Jul 2023 13:03:29 -0700 Subject: [PATCH 19/25] Update to make it match master branch --- ddraw/IDirect3DDeviceX.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 10d0298b..224ab5f0 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -2819,12 +2819,6 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy targetVertex += targetStride; } - // Check for color key - UpdateDrawFlags(dwFlags); - - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - // Set transform (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix); @@ -2833,11 +2827,24 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; // Set fixed function vertex type - (*d3d9Device)->SetFVF(newVertexTypeDesc); + if (FAILED((*d3d9Device)->SetFVF(newVertexTypeDesc))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); + return D3DERR_INVALIDVERTEXTYPE; + } + + // Check for color key + UpdateDrawFlags(dwFlags); + + // Handle dwFlags + SetDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); // Draw indexed primitive UP HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); + // Handle dwFlags + RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); + // Restore transform D3DMATRIX identityMatrix = {}; identityMatrix._11 = 1.0f; @@ -2847,9 +2854,6 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal); (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); - // Handle dwFlags - RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); - return hr; } } From 80dfe72ccee300d1cc270c117c351becd0c775b6 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Fri, 1 Mar 2024 17:04:37 -0800 Subject: [PATCH 20/25] Include DirectXMath --- .gitmodules | 3 +++ External/DirectXMath | 1 + Stub/BuildNo.rc | 2 +- ddraw/IDirect3DDeviceX.h | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) create mode 160000 External/DirectXMath diff --git a/.gitmodules b/.gitmodules index 7900f2e0..3417c839 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,3 +20,6 @@ [submodule "External/imgui"] path = External/imgui url = https://github.com/ocornut/imgui +[submodule "External/DirectXMath"] + path = External/DirectXMath + url = https://github.com/microsoft/DirectXMath diff --git a/External/DirectXMath b/External/DirectXMath new file mode 160000 index 00000000..d8375782 --- /dev/null +++ b/External/DirectXMath @@ -0,0 +1 @@ +Subproject commit d837578297c6c93849573858182350ede04987dc diff --git a/Stub/BuildNo.rc b/Stub/BuildNo.rc index 1a86af37..30a3d131 100644 --- a/Stub/BuildNo.rc +++ b/Stub/BuildNo.rc @@ -1 +1 @@ -#define BUILD_NUMBER 235 +#define BUILD_NUMBER 236 diff --git a/ddraw/IDirect3DDeviceX.h b/ddraw/IDirect3DDeviceX.h index 072f410d..22130886 100644 --- a/ddraw/IDirect3DDeviceX.h +++ b/ddraw/IDirect3DDeviceX.h @@ -1,7 +1,7 @@ #pragma once #include "IDirectDrawX.h" -#include +#include "External\DirectXMath\Inc\DirectXMath.h" struct CONVERTHOMOGENEOUS { From 1ff2bc05d4a69160623fe5f49a30b3d806cead83 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Tue, 4 Mar 2025 06:45:16 -0800 Subject: [PATCH 21/25] Fix issue with merging master branch --- ddraw/IDirect3DDeviceX.cpp | 2 +- dxwrapper.vcxproj.filters | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 45e37ded..0fde5ec6 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -1192,7 +1192,7 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat } } - HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix); + HRESULT hr = SetD9Transform(dtstTransformStateType, lpD3DMatrix); #ifdef ENABLE_DEBUGOVERLAY if (SUCCEEDED(hr) && !Config.DdrawConvertHomogeneousW) diff --git a/dxwrapper.vcxproj.filters b/dxwrapper.vcxproj.filters index 2569724f..c4cd2826 100644 --- a/dxwrapper.vcxproj.filters +++ b/dxwrapper.vcxproj.filters @@ -1,4 +1,4 @@ - + From 6fe14d612d4d649eaf1d1083789ef5f7593da7dd Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Mon, 31 Mar 2025 14:54:39 -0700 Subject: [PATCH 22/25] Merge remote-tracking branch 'origin/master' into pr/199 --- DirectShow/IAMMediaStream.cpp | 2 +- DirectShow/License.txt | 2 +- Dllmain/BuildNo.rc | 2 +- Dllmain/Dllmain.cpp | 19 +- Dllmain/License.txt | 2 +- Dllmain/dxwrapper.h | 2 +- GDI/Comdlg32.cpp | 2 +- GDI/Gdi32.cpp | 6 +- GDI/License.txt | 2 +- GDI/User32.cpp | 8 +- GDI/WndProc.cpp | 5 +- IClassFactory/IClassFactory.cpp | 35 +- IClassFactory/License.txt | 2 +- Libraries/ComPtr.h | 109 + Libraries/License.txt | 2 +- Libraries/ScopeGuard.h | 29 + Libraries/d3dx9.cpp | 81 +- Libraries/d3dx9.h | 192 +- Libraries/dwmapi.cpp | 2 +- Libraries/uxtheme.cpp | 2 +- Libraries/winmm.cpp | 19 +- Libraries/winmm.h | 1 + License.txt | 2 +- Logging/License.txt | 2 +- Logging/Logging.cpp | 5 +- MakeShader/MakeShader.cpp | 2 +- MakeShader/MakeShader.vcxproj | 1 + MakeShader/MakeShader.vcxproj.filters | 3 + README.md | 2 +- Settings/AllSettings.ini | 9 +- Settings/License.txt | 2 +- Settings/ReadParse.cpp | 2 +- Settings/Settings.cpp | 14 +- Settings/Settings.h | 18 +- Settings/Settings.ini | 7 +- Stub/License.txt | 2 +- Stub/Logging/License.txt | 2 +- Stub/Stub.cpp | 2 +- Stub/d3d8.cpp | 2 +- Stub/ddraw.cpp | 2 +- Stub/dinput.cpp | 2 +- Stub/stub.h | 2 +- Utils/CPUAffinity.cpp | 124 + Utils/Disasm.cpp | 9 +- Utils/Fullscreen.cpp | 11 +- Utils/License.txt | 2 +- Utils/MyStrings.cpp | 2 +- Utils/Utils.cpp | 134 +- Utils/Utils.h | 12 +- Utils/WriteMemory.cpp | 7 +- Wrappers/License.txt | 2 +- Wrappers/wrapper.cpp | 2 +- d3d8/License.txt | 2 +- d3d8/d3d8.cpp | 2 +- d3d9/DebugOverlay.cpp | 4 +- d3d9/IDirect3D9Ex.cpp | 74 +- d3d9/IDirect3DCubeTexture9.cpp | 2 +- d3d9/IDirect3DDevice9Ex.cpp | 561 +- d3d9/IDirect3DDevice9Ex.h | 34 +- d3d9/IDirect3DIndexBuffer9.cpp | 2 +- d3d9/IDirect3DPixelShader9.cpp | 2 +- d3d9/IDirect3DQuery9.cpp | 2 +- d3d9/IDirect3DStateBlock9.cpp | 2 +- d3d9/IDirect3DSurface9.cpp | 2 +- d3d9/IDirect3DSwapChain9Ex.cpp | 2 +- d3d9/IDirect3DTexture9.cpp | 2 +- d3d9/IDirect3DVertexBuffer9.cpp | 2 +- d3d9/IDirect3DVertexDeclaration9.cpp | 2 +- d3d9/IDirect3DVertexShader9.cpp | 2 +- d3d9/IDirect3DVolume9.cpp | 2 +- d3d9/IDirect3DVolumeTexture9.cpp | 2 +- d3d9/InterfaceQuery.cpp | 22 +- d3d9/License.txt | 2 +- d3d9/d3d9.cpp | 3 +- d3d9/d3d9.h | 7 +- d3d9/d3d9External.h | 4 + d3dddi/License.txt | 2 +- ddraw-testing/IDirectDrawSurface.cpp | 57 +- ddraw-testing/resource.h | 2 +- ddraw-testing/testing-harness.h | 2 + ddraw/AddressLookupTable.h | 29 +- ddraw/IDirect3DDeviceX.cpp | 6911 ++++++++--------- ddraw/IDirect3DDeviceX.h | 164 +- ddraw/IDirect3DExecuteBuffer.cpp | 290 +- ddraw/IDirect3DExecuteBuffer.h | 5 +- ddraw/IDirect3DLight.cpp | 170 +- ddraw/IDirect3DLight.h | 6 +- ddraw/IDirect3DMaterialX.cpp | 171 +- ddraw/IDirect3DMaterialX.h | 17 +- ddraw/IDirect3DTextureX.cpp | 157 +- ddraw/IDirect3DTextureX.h | 24 +- ddraw/IDirect3DTypes.cpp | 2 +- ddraw/IDirect3DTypes.h | 14 + ddraw/IDirect3DVertexBufferX.cpp | 95 +- ddraw/IDirect3DVertexBufferX.h | 30 +- ddraw/IDirect3DViewportX.cpp | 369 +- ddraw/IDirect3DViewportX.h | 47 +- ddraw/IDirect3DX.cpp | 976 +-- ddraw/IDirect3DX.h | 30 +- ddraw/IDirectDrawClipper.cpp | 114 +- ddraw/IDirectDrawClipper.h | 11 +- ddraw/IDirectDrawColorControl.cpp | 110 +- ddraw/IDirectDrawColorControl.h | 6 +- ddraw/IDirectDrawFactory.cpp | 39 +- ddraw/IDirectDrawFactory.h | 2 +- ddraw/IDirectDrawGammaControl.cpp | 104 +- ddraw/IDirectDrawGammaControl.h | 5 +- ddraw/IDirectDrawPalette.cpp | 112 +- ddraw/IDirectDrawPalette.h | 21 +- ddraw/IDirectDrawSurfaceX.cpp | 1734 ++--- ddraw/IDirectDrawSurfaceX.h | 211 +- ddraw/IDirectDrawTypes.cpp | 71 +- ddraw/IDirectDrawTypes.h | 49 +- ddraw/IDirectDrawX.cpp | 1472 ++-- ddraw/IDirectDrawX.h | 92 +- ddraw/InterfaceQuery.cpp | 58 +- ddraw/License.txt | 2 +- ddraw/Versions/IDirect3D.cpp | 2 +- ddraw/Versions/IDirect3D2.cpp | 2 +- ddraw/Versions/IDirect3D3.cpp | 2 +- ddraw/Versions/IDirect3D7.cpp | 2 +- ddraw/Versions/IDirect3DDevice.cpp | 4 +- ddraw/Versions/IDirect3DDevice2.cpp | 4 +- ddraw/Versions/IDirect3DDevice3.cpp | 4 +- ddraw/Versions/IDirect3DDevice7.cpp | 2 +- ddraw/Versions/IDirect3DMaterial.cpp | 2 +- ddraw/Versions/IDirect3DMaterial2.cpp | 2 +- ddraw/Versions/IDirect3DMaterial3.cpp | 2 +- ddraw/Versions/IDirect3DTexture.cpp | 2 +- ddraw/Versions/IDirect3DTexture2.cpp | 2 +- ddraw/Versions/IDirect3DVertexBuffer.cpp | 2 +- ddraw/Versions/IDirect3DVertexBuffer7.cpp | 2 +- ddraw/Versions/IDirect3DViewport.cpp | 2 +- ddraw/Versions/IDirect3DViewport2.cpp | 2 +- ddraw/Versions/IDirect3DViewport3.cpp | 2 +- ddraw/Versions/IDirectDraw.cpp | 2 +- ddraw/Versions/IDirectDraw2.cpp | 2 +- ddraw/Versions/IDirectDraw3.cpp | 2 +- ddraw/Versions/IDirectDraw4.cpp | 2 +- ddraw/Versions/IDirectDraw7.cpp | 2 +- ddraw/Versions/IDirectDrawSurface.cpp | 2 +- ddraw/Versions/IDirectDrawSurface2.cpp | 2 +- ddraw/Versions/IDirectDrawSurface3.cpp | 2 +- ddraw/Versions/IDirectDrawSurface4.cpp | 2 +- ddraw/Versions/IDirectDrawSurface7.cpp | 2 +- ddraw/Versions/License.txt | 2 +- ddraw/ddraw.cpp | 560 +- ddraw/ddraw.h | 38 +- ddraw/ddrawExternal.h | 6 - dinput/License.txt | 2 +- dinput/dinput.cpp | 2 +- dinput8/IDirectInput8.cpp | 2 +- dinput8/IDirectInputDevice8.cpp | 2 +- dinput8/IDirectInputEffect8.cpp | 2 +- dinput8/InterfaceQuery.cpp | 2 +- dinput8/License.txt | 2 +- dinput8/dinput8.cpp | 2 +- dsound/IDirectSound3DBuffer8.cpp | 2 +- dsound/IDirectSound3DListener8.cpp | 2 +- dsound/IDirectSound8.cpp | 2 +- dsound/IDirectSoundBuffer8.cpp | 2 +- dsound/IDirectSoundCapture8.cpp | 2 +- dsound/IDirectSoundCaptureBuffer8.cpp | 2 +- dsound/IDirectSoundCaptureFXAec8.cpp | 2 +- .../IDirectSoundCaptureFXNoiseSuppress8.cpp | 2 +- dsound/IDirectSoundFXChorus8.cpp | 2 +- dsound/IDirectSoundFXCompressor8.cpp | 2 +- dsound/IDirectSoundFXDistortion8.cpp | 2 +- dsound/IDirectSoundFXEcho8.cpp | 2 +- dsound/IDirectSoundFXFlanger8.cpp | 2 +- dsound/IDirectSoundFXGargle8.cpp | 2 +- dsound/IDirectSoundFXI3DL2Reverb8.cpp | 2 +- dsound/IDirectSoundFXParamEq8.cpp | 2 +- dsound/IDirectSoundFXWavesReverb8.cpp | 2 +- dsound/IDirectSoundFullDuplex8.cpp | 2 +- dsound/IDirectSoundNotify8.cpp | 2 +- dsound/IKsPropertySet.cpp | 2 +- dsound/InterfaceQuery.cpp | 2 +- dsound/License.txt | 2 +- dsound/dsound.cpp | 2 +- dxwrapper.vcxproj | 3 + dxwrapper.vcxproj.filters | 9 + 182 files changed, 8531 insertions(+), 7649 deletions(-) create mode 100644 Libraries/ComPtr.h create mode 100644 Libraries/ScopeGuard.h create mode 100644 Utils/CPUAffinity.cpp diff --git a/DirectShow/IAMMediaStream.cpp b/DirectShow/IAMMediaStream.cpp index 8f05a178..f6332d7b 100644 --- a/DirectShow/IAMMediaStream.cpp +++ b/DirectShow/IAMMediaStream.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/DirectShow/License.txt b/DirectShow/License.txt index 53f73bd0..9cdb9d78 100644 --- a/DirectShow/License.txt +++ b/DirectShow/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Dllmain/BuildNo.rc b/Dllmain/BuildNo.rc index f3bb3a9a..a58d2333 100644 --- a/Dllmain/BuildNo.rc +++ b/Dllmain/BuildNo.rc @@ -1 +1 @@ -#define BUILD_NUMBER 7528 +#define BUILD_NUMBER 7606 diff --git a/Dllmain/Dllmain.cpp b/Dllmain/Dllmain.cpp index 8d586b8c..6677525f 100644 --- a/Dllmain/Dllmain.cpp +++ b/Dllmain/Dllmain.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -326,7 +326,12 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) } if (Config.SingleProcAffinity) { - Utils::SetProcessAffinity(); + if (!Utils::CreateThread_out) + { + Utils::CreateThread_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "CreateThread"), "CreateThread", Utils::kernel_CreateThread); + } + + Utils::ApplyThreadAffinity(); } if (Config.DisableGameUX) { @@ -578,6 +583,9 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) // Prepare wrapper VISIT_PROCS_D3D9(SHIM_WRAPPED_PROC); + + // Get default display resolution + Utils::GetScreenSize(nullptr, InitWidth, InitHeight); } // Load custom dlls @@ -645,6 +653,13 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) } break; case DLL_THREAD_ATTACH: + + // Apply affinity to new threads + if (Config.SingleProcAffinity) + { + Utils::SetThreadAffinity(GetCurrentThreadId()); + } + #ifdef DDRAWCOMPAT // Unload and Unhook DDrawCompat if (DDrawCompat::IsEnabled()) diff --git a/Dllmain/License.txt b/Dllmain/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Dllmain/License.txt +++ b/Dllmain/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Dllmain/dxwrapper.h b/Dllmain/dxwrapper.h index 022e61cf..e5c3aa0a 100644 --- a/Dllmain/dxwrapper.h +++ b/Dllmain/dxwrapper.h @@ -8,7 +8,7 @@ #define APP_NAME "DirectX Dynamic Link Library" #define APP_COMPANYNAME "Sadrate Presents" #define APP_DESCRPTION "Wraps or hooks DirectX files to fix compatibility issues in older games. Also allows code to be executed from inside the application." -#define APP_COPYRIGHT "Copyright (C) 2024 Elisha Riedlinger" +#define APP_COPYRIGHT "Copyright (C) 2025 Elisha Riedlinger" #define APP_ORIGINALVERSION "dxwrapper.dll" #define APP_INTERNALNAME "DxWrapper" diff --git a/GDI/Comdlg32.cpp b/GDI/Comdlg32.cpp index 87f34b62..39cc92b1 100644 --- a/GDI/Comdlg32.cpp +++ b/GDI/Comdlg32.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/GDI/Gdi32.cpp b/GDI/Gdi32.cpp index 18d8c548..979ca76e 100644 --- a/GDI/Gdi32.cpp +++ b/GDI/Gdi32.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,7 +16,7 @@ #define WIN32_LEAN_AND_MEAN #include -#include "ddraw\ddrawExternal.h" +#include "ddraw\ddraw.h" #include "GDI.h" #include "Settings\Settings.h" #include "Logging\Logging.h" @@ -36,7 +36,7 @@ int WINAPI gdi_GetDeviceCaps(HDC hdc, int index) if (index == BITSPIXEL) { - switch (GetDDrawBitsPixel(WindowFromDC(hdc))) + switch (m_IDirectDrawX::GetDDrawBitsPixel(WindowFromDC(hdc))) { case 8: return 8; diff --git a/GDI/License.txt b/GDI/License.txt index 53f73bd0..9cdb9d78 100644 --- a/GDI/License.txt +++ b/GDI/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/GDI/User32.cpp b/GDI/User32.cpp index e569e793..53f23648 100644 --- a/GDI/User32.cpp +++ b/GDI/User32.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -19,7 +19,7 @@ #include "GDI.h" #include "GDI\WndProc.h" #include "Utils\Utils.h" -#include "ddraw\ddrawExternal.h" +#include "ddraw\ddraw.h" #include "d3d9\d3d9External.h" #include "Settings\Settings.h" #include "Logging\Logging.h" @@ -125,7 +125,7 @@ int WINAPI user_GetSystemMetrics(int nIndex) { case SM_CXSCREEN: { - int Width = GetDDrawWidth(); + int Width = m_IDirectDrawX::GetDDrawWidth(); if (Width) { return Width; @@ -134,7 +134,7 @@ int WINAPI user_GetSystemMetrics(int nIndex) } case SM_CYSCREEN: { - int Height = GetDDrawHeight(); + int Height = m_IDirectDrawX::GetDDrawHeight(); if (Height) { return Height; diff --git a/GDI/WndProc.cpp b/GDI/WndProc.cpp index cbf6c090..c0dd0a02 100644 --- a/GDI/WndProc.cpp +++ b/GDI/WndProc.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -20,7 +20,6 @@ #include "WndProc.h" #include "GDI.h" #include "ddraw\ddraw.h" -#include "ddraw\ddrawExternal.h" #include "d3d9\d3d9External.h" #include "Settings\Settings.h" #include "Logging\Logging.h" @@ -289,7 +288,7 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa // Handle Direct3D9 device creation if (Msg == WM_APP_CREATE_D3D9_DEVICE && WM_MAKE_KEY(hWnd, wParam) == lParam) { - if (CheckDirectDrawXInterface((void*)wParam)) + if (m_IDirectDrawX::CheckDirectDrawXInterface((void*)wParam)) { ((m_IDirectDrawX*)wParam)->CreateD9Device(__FUNCTION__); } diff --git a/IClassFactory/IClassFactory.cpp b/IClassFactory/IClassFactory.cpp index 27567a3a..46ba6a6c 100644 --- a/IClassFactory/IClassFactory.cpp +++ b/IClassFactory/IClassFactory.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -31,13 +31,6 @@ INITIALIZE_OUT_WRAPPED_PROC(CoCreateInstance, unused); -#ifdef DDRAW -namespace DdrawWrapper -{ - REFIID ConvertREFIID(REFIID riid); -} -#endif - #ifdef DINPUT8 namespace dinputto8 { @@ -47,25 +40,11 @@ namespace dinputto8 REFIID ConvertAllREFIID(REFIID riid) { -#ifdef DINPUT8 -#ifdef DDRAW - if (Config.Dinputto8) - { - return DdrawWrapper::ConvertREFIID(dinputto8::ConvertREFIID(riid)); - } -#endif -#endif #ifdef DINPUT8 if (Config.Dinputto8) { return dinputto8::ConvertREFIID(riid); } -#endif -#ifdef DDRAW - if (Config.Dd7to9) - { - return DdrawWrapper::ConvertREFIID(riid); - } #endif return riid; } @@ -272,11 +251,19 @@ HRESULT WINAPI CoCreateInstanceHandle(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWOR } IDirectDraw *pDirectDraw = nullptr; - HRESULT hr = ((DirectDrawCreateProc)ddraw::DirectDrawCreate_var)(nullptr, &pDirectDraw, pUnkOuter); + HRESULT hr; + if (riid == IID_IDirectDraw7) + { + hr = ((DirectDrawCreateExProc)ddraw::DirectDrawCreateEx_var)(nullptr, (LPVOID*)&pDirectDraw, riid, pUnkOuter); + } + else + { + hr = ((DirectDrawCreateProc)ddraw::DirectDrawCreate_var)(nullptr, &pDirectDraw, pUnkOuter); + } if (SUCCEEDED(hr) && pDirectDraw) { - if (riid == IID_IUnknown || riid == IID_IDirectDraw) + if (riid == IID_IUnknown || riid == IID_IDirectDraw || riid == IID_IDirectDraw7) { *ppv = pDirectDraw; } diff --git a/IClassFactory/License.txt b/IClassFactory/License.txt index 53f73bd0..9cdb9d78 100644 --- a/IClassFactory/License.txt +++ b/IClassFactory/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Libraries/ComPtr.h b/Libraries/ComPtr.h new file mode 100644 index 00000000..ae83e6af --- /dev/null +++ b/Libraries/ComPtr.h @@ -0,0 +1,109 @@ +#pragma once + +template +class ComPtr +{ +private: + T* ptr = nullptr; + +public: + // Default constructor + ComPtr() = default; + + // Constructor from raw pointer + ComPtr(T* rawPtr) : ptr(rawPtr) {} + + // Destructor - releases the interface + ~ComPtr() + { + if (ptr) + { + ptr->Release(); + } + } + + // Copy constructor (deleted to avoid accidental AddRef) + ComPtr(const ComPtr&) = delete; + ComPtr& operator=(const ComPtr&) = delete; + + // Move constructor + ComPtr(ComPtr&& other) noexcept + { + ptr = other.ptr; + other.ptr = nullptr; + } + + // Move assignment + ComPtr& operator=(ComPtr&& other) noexcept + { + if (this != &other) + { + Reset(); + ptr = other.ptr; + other.ptr = nullptr; + } + return *this; + } + + // Get raw pointer + T* Get() const + { + return ptr; + } + + // Release ownership and return raw pointer + T* Detach() + { + T* temp = ptr; + ptr = nullptr; + return temp; + } + + // Release current pointer + void Reset() + { + if (ptr) + { + ptr->Release(); + ptr = nullptr; + } + } + + // Assign a new pointer + void Attach(T* rawPtr) + { + Reset(); + ptr = rawPtr; + } + + // Overload -> operator + T* operator->() const + { + return ptr; + } + + // Overload * operator + T& operator*() const + { + return *ptr; + } + + // Get address of pointer for functions like GetAddressOf() + T** GetAddressOf() + { + return &ptr; + } + + // Get address of pointer for functions like ReleaseAndGetAddressOf() + T** ReleaseAndGetAddressOf() + { + Reset(); + return &ptr; + } + + // Implicit conversion to bool (to check if the pointer is valid) + operator bool() const + { + return ptr != nullptr; + } +}; diff --git a/Libraries/License.txt b/Libraries/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Libraries/License.txt +++ b/Libraries/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Libraries/ScopeGuard.h b/Libraries/ScopeGuard.h new file mode 100644 index 00000000..a6285e35 --- /dev/null +++ b/Libraries/ScopeGuard.h @@ -0,0 +1,29 @@ +#pragma once + +struct ScopedFlagSet { + bool& flag; + + // Constructor sets the flag to true + ScopedFlagSet(bool& setflag) : flag(setflag) { + flag = true; + } + + // Destructor sets the flag back to false + ~ScopedFlagSet() { + flag = false; + } +}; + +struct ScopedCriticalSection { + CRITICAL_SECTION* cs; + + // Constructor enters critical section + ScopedCriticalSection(CRITICAL_SECTION* cs) : cs(cs) { + EnterCriticalSection(cs); + } + + // Destructor leaves critical section + ~ScopedCriticalSection() { + LeaveCriticalSection(cs); + } +}; diff --git a/Libraries/d3dx9.cpp b/Libraries/d3dx9.cpp index b3f0f367..34b82ec2 100644 --- a/Libraries/d3dx9.cpp +++ b/Libraries/d3dx9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -45,6 +45,11 @@ typedef HRESULT(WINAPI* PFN_D3DDisassemble)(LPCVOID pSrcData, SIZE_T SrcDataSize typedef HRESULT(WINAPI* PFN_D3DXFillTexture)(LPVOID pTexture, LPD3DXFILL3D pFunction, LPVOID pData); +typedef HRESULT(WINAPI* PFN_D3DXCreateFontA)(LPDIRECT3DDEVICE9 pDevice, INT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCSTR pFaceName, LPD3DXFONT* ppFont); +typedef HRESULT(WINAPI* PFN_D3DXCreateFontW)(LPDIRECT3DDEVICE9 pDevice, INT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCWSTR pFaceName, LPD3DXFONT* ppFont); + +typedef HRESULT(WINAPI* PFN_D3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); + HMEMORYMODULE d3dx9Module = nullptr; HMEMORYMODULE d3dCompileModule = nullptr; @@ -67,6 +72,11 @@ PFN_D3DDisassemble p_D3DDisassemble = nullptr; PFN_D3DXFillTexture p_D3DXFillTexture = nullptr; +PFN_D3DXCreateFontA p_D3DXCreateFontA = nullptr; +PFN_D3DXCreateFontW p_D3DXCreateFontW = nullptr; + +PFN_D3DXCreateSprite p_D3DXCreateSprite = nullptr; + FARPROC f_D3DXAssembleShader = (FARPROC)*D3DXAssembleShader; FARPROC f_D3DXDisassembleShader = (FARPROC)*D3DXDisassembleShader; FARPROC f_D3DXLoadSurfaceFromSurface = (FARPROC)*D3DXLoadSurfaceFromSurface; @@ -102,6 +112,9 @@ void LoadD3dx9() p_D3DXAssembleShader = reinterpret_cast(MemoryGetProcAddress(d3dx9Module, "D3DXAssembleShader")); p_D3DXDisassembleShader = reinterpret_cast(MemoryGetProcAddress(d3dx9Module, "D3DXDisassembleShader")); p_D3DXFillTexture = reinterpret_cast(MemoryGetProcAddress(d3dx9Module, "D3DXFillTexture")); + p_D3DXCreateFontA = reinterpret_cast(MemoryGetProcAddress(d3dx9Module, "D3DXCreateFontA")); + p_D3DXCreateFontW = reinterpret_cast(MemoryGetProcAddress(d3dx9Module, "D3DXCreateFontW")); + p_D3DXCreateSprite = reinterpret_cast(MemoryGetProcAddress(d3dx9Module, "D3DXCreateSprite")); } if (d3dCompileModule) { @@ -499,3 +512,69 @@ HRESULT WINAPI D3DXFillTexture(LPVOID pTexture, LPD3DXFILL3D pFunction, LPVOID p return hr; } + +HRESULT WINAPI D3DXCreateFontA(LPDIRECT3DDEVICE9 pDevice, INT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCSTR pFaceName, LPD3DXFONT* ppFont) +{ + Logging::LogDebug() << __FUNCTION__; + + LoadD3dx9(); + + if (!p_D3DXCreateFontA) + { + LOG_ONCE(__FUNCTION__ << " Error: Could not find ProcAddress!"); + return D3DERR_INVALIDCALL; + } + + HRESULT hr = p_D3DXCreateFontA(pDevice, Height, Width, Weight, MipLevels, Italic, CharSet, OutputPrecision, Quality, PitchAndFamily, pFaceName, ppFont); + + if (FAILED(hr)) + { + Logging::Log() << __FUNCTION__ << " Error: Failed to create font!"; + } + + return hr; +} + +HRESULT WINAPI D3DXCreateFontW(LPDIRECT3DDEVICE9 pDevice, INT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCWSTR pFaceName, LPD3DXFONT* ppFont) +{ + Logging::LogDebug() << __FUNCTION__; + + LoadD3dx9(); + + if (!p_D3DXCreateFontW) + { + LOG_ONCE(__FUNCTION__ << " Error: Could not find ProcAddress!"); + return D3DERR_INVALIDCALL; + } + + HRESULT hr = p_D3DXCreateFontW(pDevice, Height, Width, Weight, MipLevels, Italic, CharSet, OutputPrecision, Quality, PitchAndFamily, pFaceName, ppFont); + + if (FAILED(hr)) + { + Logging::Log() << __FUNCTION__ << " Error: Failed to create font!"; + } + + return hr; +} + +HRESULT WINAPI D3DXCreateSprite(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite) +{ + Logging::LogDebug() << __FUNCTION__; + + LoadD3dx9(); + + if (!p_D3DXCreateSprite) + { + LOG_ONCE(__FUNCTION__ << " Error: Could not find ProcAddress!"); + return D3DERR_INVALIDCALL; + } + + HRESULT hr = p_D3DXCreateSprite(pDevice, ppSprite); + + if (FAILED(hr)) + { + Logging::Log() << __FUNCTION__ << " Error: Failed to create font!"; + } + + return hr; +} diff --git a/Libraries/d3dx9.h b/Libraries/d3dx9.h index cf5d2431..269912fa 100644 --- a/Libraries/d3dx9.h +++ b/Libraries/d3dx9.h @@ -71,12 +71,189 @@ typedef ID3DInclude* LPD3DINCLUDE; #define D3D_DISASM_ENABLE_INSTRUCTION_CYCLE 0x00000008 #define D3D_DISASM_DISABLE_DEBUG_INFO 0x00000010 +using D3DXMACRO = D3D_SHADER_MACRO; + +using D3DXMATRIX = D3DMATRIX; + +using ID3DXBuffer = ID3DBlob; +using LPD3DXBUFFER = ID3DXBuffer*; + +using ID3DXInclude = ID3DInclude; +using LPD3DXINCLUDE = ID3DXInclude*; + typedef struct D3DXVECTOR3 { FLOAT x; FLOAT y; FLOAT z; } D3DXVECTOR3, * LPD3DXVECTOR3; +////////////////////////////////////////////////////////////////////////////// +// D3DXSPRITE flags: +// ----------------- +// D3DXSPRITE_DONOTSAVESTATE +// Specifies device state is not to be saved and restored in Begin/End. +// D3DXSPRITE_DONOTMODIFY_RENDERSTATE +// Specifies device render state is not to be changed in Begin. The device +// is assumed to be in a valid state to draw vertices containing POSITION0, +// TEXCOORD0, and COLOR0 data. +// D3DXSPRITE_OBJECTSPACE +// The WORLD, VIEW, and PROJECTION transforms are NOT modified. The +// transforms currently set to the device are used to transform the sprites +// when the batch is drawn (at Flush or End). If this is not specified, +// WORLD, VIEW, and PROJECTION transforms are modified so that sprites are +// drawn in screenspace coordinates. +// D3DXSPRITE_BILLBOARD +// Rotates each sprite about its center so that it is facing the viewer. +// D3DXSPRITE_ALPHABLEND +// Enables ALPHABLEND(SRCALPHA, INVSRCALPHA) and ALPHATEST(alpha > 0). +// ID3DXFont expects this to be set when drawing text. +// D3DXSPRITE_SORT_TEXTURE +// Sprites are sorted by texture prior to drawing. This is recommended when +// drawing non-overlapping sprites of uniform depth. For example, drawing +// screen-aligned text with ID3DXFont. +// D3DXSPRITE_SORT_DEPTH_FRONTTOBACK +// Sprites are sorted by depth front-to-back prior to drawing. This is +// recommended when drawing opaque sprites of varying depths. +// D3DXSPRITE_SORT_DEPTH_BACKTOFRONT +// Sprites are sorted by depth back-to-front prior to drawing. This is +// recommended when drawing transparent sprites of varying depths. +// D3DXSPRITE_DO_NOT_ADDREF_TEXTURE +// Disables calling AddRef() on every draw, and Release() on Flush() for +// better performance. +////////////////////////////////////////////////////////////////////////////// + +#define D3DXSPRITE_DONOTSAVESTATE (1 << 0) +#define D3DXSPRITE_DONOTMODIFY_RENDERSTATE (1 << 1) +#define D3DXSPRITE_OBJECTSPACE (1 << 2) +#define D3DXSPRITE_BILLBOARD (1 << 3) +#define D3DXSPRITE_ALPHABLEND (1 << 4) +#define D3DXSPRITE_SORT_TEXTURE (1 << 5) +#define D3DXSPRITE_SORT_DEPTH_FRONTTOBACK (1 << 6) +#define D3DXSPRITE_SORT_DEPTH_BACKTOFRONT (1 << 7) +#define D3DXSPRITE_DO_NOT_ADDREF_TEXTURE (1 << 8) + +typedef interface ID3DXSprite ID3DXSprite; +typedef interface ID3DXSprite* LPD3DXSPRITE; + +// {BA0B762D-7D28-43ec-B9DC-2F84443B0614} +DEFINE_GUID(IID_ID3DXSprite, + 0xba0b762d, 0x7d28, 0x43ec, 0xb9, 0xdc, 0x2f, 0x84, 0x44, 0x3b, 0x6, 0x14); + +#undef INTERFACE +#define INTERFACE ID3DXSprite + +DECLARE_INTERFACE_(ID3DXSprite, IUnknown) +{ + // IUnknown + STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID * ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // ID3DXSprite + STDMETHOD(GetDevice)(THIS_ LPDIRECT3DDEVICE9 * ppDevice) PURE; + + STDMETHOD(GetTransform)(THIS_ D3DXMATRIX * pTransform) PURE; + STDMETHOD(SetTransform)(THIS_ CONST D3DXMATRIX * pTransform) PURE; + + STDMETHOD(SetWorldViewRH)(THIS_ CONST D3DXMATRIX * pWorld, CONST D3DXMATRIX * pView) PURE; + STDMETHOD(SetWorldViewLH)(THIS_ CONST D3DXMATRIX * pWorld, CONST D3DXMATRIX * pView) PURE; + + STDMETHOD(Begin)(THIS_ DWORD Flags) PURE; + STDMETHOD(Draw)(THIS_ LPDIRECT3DTEXTURE9 pTexture, CONST RECT * pSrcRect, CONST D3DXVECTOR3 * pCenter, CONST D3DXVECTOR3 * pPosition, D3DCOLOR Color) PURE; + STDMETHOD(Flush)(THIS) PURE; + STDMETHOD(End)(THIS) PURE; + + STDMETHOD(OnLostDevice)(THIS) PURE; + STDMETHOD(OnResetDevice)(THIS) PURE; +}; + +typedef struct _D3DXFONT_DESCA +{ + INT Height; + UINT Width; + UINT Weight; + UINT MipLevels; + BOOL Italic; + BYTE CharSet; + BYTE OutputPrecision; + BYTE Quality; + BYTE PitchAndFamily; + CHAR FaceName[LF_FACESIZE]; + +} D3DXFONT_DESCA, * LPD3DXFONT_DESCA; + +typedef struct _D3DXFONT_DESCW +{ + INT Height; + UINT Width; + UINT Weight; + UINT MipLevels; + BOOL Italic; + BYTE CharSet; + BYTE OutputPrecision; + BYTE Quality; + BYTE PitchAndFamily; + WCHAR FaceName[LF_FACESIZE]; + +} D3DXFONT_DESCW, * LPD3DXFONT_DESCW; + +#ifdef UNICODE +typedef D3DXFONT_DESCW D3DXFONT_DESC; +typedef LPD3DXFONT_DESCW LPD3DXFONT_DESC; +#else +typedef D3DXFONT_DESCA D3DXFONT_DESC; +typedef LPD3DXFONT_DESCA LPD3DXFONT_DESC; +#endif + +typedef interface ID3DXFont ID3DXFont; +typedef interface ID3DXFont* LPD3DXFONT; + +// {D79DBB70-5F21-4d36-BBC2-FF525C213CDC} +DEFINE_GUID(IID_ID3DXFont, + 0xd79dbb70, 0x5f21, 0x4d36, 0xbb, 0xc2, 0xff, 0x52, 0x5c, 0x21, 0x3c, 0xdc); + +#undef INTERFACE +#define INTERFACE ID3DXFont + +DECLARE_INTERFACE_(ID3DXFont, IUnknown) +{ + // IUnknown + STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID * ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // ID3DXFont + STDMETHOD(GetDevice)(THIS_ LPDIRECT3DDEVICE9 * ppDevice) PURE; + STDMETHOD(GetDescA)(THIS_ D3DXFONT_DESCA * pDesc) PURE; + STDMETHOD(GetDescW)(THIS_ D3DXFONT_DESCW * pDesc) PURE; + STDMETHOD_(BOOL, GetTextMetricsA)(THIS_ TEXTMETRICA * pTextMetrics) PURE; + STDMETHOD_(BOOL, GetTextMetricsW)(THIS_ TEXTMETRICW * pTextMetrics) PURE; + + STDMETHOD_(HDC, GetDC)(THIS) PURE; + STDMETHOD(GetGlyphData)(THIS_ UINT Glyph, LPDIRECT3DTEXTURE9 * ppTexture, RECT * pBlackBox, POINT * pCellInc) PURE; + + STDMETHOD(PreloadCharacters)(THIS_ UINT First, UINT Last) PURE; + STDMETHOD(PreloadGlyphs)(THIS_ UINT First, UINT Last) PURE; + STDMETHOD(PreloadTextA)(THIS_ LPCSTR pString, INT Count) PURE; + STDMETHOD(PreloadTextW)(THIS_ LPCWSTR pString, INT Count) PURE; + + STDMETHOD_(INT, DrawTextA)(THIS_ LPD3DXSPRITE pSprite, LPCSTR pString, INT Count, LPRECT pRect, DWORD Format, D3DCOLOR Color) PURE; + STDMETHOD_(INT, DrawTextW)(THIS_ LPD3DXSPRITE pSprite, LPCWSTR pString, INT Count, LPRECT pRect, DWORD Format, D3DCOLOR Color) PURE; + + STDMETHOD(OnLostDevice)(THIS) PURE; + STDMETHOD(OnResetDevice)(THIS) PURE; + +#ifdef __cplusplus +#ifdef UNICODE + HRESULT GetDesc(D3DXFONT_DESCW * pDesc) { return GetDescW(pDesc); } + HRESULT PreloadText(LPCWSTR pString, INT Count) { return PreloadTextW(pString, Count); } +#else + HRESULT GetDesc(D3DXFONT_DESCA * pDesc) { return GetDescA(pDesc); } + HRESULT PreloadText(LPCSTR pString, INT Count) { return PreloadTextA(pString, Count); } +#endif +#endif //__cplusplus +}; + typedef enum D3DXIMAGE_FILEFORMAT { D3DXIFF_BMP = 0, D3DXIFF_JPG = 1, @@ -123,16 +300,6 @@ typedef HRESULT(WINAPI* LPD3DXFILL3D)(D3DXVECTOR4* pOut, const D3DXVECTOR2* pTex #define D3DXASM_FLAGS D3DXASM_DEBUG #endif // NDEBUG -using D3DXMACRO = D3D_SHADER_MACRO; - -using D3DXMATRIX = D3DMATRIX; - -using ID3DXBuffer = ID3DBlob; -using LPD3DXBUFFER = ID3DXBuffer*; - -using ID3DXInclude = ID3DInclude; -using LPD3DXINCLUDE = ID3DXInclude*; - HRESULT WINAPI D3DXCreateTexture(LPDIRECT3DDEVICE9 pDevice, UINT Width, UINT Height, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, LPDIRECT3DTEXTURE9* ppTexture); HRESULT WINAPI D3DXLoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSurface, const PALETTEENTRY* pDestPalette, const RECT* pDestRect, LPCVOID pSrcMemory, D3DFORMAT SrcFormat, UINT SrcPitch, const PALETTEENTRY* pSrcPalette, const RECT* pSrcRect, DWORD Filter, D3DCOLOR ColorKey); HRESULT WINAPI D3DXLoadSurfaceFromSurface(LPDIRECT3DSURFACE9 pDestSurface, const PALETTEENTRY* pDestPalette, const RECT* pDestRect, LPDIRECT3DSURFACE9 pSrcSurface, const PALETTEENTRY* pSrcPalette, const RECT* pSrcRect, DWORD Filter, D3DCOLOR ColorKey); @@ -153,3 +320,8 @@ HRESULT WINAPI D3DCompile(LPCVOID pSrcData, SIZE_T SrcDataSize, LPCSTR pSourceNa HRESULT WINAPI D3DDisassemble(LPCVOID pSrcData, SIZE_T SrcDataSize, UINT Flags, LPCSTR szComments, ID3DBlob** ppDisassembly); HRESULT WINAPI D3DXFillTexture(LPVOID pTexture, LPD3DXFILL3D pFunction, LPVOID pData); + +HRESULT WINAPI D3DXCreateFontA(LPDIRECT3DDEVICE9 pDevice, INT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCSTR pFaceName, LPD3DXFONT* ppFont); +HRESULT WINAPI D3DXCreateFontW(LPDIRECT3DDEVICE9 pDevice, INT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCWSTR pFaceName, LPD3DXFONT* ppFont); + +HRESULT WINAPI D3DXCreateSprite(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); diff --git a/Libraries/dwmapi.cpp b/Libraries/dwmapi.cpp index bfabe834..e9f9dde9 100644 --- a/Libraries/dwmapi.cpp +++ b/Libraries/dwmapi.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Libraries/uxtheme.cpp b/Libraries/uxtheme.cpp index 42db348b..a5618068 100644 --- a/Libraries/uxtheme.cpp +++ b/Libraries/uxtheme.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Libraries/winmm.cpp b/Libraries/winmm.cpp index 937b8726..daa97e26 100644 --- a/Libraries/winmm.cpp +++ b/Libraries/winmm.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -20,8 +20,10 @@ typedef MMRESULT(WINAPI *PFN_timeBeginPeriod)(UINT uPeriod); typedef MMRESULT(WINAPI *PFN_timeEndPeriod)(UINT uPeriod); +typedef DWORD(WINAPI* PFN_timeGetTime)(); PFN_timeBeginPeriod timeBeginPeriodPtr = nullptr; PFN_timeEndPeriod timeEndPeriodPtr = nullptr; +PFN_timeGetTime timeGetTimePtr = nullptr; HMODULE winmmModule = nullptr; void Loadwinmm() @@ -37,8 +39,10 @@ void Loadwinmm() { timeBeginPeriodPtr = reinterpret_cast(GetProcAddress(winmmModule, "timeBeginPeriod")); timeEndPeriodPtr = reinterpret_cast(GetProcAddress(winmmModule, "timeEndPeriod")); + timeGetTimePtr = reinterpret_cast(GetProcAddress(winmmModule, "timeGetTime")); if (!timeBeginPeriodPtr) Logging::Log() << "Failed to get 'timeBeginPeriod' ProcAddress of winmm.dll!"; if (!timeEndPeriodPtr) Logging::Log() << "Failed to get 'timeEndPeriod' ProcAddress of winmm.dll!"; + if (!timeGetTimePtr) Logging::Log() << "Failed to get 'timeGetTime' ProcAddress of winmm.dll!"; } else { @@ -71,3 +75,16 @@ MMRESULT timeEndPeriod(UINT uPeriod) } return S_FALSE; } + +DWORD timeGetTime() +{ + // Load module + Loadwinmm(); + + // Call function + if (timeGetTimePtr) + { + return timeGetTimePtr(); + } + return 0; +} diff --git a/Libraries/winmm.h b/Libraries/winmm.h index e89b21e4..973619e9 100644 --- a/Libraries/winmm.h +++ b/Libraries/winmm.h @@ -11,3 +11,4 @@ typedef _Return_type_success_(return == 0) UINT MMRESULT; /* error return code MMRESULT timeBeginPeriod(UINT); MMRESULT timeEndPeriod(UINT); +DWORD timeGetTime(); diff --git a/License.txt b/License.txt index 53f73bd0..9cdb9d78 100644 --- a/License.txt +++ b/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Logging/License.txt b/Logging/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Logging/License.txt +++ b/Logging/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Logging/Logging.cpp b/Logging/Logging.cpp index 89850c40..cc4b17b7 100644 --- a/Logging/Logging.cpp +++ b/Logging/Logging.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -23,8 +23,7 @@ #include #include #include -#include "ddraw\IDirectDrawTypes.h" -#include "ddraw\IDirect3DTypes.h" +#include "ddraw\ddraw.h" #include #include #include diff --git a/MakeShader/MakeShader.cpp b/MakeShader/MakeShader.cpp index accda4df..2e57a5dc 100644 --- a/MakeShader/MakeShader.cpp +++ b/MakeShader/MakeShader.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/MakeShader/MakeShader.vcxproj b/MakeShader/MakeShader.vcxproj index 28b57519..dd7e19a1 100644 --- a/MakeShader/MakeShader.vcxproj +++ b/MakeShader/MakeShader.vcxproj @@ -58,6 +58,7 @@ + diff --git a/MakeShader/MakeShader.vcxproj.filters b/MakeShader/MakeShader.vcxproj.filters index cc37fc09..ed0d3b38 100644 --- a/MakeShader/MakeShader.vcxproj.filters +++ b/MakeShader/MakeShader.vcxproj.filters @@ -20,6 +20,9 @@ Hooking + + Utils + diff --git a/README.md b/README.md index 9d90adea..18de8e1e 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ DxWrapper can wrap the following dlls: - wsock32.dll ### License -Copyright (C) 2024 Elisha Riedlinger +Copyright (C) 2025 Elisha Riedlinger This software is provided 'as-is', without any express or implied warranty. In no event will the author(s) be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: diff --git a/Settings/AllSettings.ini b/Settings/AllSettings.ini index d490a939..342c39e9 100644 --- a/Settings/AllSettings.ini +++ b/Settings/AllSettings.ini @@ -51,8 +51,6 @@ DDrawCompatDisableGDIHook = 0 DDrawCompatNoProcAffinity = 0 [ddraw] -ConvertToDirectDraw7 = 0 -ConvertToDirect3D7 = 0 DdrawOverrideBitMode = 0 DdrawResolutionHack = 0 DirectShowEmulation = 0 @@ -73,6 +71,7 @@ DdrawReadFromGDI = 0 DdrawWriteToGDI = 0 DdrawEnableMouseHook = 0 DdrawDisableDirect3DCaps = 0 +DdrawLimitTextureFormats = 0 DdrawLimitDisplayModeCount = 0 DdrawCustomWidth = 0 DdrawCustomHeight = 0 @@ -99,12 +98,18 @@ AntiAliasing = 0 CacheClipPlane = 0 EnvironmentMapCubeFix = 0 LimitStateBlocks = 0 +ForceSingleBeginEndScene = 0 EnableVSync = 0 ForceVsyncMode = 0 +ShowFPSCounter = 0 OverrideRefreshRate = 0 +LimitDisplayModeCount = 0 +CustomDisplayWidth = 0 +CustomDisplayHeight = 0 LimitPerFrameFPS = 0 EnableWindowMode = 0 WindowModeBorder = 0 +WindowModeGammaShader = 0 SetInitialWindowPosition = 0 InitialWindowPositionLeft = 0 InitialWindowPositionTop = 0 diff --git a/Settings/License.txt b/Settings/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Settings/License.txt +++ b/Settings/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Settings/ReadParse.cpp b/Settings/ReadParse.cpp index bac12f38..e811f4c6 100644 --- a/Settings/ReadParse.cpp +++ b/Settings/ReadParse.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Settings/Settings.cpp b/Settings/Settings.cpp index 1e4bf88b..22d69898 100644 --- a/Settings/Settings.cpp +++ b/Settings/Settings.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -470,6 +470,8 @@ void Settings::SetDefaultConfigSettings() Config.CacheClipPlane = NOT_EXIST; Config.EnvironmentMapCubeFix = NOT_EXIST; Config.LimitStateBlocks = NOT_EXIST; + Config.ForceSingleBeginEndScene = NOT_EXIST; + Config.WindowModeGammaShader = NOT_EXIST; // Other values that may not exist in ini file Config.DisableMaxWindowedModeNotSet = true; @@ -688,15 +690,9 @@ void CONFIG::SetConfig() Dinputto8 = (Dinputto8 || IsSet(Dinput8HookSystem32)); EnableDinput8Wrapper = (EnableDinput8Wrapper || IsSet(Dinput8HookSystem32)); - if (Dd7to9) - { - ConvertToDirectDraw7 = true; - ConvertToDirect3D7 = true; - } - DDrawCompat32 = (DDrawCompat30 || DDrawCompat31 || DDrawCompat32 || DDrawCompatExperimental); DDrawCompat = (DDrawCompat || DDrawCompat20 || DDrawCompat21 || DDrawCompat32); - EnableDdrawWrapper = (EnableDdrawWrapper || IsSet(DdrawHookSystem32) || ConvertToDirectDraw7 || ConvertToDirect3D7 || IsSet(DdrawResolutionHack) || Dd7to9); + EnableDdrawWrapper = (EnableDdrawWrapper || IsSet(DdrawHookSystem32) || IsSet(DdrawResolutionHack) || Dd7to9); D3d8to9 = (D3d8to9 || IsSet(D3d8HookSystem32)); DdrawAutoFrameSkip = (AutoFrameSkip || DdrawAutoFrameSkip); // For legacy purposes EnableWindowMode = (FullscreenWindowMode) ? true : EnableWindowMode; @@ -778,4 +774,6 @@ void CONFIG::SetConfig() CacheClipPlane = (CacheClipPlane != 0); EnvironmentMapCubeFix = (EnvironmentMapCubeFix != 0); LimitStateBlocks = (LimitStateBlocks != 0); + ForceSingleBeginEndScene = (ForceSingleBeginEndScene != 0); + WindowModeGammaShader = (WindowModeGammaShader != 0); } diff --git a/Settings/Settings.h b/Settings/Settings.h index dfe619b4..a0a62395 100644 --- a/Settings/Settings.h +++ b/Settings/Settings.h @@ -13,6 +13,8 @@ visit(AntiAliasing) \ visit(AudioClipDetection) \ visit(AudioFadeOutDelayMS) \ + visit(CustomDisplayWidth) \ + visit(CustomDisplayHeight) \ visit(Dd7to9) \ visit(D3d8to9) \ visit(Dinputto8) \ @@ -42,6 +44,7 @@ visit(DdrawWriteToGDI) \ visit(DdrawIntegerScalingClamp) \ visit(DdrawLimitDisplayModeCount) \ + visit(DdrawLimitTextureFormats) \ visit(DdrawMaintainAspectRatio) \ visit(DdrawOverrideBitMode) \ visit(DdrawOverrideWidth) \ @@ -73,8 +76,6 @@ visit(DirectShowEmulation) \ visit(CacheClipPlane) \ visit(EnvironmentMapCubeFix) \ - visit(ConvertToDirectDraw7) \ - visit(ConvertToDirect3D7) \ visit(EnableDdrawWrapper) \ visit(EnableD3d9Wrapper) \ visit(EnableDinput8Wrapper) \ @@ -88,6 +89,7 @@ visit(ForceExclusiveFullscreen) \ visit(ForceMixedVertexProcessing) \ visit(ForceSystemMemVertexCache) \ + visit(ForceSingleBeginEndScene) \ visit(FilterNonActiveInput) \ visit(FixHighFrequencyMouse) \ visit(FixSpeakerConfigType) \ @@ -110,6 +112,7 @@ visit(InitialWindowPositionLeft) \ visit(InitialWindowPositionTop) \ visit(isAppCompatDataSet) \ + visit(LimitDisplayModeCount) \ visit(LimitPerFrameFPS) \ visit(LoadCustomDllPath) \ visit(LoadFromScriptsOnly) \ @@ -133,6 +136,7 @@ visit(SetFullScreenLayer) \ visit(SetInitialWindowPosition) \ visit(SetNamedLayer) \ + visit(ShowFPSCounter) \ visit(SingleProcAffinity) \ visit(StoppedDriverWorkaround) \ visit(WaitForProcess) \ @@ -141,6 +145,7 @@ visit(WindowModeBorder) \ visit(WinVersionLie) \ visit(WinVersionLieSP) \ + visit(WindowModeGammaShader) \ visit(WrapperMode) #define VISIT_APPCOMPATDATA_SETTINGS(visit) \ @@ -253,6 +258,7 @@ struct CONFIG DWORD DdrawCustomWidth = 0; // Custom resolution width for Dd7to9 when using DdrawLimitDisplayModeCount, resolution must be supported by video card and monitor DWORD DdrawCustomHeight = 0; // Custom resolution height for Dd7to9 when using DdrawLimitDisplayModeCount, resolution must be supported by video card and monitor bool DdrawDisableDirect3DCaps = false; // Disable caps for Direct3D to try and force the game to use DirectDraw instaed of Direct3D + bool DdrawLimitTextureFormats = false; // Limits the number of texture formats sent to the program, some games crash when you feed them with too many textures bool DdrawLimitDisplayModeCount = false; // Limits the number of display modes sent to program, some games crash when you feed them with too many resolutions DWORD DdrawOverrideBitMode = 0; // Forces DirectX to use specified bit mode: 8, 16, 24, 32 DWORD DdrawOverrideWidth = 0; // Force Direct3d9 to use this width when using Dd7to9 @@ -277,8 +283,8 @@ struct CONFIG DWORD SetSwapEffectShim = 0; // Disables the call to d3d9.dll 'Direct3D9SetSwapEffectUpgradeShim' to switch present mode DWORD CacheClipPlane = 0; // Caches the ClipPlane for Direct3D9 to fix an issue in d3d9 on Windows 8 and newer DWORD EnvironmentMapCubeFix = 0; // Fixes environment cube maps when no texture is applied, issue exists in d3d8 - bool ConvertToDirectDraw7 = false; // Converts DirectDraw 1-6 to DirectDraw 7 - bool ConvertToDirect3D7 = false; // Converts Direct3D 1-6 to Direct3D 7 + DWORD CustomDisplayWidth = 0; // Custom resolution width when using LimitDisplayModeCount, resolution must be supported by video card and monitor + DWORD CustomDisplayHeight = 0; // Custom resolution height when using LimitDisplayModeCount, resolution must be supported by video card and monitor bool EnableDdrawWrapper = false; // Enables the ddraw wrapper DWORD EnableD3d9Wrapper = 0; // Enables the d3d9 wrapper bool EnableDinput8Wrapper = false; // Enables the dinput8 wrapper @@ -294,6 +300,7 @@ struct CONFIG bool ForceExclusiveFullscreen = false; // Forces exclusive fullscreen mode in d3d9 bool ForceMixedVertexProcessing = false; // Forces Mixed mode for vertex processing in d3d9 bool ForceSystemMemVertexCache = false; // Forces System Memory caching for vertexes in d3d9 + DWORD ForceSingleBeginEndScene = 0; // Ensures that only a single EndScene/BeginScene pair are called per frame bool FullScreen = false; // Sets the main window to fullscreen bool FullscreenWindowMode = false; // Enables fullscreen windowed mode, requires EnableWindowMode bool ForceTermination = false; // Terminates application when main window closes @@ -302,6 +309,7 @@ struct CONFIG DWORD GraphicsHybridAdapter = 0; // Sets the Direct3D9 Hybrid Enumeration Mode to allow using a secondary display adapter bool HandleExceptions = false; // Handles unhandled exceptions in the application bool isAppCompatDataSet = false; // Flag that holds tells whether any of the AppCompatData flags are set + bool LimitDisplayModeCount = false; // Limits the number of display modes sent to program, some games crash when you feed them with too many resolutions float LimitPerFrameFPS = 0; // Limits each frame by adding a delay if the frame is to fast bool LoadPlugins = false; // Loads ASI plugins bool LoadFromScriptsOnly = false; // Loads ASI plugins from 'scripts' and 'plugins' folder only @@ -312,12 +320,14 @@ struct CONFIG bool WaitForProcess = false; // Waits for process to end before continuing, requires FullScreen bool WaitForWindowChanges = false; // Waits for window handle to stabilize before setting fullsreen, requires FullScreen bool WindowModeBorder = false; // Enables the window border when EnableWindowMode is set, requires EnableWindowMode + DWORD WindowModeGammaShader = 0; // Use shader for gamma when in window mode bool SetInitialWindowPosition = false; // Enable Initial window position DWORD InitialWindowPositionLeft; // Initial left window position for application DWORD InitialWindowPositionTop; // Initial top window position for application DWORD LoopSleepTime = 0; // Time to sleep between each window handle check loop, requires FullScreen DWORD ResetMemoryAfter = 0; // Undo hot patch after this amount of time DWORD WindowSleepTime = 0; // Time to wait (sleep) for window handle and screen updates to finish, requires FullScreen + DWORD ShowFPSCounter = 0; // Shows the FPS counter. 1 = top left; 2 = top right; 3 = bottom right; 4 = bottom left DWORD SingleProcAffinity = 0; // Sets the CPU affinity for this process DWORD SetFullScreenLayer = 0; // The layer to be selected for fullscreen, requires FullScreen DWORD AnisotropicFiltering = 0; // Enable Anisotropic Filtering for d3d9 diff --git a/Settings/Settings.ini b/Settings/Settings.ini index 9ab09b36..7879d464 100644 --- a/Settings/Settings.ini +++ b/Settings/Settings.ini @@ -40,8 +40,6 @@ DDrawCompatDisableGDIHook = 0 DDrawCompatNoProcAffinity = 0 [ddraw] -ConvertToDirectDraw7 = 0 -ConvertToDirect3D7 = 0 DdrawOverrideBitMode = 0 [Dd7to9] @@ -57,6 +55,7 @@ DdrawRemoveInterlacing = 0 DdrawReadFromGDI = 0 DdrawWriteToGDI = 0 DdrawDisableDirect3DCaps = 0 +DdrawLimitTextureFormats = 0 DdrawLimitDisplayModeCount = 0 DdrawCustomWidth = 0 DdrawCustomHeight = 0 @@ -71,7 +70,11 @@ AnisotropicFiltering = 0 AntiAliasing = 0 EnableVSync = 0 ForceVsyncMode = 0 +ShowFPSCounter = 0 OverrideRefreshRate = 0 +LimitDisplayModeCount = 0 +CustomDisplayWidth = 0 +CustomDisplayHeight = 0 LimitPerFrameFPS = 0 EnableWindowMode = 0 WindowModeBorder = 0 diff --git a/Stub/License.txt b/Stub/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Stub/License.txt +++ b/Stub/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Stub/Logging/License.txt b/Stub/Logging/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Stub/Logging/License.txt +++ b/Stub/Logging/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Stub/Stub.cpp b/Stub/Stub.cpp index 3c57bd91..05374636 100644 --- a/Stub/Stub.cpp +++ b/Stub/Stub.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Stub/d3d8.cpp b/Stub/d3d8.cpp index 8963dc43..33400263 100644 --- a/Stub/d3d8.cpp +++ b/Stub/d3d8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Stub/ddraw.cpp b/Stub/ddraw.cpp index 66f0439a..9a121adb 100644 --- a/Stub/ddraw.cpp +++ b/Stub/ddraw.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Stub/dinput.cpp b/Stub/dinput.cpp index bbd1cec1..26707ef7 100644 --- a/Stub/dinput.cpp +++ b/Stub/dinput.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Stub/stub.h b/Stub/stub.h index 13924831..e07b5f4e 100644 --- a/Stub/stub.h +++ b/Stub/stub.h @@ -8,7 +8,7 @@ #define APP_NAME "DxWrapper Stub" #define APP_COMPANYNAME "Sadrate Presents" #define APP_DESCRPTION "Stub for DxWrapper. Supports: bcrypt.dll, cryptsp.dll, d2d1.dll, d3d8.dll, d3d9.dll, d3d10.dll, d3d11.dll, d3d12.dll, dciman32.dll, ddraw.dll, dinput.dll, dinput8.dll, dplayx.dll, dsound.dll, msacm32.dll, msvfw32.dll, version.dll, winmm.dll, winmmbase.dll" // Can only be 256 characters long -#define APP_COPYRIGHT "Copyright (C) 2024 Elisha Riedlinger" +#define APP_COPYRIGHT "Copyright (C) 2025 Elisha Riedlinger" #define APP_ORIGINALVERSION "Stub.dll" #define APP_INTERNALNAME "DxWrapper Stub" diff --git a/Utils/CPUAffinity.cpp b/Utils/CPUAffinity.cpp new file mode 100644 index 00000000..89eb61d8 --- /dev/null +++ b/Utils/CPUAffinity.cpp @@ -0,0 +1,124 @@ +/** +* Copyright (C) 2025 Elisha Riedlinger +* +* This software is provided 'as-is', without any express or implied warranty. In no event will the +* authors be held liable for any damages arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the +* original software. If you use this software in a product, an acknowledgment in the product +* documentation would be appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented as +* being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include "Utils.h" +#include "Settings\Settings.h" +#include "Logging\Logging.h" + +namespace Utils +{ + // Function declarations + DWORD GetCoresUsedByProcess(); + DWORD_PTR GetCPUMask(); +} + +// Check the number CPU cores is being used by the process +DWORD Utils::GetCoresUsedByProcess() +{ + int numCores = 0; + DWORD_PTR ProcessAffinityMask, SystemAffinityMask; + if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask)) + { + while (ProcessAffinityMask) + { + if (ProcessAffinityMask & 1) + { + ++numCores; + } + ProcessAffinityMask >>= 1; + } + } + return numCores; +} + +// Get processor mask +DWORD_PTR Utils::GetCPUMask() +{ + static DWORD_PTR nMask = 0; + if (nMask) + { + return nMask; + } + + DWORD_PTR ProcessAffinityMask, SystemAffinityMask; + if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask)) + { + DWORD_PTR AffinityLow = 1; + while (AffinityLow && (AffinityLow & SystemAffinityMask) == 0) + { + AffinityLow <<= 1; + } + if (AffinityLow) + { + nMask = ((AffinityLow << (Config.SingleProcAffinity - 1)) & SystemAffinityMask) ? (AffinityLow << (Config.SingleProcAffinity - 1)) : AffinityLow; + } + } + + Logging::Log() << __FUNCTION__ << " Setting CPU mask: " << Logging::hex(nMask); + return nMask; +} + +// Set Single Core Affinity +void Utils::SetProcessAffinity() +{ + Logging::Log() << "Setting SingleCoreAffinity..."; + SetProcessAffinityMask(GetCurrentProcess(), GetCPUMask()); +} + +void Utils::SetThreadAffinity(DWORD threadId) +{ + static DWORD_PTR cpuAffinityMask = GetCPUMask(); + + HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION, FALSE, threadId); + if (hThread) + { + SetThreadAffinityMask(hThread, cpuAffinityMask); + CloseHandle(hThread); + } +} + +void Utils::ApplyThreadAffinity() +{ + const DWORD pid = GetCurrentProcessId(); + const HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (INVALID_HANDLE_VALUE == snapshot) + { + Logging::Log() << "ERROR: CreateToolhelp32Snapshot failed: " << Logging::hex(GetLastError()); + return; + } + + THREADENTRY32 te = {}; + te.dwSize = sizeof(te); + if (!Thread32First(snapshot, &te)) + { + CloseHandle(snapshot); + Logging::Log() << "ERROR: Thread32First failed: " << Logging::hex(GetLastError()); + return; + } + + do { + if (pid == te.th32OwnerProcessID) + { + SetThreadAffinity(te.th32ThreadID); + } + } while (Thread32Next(snapshot, &te)); + + CloseHandle(snapshot); +} diff --git a/Utils/Disasm.cpp b/Utils/Disasm.cpp index 68e077eb..953bd009 100644 --- a/Utils/Disasm.cpp +++ b/Utils/Disasm.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -42,10 +42,15 @@ namespace Utils // Add filter for UnhandledExceptionFilter used by the exception handler to catch exceptions LONG WINAPI Utils::myUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { + char moduleName[MAX_PATH]; + GetModuleFromAddress(ExceptionInfo->ExceptionRecord->ExceptionAddress, moduleName, MAX_PATH); + Logging::Log() << "UnhandledExceptionFilter: exception" << std::showbase << std::hex << " code=" << ExceptionInfo->ExceptionRecord->ExceptionCode << " flags=" << ExceptionInfo->ExceptionRecord->ExceptionFlags << - " addr=" << ExceptionInfo->ExceptionRecord->ExceptionAddress << std::dec << std::noshowbase; + " addr=" << ExceptionInfo->ExceptionRecord->ExceptionAddress << std::dec << std::noshowbase << + " module=" << moduleName; + DWORD oldprot; PVOID target = ExceptionInfo->ExceptionRecord->ExceptionAddress; switch (ExceptionInfo->ExceptionRecord->ExceptionCode) diff --git a/Utils/Fullscreen.cpp b/Utils/Fullscreen.cpp index 5a01f6ff..7ca9c1bc 100644 --- a/Utils/Fullscreen.cpp +++ b/Utils/Fullscreen.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -117,7 +117,7 @@ namespace Fullscreen }; // Declare variables - bool m_StopThreadFlag = false; + const bool& m_StopThreadFlag = Config.Exiting; bool m_ThreadRunningFlag = false; HANDLE m_hThread = nullptr; DWORD m_dwThreadID = 0; @@ -255,7 +255,7 @@ void Fullscreen::GetScreenSize(HWND hwnd, screen_res& Res, MONITORINFO& mi) Res.Height = mi.rcMonitor.bottom - mi.rcMonitor.top; } -void Utils::GetScreenSize(HWND hwnd, LONG &screenWidth, LONG &screenHeight) +void Utils::GetScreenSize(HWND hwnd, volatile LONG &screenWidth, volatile LONG &screenHeight) { MONITORINFO info = {}; info.cbSize = sizeof(MONITORINFO); @@ -266,7 +266,7 @@ void Utils::GetScreenSize(HWND hwnd, LONG &screenWidth, LONG &screenHeight) void Utils::GetScreenSize(HWND hwnd, int &screenWidth, int &screenHeight) { - LONG Width, Height; + LONG Width = 0, Height = 0; GetScreenSize(hwnd, Width, Height); screenWidth = Width; screenHeight = Height; @@ -782,9 +782,6 @@ bool Fullscreen::IsThreadRunning() // Stop thread void Fullscreen::StopThread() { - // Set flag to stop thread - m_StopThreadFlag = true; - // Wait for thread to exit if (IsThreadRunning()) { diff --git a/Utils/License.txt b/Utils/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Utils/License.txt +++ b/Utils/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Utils/MyStrings.cpp b/Utils/MyStrings.cpp index df5c56d9..3b7d4fa5 100644 --- a/Utils/MyStrings.cpp +++ b/Utils/MyStrings.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Utils/Utils.cpp b/Utils/Utils.cpp index 9de5638f..897c2a1a 100644 --- a/Utils/Utils.cpp +++ b/Utils/Utils.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -121,7 +121,6 @@ namespace Utils std::vector custom_dll; // Used for custom dll's and asi plugins // Function declarations - DWORD_PTR GetProcessMask(); void InitializeASI(HMODULE hModule); void FindFiles(WIN32_FIND_DATA*); void *memmem(const void *l, size_t l_len, const void *s, size_t s_len); @@ -162,59 +161,6 @@ void Utils::Shell(const char* fileName) return; } -// Check the number CPU cores is being used by the process -DWORD Utils::GetCoresUsedByProcess() -{ - int numCores = 0; - DWORD_PTR ProcessAffinityMask, SystemAffinityMask; - if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask)) - { - while (ProcessAffinityMask) - { - if (ProcessAffinityMask & 1) - { - ++numCores; - } - ProcessAffinityMask >>= 1; - } - } - return numCores; -} - -// Get processor mask -DWORD_PTR Utils::GetProcessMask() -{ - static DWORD_PTR nMask = 0; - if (nMask) - { - return nMask; - } - - DWORD_PTR ProcessAffinityMask, SystemAffinityMask; - if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask)) - { - DWORD_PTR AffinityLow = 1; - while (AffinityLow && (AffinityLow & SystemAffinityMask) == 0) - { - AffinityLow <<= 1; - } - if (AffinityLow) - { - nMask = ((AffinityLow << (Config.SingleProcAffinity - 1)) & SystemAffinityMask) ? (AffinityLow << (Config.SingleProcAffinity - 1)) : AffinityLow; - } - } - - Logging::Log() << __FUNCTION__ << " Setting CPU mask: " << Logging::hex(nMask); - return nMask; -} - -// Set Single Core Affinity -void Utils::SetProcessAffinity() -{ - Logging::Log() << "Setting SingleCoreAffinity..."; - SetProcessAffinityMask(GetCurrentProcess(), GetProcessMask()); -} - // Sets application DPI aware which disables DPI virtulization/High DPI scaling for this process void Utils::DisableHighDPIScaling() { @@ -398,7 +344,7 @@ HANDLE WINAPI Utils::kernel_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttribute if (!CreateThread) { - return FALSE; + return nullptr; } // Check the current stack size, and if it's too small, increase it @@ -408,6 +354,25 @@ HANDLE WINAPI Utils::kernel_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttribute } // Call the original CreateThread with modified parameters + if (Config.SingleProcAffinity) + { + DWORD ThreadID = 0; + if (!lpThreadId) lpThreadId = &ThreadID; + + HANDLE thread = CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags | CREATE_SUSPENDED, lpThreadId); + + if (thread) + { + SetThreadAffinity(*lpThreadId); + if (!(dwCreationFlags & CREATE_SUSPENDED)) + { + ResumeThread(thread); + } + } + + return thread; + } + return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId); } @@ -486,19 +451,32 @@ SIZE_T WINAPI Utils::kernel_HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) } // Your existing exception handler function -LONG WINAPI Utils::Vectored_Exception_Handler(EXCEPTION_POINTERS* exception) +LONG WINAPI Utils::Vectored_Exception_Handler(EXCEPTION_POINTERS* ExceptionInfo) { - if (exception && - exception->ContextRecord && - exception->ExceptionRecord && - exception->ExceptionRecord->ExceptionAddress && - exception->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) + if (ExceptionInfo && + ExceptionInfo->ContextRecord && + ExceptionInfo->ExceptionRecord && + ExceptionInfo->ExceptionRecord->ExceptionAddress && + ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) { - size_t size = Disasm::getInstructionLength(exception->ExceptionRecord->ExceptionAddress); + size_t size = Disasm::getInstructionLength(ExceptionInfo->ExceptionRecord->ExceptionAddress); if (size) { - exception->ContextRecord->Eip += size; + static DWORD count = 0; + if (count++ < 10) + { + char moduleName[MAX_PATH]; + GetModuleFromAddress(ExceptionInfo->ExceptionRecord->ExceptionAddress, moduleName, MAX_PATH); + + Logging::Log() << "Skipping exception:" << + " code=" << Logging::hex(ExceptionInfo->ExceptionRecord->ExceptionCode) << + " flags=" << Logging::hex(ExceptionInfo->ExceptionRecord->ExceptionFlags) << + " addr=" << ExceptionInfo->ExceptionRecord->ExceptionAddress << + " module=" << moduleName; + } + + ExceptionInfo->ContextRecord->Eip += size; return EXCEPTION_CONTINUE_EXECUTION; } } @@ -1326,6 +1304,34 @@ void Utils::WaitForWindowActions(HWND hWnd, DWORD Loops) } } +void Utils::GetModuleFromAddress(void* address, char* module, const size_t size) +{ + if (!module || size == 0) + { + return; + } + + module[0] = '\0'; // Ensure null-termination in case of failure + + HMODULE hModule = NULL; + HANDLE hProcess = GetCurrentProcess(); + MEMORY_BASIC_INFORMATION mbi; + + // Query the memory region of the given address + if (VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi))) + { + hModule = (HMODULE)mbi.AllocationBase; + + if (hModule) + { + if (GetModuleFileNameA(hModule, module, static_cast(size)) == 0) + { + module[0] = '\0'; // Ensure null-termination if GetModuleFileNameA() fails + } + } + } +} + bool Utils::SetWndProcFilter(HWND hWnd) { // Check window handle diff --git a/Utils/Utils.h b/Utils/Utils.h index c9f35411..eef0a639 100644 --- a/Utils/Utils.h +++ b/Utils/Utils.h @@ -22,8 +22,6 @@ namespace Utils void Shell(const char*); void DisableHighDPIScaling(); - DWORD GetCoresUsedByProcess(); - void SetProcessAffinity(); FARPROC GetProcAddress(HMODULE hModule, LPCSTR FunctionName, FARPROC SetReturnValue); FARPROC WINAPI GetProcAddressHandler(HMODULE hModule, LPSTR lpProcName); DWORD WINAPI GetModuleFileNameAHandler(HMODULE hModule, LPSTR lpFilename, DWORD nSize); @@ -35,7 +33,7 @@ namespace Utils SIZE_T WINAPI kernel_HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); void HookExceptionHandler(); void UnHookExceptionHandler(); - LONG WINAPI Vectored_Exception_Handler(EXCEPTION_POINTERS* exception); + LONG WINAPI Vectored_Exception_Handler(EXCEPTION_POINTERS* ExceptionInfo); void AddHandleToVector(HMODULE dll, const char *name); HMODULE LoadLibrary(const char *dllname, bool EnableLogging = false); void LoadCustomDll(); @@ -64,13 +62,19 @@ namespace Utils DWORD GetThreadIDByHandle(HANDLE hThread); void DisableGameUX(); void WaitForWindowActions(HWND hWnd, DWORD Loops); + void GetModuleFromAddress(void* address, char* module, const size_t size); bool SetWndProcFilter(HWND hWnd); bool RestoreWndProcFilter(HWND hWnd); - void GetScreenSize(HWND hwnd, LONG &screenWidth, LONG &screenHeight); + void GetScreenSize(HWND hwnd, volatile LONG &screenWidth, volatile LONG &screenHeight); void GetScreenSize(HWND hwnd, int &screenWidth, int &screenHeight); void GetDesktopRect(HWND hWnd, RECT& screenRect); HRESULT GetVideoRam(UINT AdapterNo, DWORD& TotalMemory); // Adapters start numbering from '1', based on "Win32_VideoController" WMI class and "DeviceID" property. + // CPU Affinity + void SetProcessAffinity(); + void SetThreadAffinity(DWORD threadId); + void ApplyThreadAffinity(); + inline void BusyWaitYield(DWORD RemainingMS) { static bool supports_pause = []() { diff --git a/Utils/WriteMemory.cpp b/Utils/WriteMemory.cpp index 3bf057ce..cb239c69 100644 --- a/Utils/WriteMemory.cpp +++ b/Utils/WriteMemory.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -21,7 +21,7 @@ namespace WriteMemory { // Declare variables - bool m_StopThreadFlag = false; + const bool& m_StopThreadFlag = Config.Exiting; bool m_ThreadRunningFlag = false; HANDLE m_hThread = nullptr; DWORD m_dwThreadID = 0; @@ -218,9 +218,6 @@ bool WriteMemory::IsThreadRunning() // Stop thread void WriteMemory::StopThread() { - // Set flag to stop thread - m_StopThreadFlag = true; - // Wait for thread to exit if (IsThreadRunning()) { diff --git a/Wrappers/License.txt b/Wrappers/License.txt index 53f73bd0..9cdb9d78 100644 --- a/Wrappers/License.txt +++ b/Wrappers/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/Wrappers/wrapper.cpp b/Wrappers/wrapper.cpp index 743fb9b9..16773d1c 100644 --- a/Wrappers/wrapper.cpp +++ b/Wrappers/wrapper.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d8/License.txt b/d3d8/License.txt index 53f73bd0..9cdb9d78 100644 --- a/d3d8/License.txt +++ b/d3d8/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d8/d3d8.cpp b/d3d8/d3d8.cpp index bd58d999..c4e72821 100644 --- a/d3d8/d3d8.cpp +++ b/d3d8/d3d8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/DebugOverlay.cpp b/d3d9/DebugOverlay.cpp index bfd7d9c5..99204af4 100644 --- a/d3d9/DebugOverlay.cpp +++ b/d3d9/DebugOverlay.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -18,7 +18,7 @@ #include "DebugOverlay.h" #include -#include "d3d9\d3d9External.h" +#include "d3d9.h" #include "GDI\WndProc.h" #define IMGUI_DEFINE_MATH_OPERATORS diff --git a/d3d9/IDirect3D9Ex.cpp b/d3d9/IDirect3D9Ex.cpp index be7eb2ed..23593771 100644 --- a/d3d9/IDirect3D9Ex.cpp +++ b/d3d9/IDirect3D9Ex.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -17,6 +17,10 @@ #include "d3d9.h" #include "GDI\WndProc.h" +// Initial screen resolution +volatile LONG InitWidth = 0; +volatile LONG InitHeight = 0; + AddressLookupTableD3d9 ProxyAddressLookupTable9; // Just used for m_IDirect3D9Ex interfaces only void AdjustWindow(HWND MainhWnd, LONG displayWidth, LONG displayHeight, bool isWindowed); @@ -109,7 +113,7 @@ HRESULT m_IDirect3D9Ex::EnumAdapterModes(THIS_ UINT Adapter, D3DFORMAT Format, U { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (Config.OverrideRefreshRate) + if (Config.LimitDisplayModeCount || Config.OverrideRefreshRate) { if (!pMode) { @@ -170,6 +174,23 @@ UINT m_IDirect3D9Ex::GetAdapterModeCache(THIS_ UINT Adapter, D3DFORMAT Format, b return 0; } + // For games that require limited resolution return + const SIZE LimitedResolutionList[] = { + { 512, 384 }, + { 640, 400 }, + { 640, 480 }, + { 720, 480 }, + { 800, 600 }, + { 1024, 768 }, + { 1152, 864 }, + { 1280, 720 }, + { 1280, 1024 }, + { 1366, 768 }, + { 1440, 900 }, + { 1600, 1200 }, + { InitWidth, InitHeight }, + { (LONG)Config.CustomDisplayWidth, (LONG)Config.CustomDisplayHeight } }; + for (auto& entry : AdapterModesCache) { if (entry.Adapter == Adapter && entry.IsEx == IsEx && @@ -202,13 +223,15 @@ UINT m_IDirect3D9Ex::GetAdapterModeCache(THIS_ UINT Adapter, D3DFORMAT Format, b UINT RefreshRate = 0; std::vector NewDisplayModeList; + // Cache all adapter modes for (UINT x = 0; x < Count; x++) { D3DDISPLAYMODEEX_CONVERT DisplayMode; if (SUCCEEDED(!IsEx ? ProxyInterface->EnumAdapterModes(Adapter, Format, x, DisplayMode.Ptr()) : ProxyInterfaceEx->EnumAdapterModesEx(Adapter, pFilter, x, DisplayMode.PtrEx()))) { - if (RefreshRate == 0 || std::abs((INT)Config.OverrideRefreshRate - (INT)DisplayMode.RefreshRate) < std::abs((INT)Config.OverrideRefreshRate - (INT)RefreshRate)) + if (Config.OverrideRefreshRate && + (RefreshRate == 0 || std::abs((INT)Config.OverrideRefreshRate - (INT)DisplayMode.RefreshRate) < std::abs((INT)Config.OverrideRefreshRate - (INT)RefreshRate))) { RefreshRate = DisplayMode.RefreshRate; } @@ -216,9 +239,27 @@ UINT m_IDirect3D9Ex::GetAdapterModeCache(THIS_ UINT Adapter, D3DFORMAT Format, b } } + // Filter cached adapter modes for (auto& entry : NewDisplayModeList) { - if (entry.RefreshRate == RefreshRate) + // Check if resolution has already been sent + bool IsResolutionAlreadySent = std::any_of(NewCacheEntry.DisplayModeList.begin(), NewCacheEntry.DisplayModeList.end(), + [&](const auto& res) { + return (res.Width == entry.Width && res.Height == entry.Height && res.RefreshRate == entry.RefreshRate); + }); + + // Check if the resolution is on the LimitedResolutionList + bool IsResolutionSupported = (!Config.LimitDisplayModeCount || + std::any_of(std::begin(LimitedResolutionList), std::end(LimitedResolutionList), + [&](const auto& res) { + return ((DWORD)res.cx == entry.Width && (DWORD)res.cy == entry.Height); + })); + + // Check if refresh rate is suported + bool IsRefreshSupported = (!Config.OverrideRefreshRate || entry.RefreshRate == RefreshRate); + + // Store entry + if (!IsResolutionAlreadySent && IsResolutionSupported && IsRefreshSupported) { NewCacheEntry.DisplayModeList.push_back(entry); } @@ -233,7 +274,7 @@ UINT m_IDirect3D9Ex::GetAdapterModeCount(THIS_ UINT Adapter, D3DFORMAT Format) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (Config.OverrideRefreshRate) + if (Config.LimitDisplayModeCount || Config.OverrideRefreshRate) { return GetAdapterModeCache(Adapter, Format, false, nullptr); } @@ -282,7 +323,7 @@ HRESULT m_IDirect3D9Ex::CheckDeviceMultiSampleType(THIS_ UINT Adapter, D3DDEVTYP if (Config.EnableWindowMode) { - Windowed = true; + Windowed = TRUE; } return ProxyInterface->CheckDeviceMultiSampleType(Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels); @@ -294,7 +335,7 @@ HRESULT m_IDirect3D9Ex::CheckDeviceType(UINT Adapter, D3DDEVTYPE CheckType, D3DF if (Config.EnableWindowMode) { - Windowed = true; + Windowed = TRUE; } return ProxyInterface->CheckDeviceType(Adapter, CheckType, DisplayFormat, BackBufferFormat, Windowed); @@ -322,6 +363,7 @@ HRESULT m_IDirect3D9Ex::CreateDeviceT(DEVICEDETAILS& DeviceDetails, UINT Adapter WndDataStruct->IsDirect3D9 = true; WndDataStruct->IsCreatingDevice = true; WndDataStruct->IsExclusiveMode = !pPresentationParameters->Windowed; + DeviceDetails.IsDirectDrawDevice = WndDataStruct->IsDirectDraw; } BehaviorFlags = UpdateBehaviorFlags(BehaviorFlags); @@ -339,6 +381,8 @@ HRESULT m_IDirect3D9Ex::CreateDeviceT(DEVICEDETAILS& DeviceDetails, UINT Adapter CopyMemory(&d3dpp, pPresentationParameters, sizeof(D3DPRESENT_PARAMETERS)); UpdatePresentParameter(&d3dpp, hFocusWindow, DeviceDetails, ForceFullscreen, true); + bool IsWindowMode = d3dpp.Windowed != FALSE; + // Check for AntiAliasing if (Config.AntiAliasing != 0) { @@ -358,7 +402,7 @@ HRESULT m_IDirect3D9Ex::CreateDeviceT(DEVICEDETAILS& DeviceDetails, UINT Adapter UpdatePresentParameterForMultisample(&d3dpp, Samples, (QualityLevels > 0) ? QualityLevels - 1 : 0); // Create Device - hr = CreateDeviceT(Adapter, DeviceType, hFocusWindow, BehaviorFlags, &d3dpp, (d3dpp.Windowed) ? nullptr : pFullscreenDisplayMode, ppReturnedDeviceInterface); + hr = CreateDeviceT(Adapter, DeviceType, hFocusWindow, BehaviorFlags, &d3dpp, (d3dpp.Windowed ? nullptr : pFullscreenDisplayMode), ppReturnedDeviceInterface); // Check if device was created successfully if (SUCCEEDED(hr)) @@ -384,7 +428,7 @@ HRESULT m_IDirect3D9Ex::CreateDeviceT(DEVICEDETAILS& DeviceDetails, UINT Adapter UpdatePresentParameter(&d3dpp, hFocusWindow, DeviceDetails, ForceFullscreen, false); // Create Device - hr = CreateDeviceT(Adapter, DeviceType, hFocusWindow, BehaviorFlags, &d3dpp, (d3dpp.Windowed) ? nullptr : pFullscreenDisplayMode, ppReturnedDeviceInterface); + hr = CreateDeviceT(Adapter, DeviceType, hFocusWindow, BehaviorFlags, &d3dpp, (d3dpp.Windowed ? nullptr : pFullscreenDisplayMode), ppReturnedDeviceInterface); } if (SUCCEEDED(hr)) @@ -393,7 +437,7 @@ HRESULT m_IDirect3D9Ex::CreateDeviceT(DEVICEDETAILS& DeviceDetails, UINT Adapter if (WndDataStruct && WndDataStruct->IsExclusiveMode) { - d3dpp.Windowed = false; + d3dpp.Windowed = FALSE; } if (MultiSampleFlag) @@ -403,6 +447,8 @@ HRESULT m_IDirect3D9Ex::CreateDeviceT(DEVICEDETAILS& DeviceDetails, UINT Adapter DeviceDetails.DeviceMultiSampleQuality = d3dpp.MultiSampleQuality; } + DeviceDetails.IsWindowMode = IsWindowMode; + CopyMemory(pPresentationParameters, &d3dpp, sizeof(D3DPRESENT_PARAMETERS)); } @@ -452,7 +498,7 @@ UINT m_IDirect3D9Ex::GetAdapterModeCountEx(THIS_ UINT Adapter, CONST D3DDISPLAYM return 0; } - if (Config.OverrideRefreshRate) + if (Config.LimitDisplayModeCount || Config.OverrideRefreshRate) { return GetAdapterModeCache(Adapter, D3DFMT_UNKNOWN, true, pFilter); } @@ -470,7 +516,7 @@ HRESULT m_IDirect3D9Ex::EnumAdapterModesEx(THIS_ UINT Adapter, CONST D3DDISPLAYM return D3DERR_INVALIDCALL; } - if (Config.OverrideRefreshRate) + if (Config.LimitDisplayModeCount || Config.OverrideRefreshRate) { if (!pMode) { @@ -627,7 +673,7 @@ void UpdatePresentParameter(D3DPRESENT_PARAMETERS* pPresentationParameters, HWND // Set windowed mode if enabled if (ForceExclusiveFullscreen) { - pPresentationParameters->Windowed = false; + pPresentationParameters->Windowed = FALSE; if (!pPresentationParameters->FullScreen_RefreshRateInHz) { pPresentationParameters->FullScreen_RefreshRateInHz = Utils::GetRefreshRate(DeviceDetails.DeviceWindow); @@ -639,7 +685,7 @@ void UpdatePresentParameter(D3DPRESENT_PARAMETERS* pPresentationParameters, HWND } else if (Config.EnableWindowMode) { - pPresentationParameters->Windowed = true; + pPresentationParameters->Windowed = TRUE; pPresentationParameters->FullScreen_RefreshRateInHz = 0; } diff --git a/d3d9/IDirect3DCubeTexture9.cpp b/d3d9/IDirect3DCubeTexture9.cpp index e33f1a0d..693869c7 100644 --- a/d3d9/IDirect3DCubeTexture9.cpp +++ b/d3d9/IDirect3DCubeTexture9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DDevice9Ex.cpp b/d3d9/IDirect3DDevice9Ex.cpp index f3b4ea48..3118bc62 100644 --- a/d3d9/IDirect3DDevice9Ex.cpp +++ b/d3d9/IDirect3DDevice9Ex.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -15,8 +15,6 @@ */ #include "d3d9.h" -#include "d3dx9.h" -#include "d3d9\d3d9External.h" #include "ddraw\Shaders\GammaPixelShader.h" #include "GDI\WndProc.h" #include "Utils\Utils.h" @@ -136,7 +134,7 @@ ULONG m_IDirect3DDevice9Ex::Release() return ref; } -inline void m_IDirect3DDevice9Ex::ClearVars(D3DPRESENT_PARAMETERS* pPresentationParameters) const +void m_IDirect3DDevice9Ex::ClearVars(D3DPRESENT_PARAMETERS* pPresentationParameters) const { UNREFERENCED_PARAMETER(pPresentationParameters); @@ -150,7 +148,7 @@ inline void m_IDirect3DDevice9Ex::ClearVars(D3DPRESENT_PARAMETERS* pPresentation } template -inline HRESULT m_IDirect3DDevice9Ex::ResetT(T func, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) +HRESULT m_IDirect3DDevice9Ex::ResetT(T func, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) { if (!pPresentationParameters) { @@ -190,6 +188,8 @@ inline HRESULT m_IDirect3DDevice9Ex::ResetT(T func, D3DPRESENT_PARAMETERS* pPres CopyMemory(&d3dpp, pPresentationParameters, sizeof(D3DPRESENT_PARAMETERS)); UpdatePresentParameter(&d3dpp, nullptr, SHARED, ForceFullscreen, true); + bool IsWindowMode = d3dpp.Windowed != FALSE; + // Test for Multisample if (SHARED.DeviceMultiSampleFlag) { @@ -237,9 +237,11 @@ inline HRESULT m_IDirect3DDevice9Ex::ResetT(T func, D3DPRESENT_PARAMETERS* pPres if (WndDataStruct && WndDataStruct->IsExclusiveMode) { - d3dpp.Windowed = false; + d3dpp.Windowed = FALSE; } + SHARED.IsWindowMode = IsWindowMode; + CopyMemory(pPresentationParameters, &d3dpp, sizeof(D3DPRESENT_PARAMETERS)); ClearVars(pPresentationParameters); @@ -262,9 +264,11 @@ HRESULT m_IDirect3DDevice9Ex::Reset(D3DPRESENT_PARAMETERS *pPresentationParamete return ResetT(nullptr, pPresentationParameters); } -HRESULT m_IDirect3DDevice9Ex::EndScene() +HRESULT m_IDirect3DDevice9Ex::CallEndScene() { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // clear Begin/End Scene flags + SHARED.IsInScene = false; + SHARED.BeginSceneCalled = false; #ifdef ENABLE_DEBUGOVERLAY if (Config.EnableImgui && DOverlay.Getd3d9Device() == ProxyInterface) @@ -276,6 +280,25 @@ HRESULT m_IDirect3DDevice9Ex::EndScene() return ProxyInterface->EndScene(); } +HRESULT m_IDirect3DDevice9Ex::EndScene() +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.ForceSingleBeginEndScene) + { + if (SHARED.IsInScene) + { + SHARED.IsInScene = false; + + return D3D_OK; + } + + return D3DERR_INVALIDCALL; + } + + return CallEndScene(); +} + void m_IDirect3DDevice9Ex::SetCursorPosition(int X, int Y, DWORD Flags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -725,7 +748,7 @@ HRESULT m_IDirect3DDevice9Ex::SetTransform(D3DTRANSFORMSTATETYPE State, CONST D3 return hr; } -inline HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) +HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) { Logging::LogDebug() << __FUNCTION__; @@ -738,8 +761,13 @@ inline HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) } else { - ProxyInterface->CreateTexture(256, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &SHARED.GammaLUTTexture, nullptr); SHARED.UsingShader32f = false; + HRESULT hr = ProxyInterface->CreateTexture(256, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &SHARED.GammaLUTTexture, nullptr); + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to create gamma LUD texture!"); + return hr; + } } } @@ -775,7 +803,7 @@ inline HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) return D3D_OK; } -inline LPDIRECT3DPIXELSHADER9 m_IDirect3DDevice9Ex::GetGammaPixelShader() const +LPDIRECT3DPIXELSHADER9 m_IDirect3DDevice9Ex::GetGammaPixelShader() const { // Create pixel shaders if (!SHARED.gammaPixelShader) @@ -785,11 +813,14 @@ inline LPDIRECT3DPIXELSHADER9 m_IDirect3DDevice9Ex::GetGammaPixelShader() const return SHARED.gammaPixelShader; } -inline void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() +void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() { if (!SHARED.GammaLUTTexture) { - SetBrightnessLevel(SHARED.RampData); + if (FAILED(SetBrightnessLevel(SHARED.RampData))) + { + return; + } } // Set shader @@ -801,8 +832,8 @@ inline void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() } // Get current backbuffer - IDirect3DSurface9* pBackBuffer = nullptr; - if (FAILED(ProxyInterface->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) + ComPtr pBackBuffer; + if (FAILED(ProxyInterface->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, pBackBuffer.GetAddressOf()))) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to get back buffer!"); return; @@ -816,61 +847,28 @@ inline void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() if (FAILED(ProxyInterface->CreateTexture(desc.Width, desc.Height, 1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT, &SHARED.ScreenCopyTexture, nullptr))) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to create screen copy texture!"); - pBackBuffer->Release(); return; } } - IDirect3DSurface9* pCopySurface = nullptr; - SHARED.ScreenCopyTexture->GetSurfaceLevel(0, &pCopySurface); - if (FAILED(ProxyInterface->StretchRect(pBackBuffer, nullptr, pCopySurface, nullptr, D3DTEXF_NONE))) + ComPtr pCopySurface; + if (FAILED(SHARED.ScreenCopyTexture->GetSurfaceLevel(0, pCopySurface.GetAddressOf()))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to get surface level from screen copy texture!"); + return; + } + if (FAILED(ProxyInterface->StretchRect(pBackBuffer.Get(), nullptr, pCopySurface.Get(), nullptr, D3DTEXF_NONE))) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to copy render target!"); + return; } - pCopySurface->Release(); - - // Render states - DWORD rsLighting, rsAlphaTestEnable, rsAlphaBlendEnable, rsFogEnable, rsZEnable, rsZWriteEnable, reStencilEnable; - ProxyInterface->GetRenderState(D3DRS_LIGHTING, &rsLighting); - ProxyInterface->GetRenderState(D3DRS_ALPHATESTENABLE, &rsAlphaTestEnable); - ProxyInterface->GetRenderState(D3DRS_ALPHABLENDENABLE, &rsAlphaBlendEnable); - ProxyInterface->GetRenderState(D3DRS_FOGENABLE, &rsFogEnable); - ProxyInterface->GetRenderState(D3DRS_ZENABLE, &rsZEnable); - ProxyInterface->GetRenderState(D3DRS_ZWRITEENABLE, &rsZWriteEnable); - ProxyInterface->GetRenderState(D3DRS_STENCILENABLE, &reStencilEnable); - ProxyInterface->SetRenderState(D3DRS_LIGHTING, FALSE); - ProxyInterface->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_FOGENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_ZENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_STENCILENABLE, FALSE); - - // Texture states - DWORD tsColorOP, tsColorArg1, tsColorArg2, tsAlphaOP; - ProxyInterface->GetTextureStageState(0, D3DTSS_COLOROP, &tsColorOP); - ProxyInterface->GetTextureStageState(0, D3DTSS_COLORARG1, &tsColorArg1); - ProxyInterface->GetTextureStageState(0, D3DTSS_COLORARG2, &tsColorArg2); - ProxyInterface->GetTextureStageState(0, D3DTSS_ALPHAOP, &tsAlphaOP); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); - ProxyInterface->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - - // Sampler states - DWORD ss1addressU, ss1addressV; - ProxyInterface->GetSamplerState(1, D3DSAMP_ADDRESSU, &ss1addressU); - ProxyInterface->GetSamplerState(1, D3DSAMP_ADDRESSV, &ss1addressV); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + // Clear render target + ProxyInterface->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0); // Set texture ProxyInterface->SetTexture(0, SHARED.ScreenCopyTexture); ProxyInterface->SetTexture(1, SHARED.GammaLUTTexture); - for (int x = 2; x < 8; x++) - { - ProxyInterface->SetTexture(x, nullptr); - } // Set shader ProxyInterface->SetPixelShader(pShader); @@ -897,38 +895,23 @@ inline void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to draw primitive!"); } - // Reset textures - ProxyInterface->SetTexture(0, nullptr); - ProxyInterface->SetTexture(1, nullptr); - - // Reset pixel shader + // Clear shader ProxyInterface->SetPixelShader(nullptr); - // Cleanup - pBackBuffer->Release(); - - // Restore sampler states - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSU, ss1addressU); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSV, ss1addressV); - - // Restore render states - ProxyInterface->SetRenderState(D3DRS_LIGHTING, rsLighting); - ProxyInterface->SetRenderState(D3DRS_ALPHATESTENABLE, rsAlphaTestEnable); - ProxyInterface->SetRenderState(D3DRS_ALPHABLENDENABLE, rsAlphaBlendEnable); - ProxyInterface->SetRenderState(D3DRS_FOGENABLE, rsFogEnable); - ProxyInterface->SetRenderState(D3DRS_ZENABLE, rsZEnable); - ProxyInterface->SetRenderState(D3DRS_ZWRITEENABLE, rsZWriteEnable); - ProxyInterface->SetRenderState(D3DRS_STENCILENABLE, reStencilEnable); - - // Restore texture states - ProxyInterface->SetTextureStageState(0, D3DTSS_COLOROP, tsColorOP); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG1, tsColorArg1); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG2, tsColorArg2); - ProxyInterface->SetTextureStageState(0, D3DTSS_ALPHAOP, tsAlphaOP); + // Clear texture + ProxyInterface->SetTexture(0, nullptr); + ProxyInterface->SetTexture(1, nullptr); } -inline void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) +void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) { + ScopedCriticalSection ThreadLock(&SHARED.d9cs); + + if (SHARED.DontReleaseResources) + { + return; + } + if (SHARED.GammaLUTTexture) { ULONG ref = SHARED.GammaLUTTexture->Release(); @@ -974,6 +957,36 @@ inline void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) SHARED.BlankTexture = nullptr; } + if (SHARED.pFont) + { + ULONG ref = SHARED.pFont->Release(); + if (ref) + { + Logging::Log() << __FUNCTION__ << " Error: there is still a reference to 'pFont' " << ref; + } + SHARED.pFont = nullptr; + } + + if (SHARED.pSprite) + { + ULONG ref = SHARED.pSprite->Release(); + if (ref) + { + Logging::Log() << __FUNCTION__ << " Error: there is still a reference to 'pSprite' " << ref; + } + SHARED.pSprite = nullptr; + } + + if (SHARED.pStateBlock) + { + ULONG ref = SHARED.pStateBlock->Release(); + if (ref) + { + Logging::Log() << __FUNCTION__ << " Error: there is still a reference to 'pStateBlock' " << ref; + } + SHARED.pStateBlock = nullptr; + } + if (isReset) { // Clear all state blocks on reset @@ -983,6 +996,10 @@ inline void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) SHARED.isAnisotropySet = false; SHARED.AnisotropyDisabledFlag = false; + // clear Begin/End Scene flags + SHARED.IsInScene = false; + SHARED.BeginSceneCalled = false; + // For environment map cube std::fill(std::begin(SHARED.isTextureMapCube), std::end(SHARED.isTextureMapCube), false); std::fill(std::begin(SHARED.isTransformMapCube), std::end(SHARED.isTransformMapCube), false); @@ -1009,8 +1026,13 @@ void m_IDirect3DDevice9Ex::GetGammaRamp(THIS_ UINT iSwapChain, D3DGAMMARAMP* pRa { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (pRamp) + if (pRamp && Config.WindowModeGammaShader && SHARED.IsWindowMode) { + if (iSwapChain) + { + LOG_LIMIT(3, __FUNCTION__ << " Warning: Gamma support for swapchains not implemented: " << iSwapChain); + } + memcpy(pRamp, &SHARED.RampData, sizeof(D3DGAMMARAMP)); return; } @@ -1022,8 +1044,13 @@ void m_IDirect3DDevice9Ex::SetGammaRamp(THIS_ UINT iSwapChain, DWORD Flags, CONS { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (pRamp) + if (pRamp && Config.WindowModeGammaShader && SHARED.IsWindowMode) { + if (iSwapChain) + { + LOG_LIMIT(3, __FUNCTION__ << " Warning: Gamma support for swapchains not implemented: " << iSwapChain); + } + SHARED.IsGammaSet = false; memcpy(&SHARED.RampData, pRamp, sizeof(D3DGAMMARAMP)); @@ -1275,17 +1302,121 @@ HRESULT m_IDirect3DDevice9Ex::SetPixelShader(THIS_ IDirect3DPixelShader9* pShade return ProxyInterface->SetPixelShader(pShader); } -HRESULT m_IDirect3DDevice9Ex::Present(CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion) +void m_IDirect3DDevice9Ex::ApplyPresentFixes() { - Utils::ResetInvalidFPUState(); // Check FPU state before presenting + bool CalledBeginScene = false; - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + if (SHARED.IsGammaSet || Config.ShowFPSCounter) + { + ScopedCriticalSection ThreadLock(&SHARED.d9cs); + ScopedFlagSet AutoSet(SHARED.DontReleaseResources); - if (SHARED.IsGammaSet) + // Create state block + if (SHARED.pStateBlock || SUCCEEDED(ProxyInterface->CreateStateBlock(D3DSBT_ALL, &SHARED.pStateBlock))) + { + if (!Config.ForceSingleBeginEndScene || !SHARED.BeginSceneCalled) + { + CalledBeginScene = true; + CallBeginScene(); + } + + // Capture modified state + SHARED.pStateBlock->Capture(); + + // Set render states + ProxyInterface->SetRenderState(D3DRS_LIGHTING, FALSE); + ProxyInterface->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + ProxyInterface->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + ProxyInterface->SetRenderState(D3DRS_FOGENABLE, FALSE); + ProxyInterface->SetRenderState(D3DRS_ZENABLE, FALSE); + ProxyInterface->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + ProxyInterface->SetRenderState(D3DRS_STENCILENABLE, FALSE); + ProxyInterface->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + ProxyInterface->SetRenderState(D3DRS_CLIPPING, FALSE); + + // Set texture states + ProxyInterface->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + ProxyInterface->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + // Set sampler states + for (UINT x = 0; x < 2; x++) + { + ProxyInterface->SetSamplerState(x, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + ProxyInterface->SetSamplerState(x, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + // Set viewport + D3DVIEWPORT9 Viewport = { 0, 0, static_cast(SHARED.BufferWidth), static_cast(SHARED.BufferHeight), 0.0f, 1.0f }; + ProxyInterface->SetViewport(&Viewport); + + // Set trasform + D3DMATRIX identityMatrix = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + ProxyInterface->SetTransform(D3DTS_WORLD, &identityMatrix); + ProxyInterface->SetTransform(D3DTS_VIEW, &identityMatrix); + ProxyInterface->SetTransform(D3DTS_PROJECTION, &identityMatrix); + + // Set shaders + ProxyInterface->SetPixelShader(nullptr); + ProxyInterface->SetVertexShader(nullptr); + + // Set textures + for (int x = 0; x < 8; x++) + { + ProxyInterface->SetTexture(x, nullptr); + } + + // Backup the current render target + ComPtr pOldRenderTarget; + if (SUCCEEDED(ProxyInterface->GetRenderTarget(0, pOldRenderTarget.GetAddressOf()))) + { + ComPtr pBackBuffer; + if (SUCCEEDED(ProxyInterface->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, pBackBuffer.GetAddressOf()))) + { + if (pOldRenderTarget.Get() != pBackBuffer.Get()) + { + ProxyInterface->SetRenderTarget(0, pBackBuffer.Get()); + } + } + } + + // Apply brightness level + if (SHARED.IsGammaSet) + { + ApplyBrightnessLevel(); + } + + // Draw FPS counter to screen + if (Config.ShowFPSCounter) + { + RECT rect = { 0, 0, SHARED.BufferWidth, SHARED.BufferHeight }; + if (SHARED.IsDirectDrawDevice && SHARED.IsWindowMode) + { + GetClientRect(SHARED.DeviceWindow, &rect); + } + DrawFPS(static_cast(SHARED.AverageFPSCounter), rect, Config.ShowFPSCounter); + } + + // Restore render target + if (pOldRenderTarget) + { + ProxyInterface->SetRenderTarget(0, pOldRenderTarget.Get()); + } + + // Apply state block + SHARED.pStateBlock->Apply(); + } + } + + if (CalledBeginScene || (Config.ForceSingleBeginEndScene && SHARED.BeginSceneCalled)) { - ProxyInterface->BeginScene(); - ApplyBrightnessLevel(); - ProxyInterface->EndScene(); + CallEndScene(); } if (Config.LimitPerFrameFPS) @@ -1293,23 +1424,30 @@ HRESULT m_IDirect3DDevice9Ex::Present(CONST RECT *pSourceRect, CONST RECT *pDest LimitFrameRate(); } + // Check FPU state before presenting + Utils::ResetInvalidFPUState(); +} + +HRESULT m_IDirect3DDevice9Ex::Present(CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + ApplyPresentFixes(); + HRESULT hr = ProxyInterface->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); if (SUCCEEDED(hr)) { -#ifdef ENABLE_DEBUGOVERLAY - if (Config.EnableImgui) + if (Config.ShowFPSCounter || Config.EnableImgui) { CalculateFPS(); - DOverlay.SetFPSCount(SHARED.AverageFPSCounter); } -#endif } return hr; } -inline void m_IDirect3DDevice9Ex::ApplyDrawFixes() +void m_IDirect3DDevice9Ex::ApplyDrawFixes() { // CacheClipPlane if (Config.CacheClipPlane && SHARED.isClipPlaneSet) @@ -1366,6 +1504,26 @@ HRESULT m_IDirect3DDevice9Ex::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UI return ProxyInterface->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); } +HRESULT m_IDirect3DDevice9Ex::CallBeginScene() +{ + HRESULT hr = ProxyInterface->BeginScene(); + + if (SUCCEEDED(hr)) + { + SHARED.IsInScene = true; + SHARED.BeginSceneCalled = true; + +#ifdef ENABLE_DEBUGOVERLAY + if (Config.EnableImgui) + { + DOverlay.BeginScene(); + } +#endif + } + + return hr; +} + HRESULT m_IDirect3DDevice9Ex::BeginScene() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -1378,37 +1536,45 @@ HRESULT m_IDirect3DDevice9Ex::BeginScene() } #endif - HRESULT hr = ProxyInterface->BeginScene(); - -#ifdef ENABLE_DEBUGOVERLAY - if (Config.EnableImgui) + if (Config.ForceSingleBeginEndScene && (SHARED.IsInScene || SHARED.BeginSceneCalled)) { - DOverlay.BeginScene(); + if (SHARED.IsInScene) + { + return D3DERR_INVALIDCALL; + } + + SHARED.IsInScene = true; + + return D3D_OK; } -#endif - // Get DeviceCaps - if (SHARED.Caps.DeviceType == NULL) + HRESULT hr = CallBeginScene(); + + if (SUCCEEDED(hr)) { - if (SUCCEEDED(ProxyInterface->GetDeviceCaps(&SHARED.Caps))) + // Get DeviceCaps + if (SHARED.Caps.DeviceType == NULL) { - // Set for Anisotropic Filtering - SHARED.MaxAnisotropy = (Config.AnisotropicFiltering == 1) ? SHARED.Caps.MaxAnisotropy : min((DWORD)Config.AnisotropicFiltering, SHARED.Caps.MaxAnisotropy); - } - else - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Falied to get DeviceCaps (" << this << ")"); - ZeroMemory(&SHARED.Caps, sizeof(D3DCAPS9)); + if (SUCCEEDED(ProxyInterface->GetDeviceCaps(&SHARED.Caps))) + { + // Set for Anisotropic Filtering + SHARED.MaxAnisotropy = (Config.AnisotropicFiltering == 1) ? SHARED.Caps.MaxAnisotropy : min((DWORD)Config.AnisotropicFiltering, SHARED.Caps.MaxAnisotropy); + } + else + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Falied to get DeviceCaps (" << this << ")"); + ZeroMemory(&SHARED.Caps, sizeof(D3DCAPS9)); + } } - } - // Set for Multisample - if (SHARED.DeviceMultiSampleFlag) - { - ProxyInterface->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - if (SHARED.SetSSAA) + // Set for Multisample + if (SHARED.DeviceMultiSampleFlag) { - ProxyInterface->SetRenderState(D3DRS_ADAPTIVETESS_Y, MAKEFOURCC('S', 'S', 'A', 'A')); + ProxyInterface->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + if (SHARED.SetSSAA) + { + ProxyInterface->SetRenderState(D3DRS_ADAPTIVETESS_Y, MAKEFOURCC('S', 'S', 'A', 'A')); + } } } @@ -1504,7 +1670,7 @@ HRESULT m_IDirect3DDevice9Ex::GetTextureStageState(DWORD Stage, D3DTEXTURESTAGES } // Check if this is a texture stage transform for cube mapping -inline void m_IDirect3DDevice9Ex::CheckTransformForCubeMap(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) const +void m_IDirect3DDevice9Ex::CheckTransformForCubeMap(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) const { if (State >= D3DTS_TEXTURE0 && State <= D3DTS_TEXTURE7) { @@ -1549,7 +1715,7 @@ inline void m_IDirect3DDevice9Ex::CheckTransformForCubeMap(D3DTRANSFORMSTATETYPE } // Check if an environment cube map is being used -inline bool m_IDirect3DDevice9Ex::CheckTextureStageForCubeMap() const +bool m_IDirect3DDevice9Ex::CheckTextureStageForCubeMap() const { for (DWORD i = 0; i < MAX_TEXTURE_STAGES; i++) { @@ -1562,7 +1728,7 @@ inline bool m_IDirect3DDevice9Ex::CheckTextureStageForCubeMap() const return false; } -inline void m_IDirect3DDevice9Ex::SetEnvironmentMapCubeTexture() +void m_IDirect3DDevice9Ex::SetEnvironmentMapCubeTexture() { const bool isCubeMap = CheckTextureStageForCubeMap() || [&]() { @@ -1786,7 +1952,7 @@ HRESULT m_IDirect3DDevice9Ex::SetClipPlane(DWORD Index, CONST float *pPlane) } // CacheClipPlane -inline void m_IDirect3DDevice9Ex::ApplyClipPlanes() +void m_IDirect3DDevice9Ex::ApplyClipPlanes() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -2160,7 +2326,7 @@ HRESULT m_IDirect3DDevice9Ex::SetSamplerState(THIS_ DWORD Sampler, D3DSAMPLERSTA return ProxyInterface->SetSamplerState(Sampler, Type, Value); } -inline void m_IDirect3DDevice9Ex::DisableAnisotropicSamplerState(bool AnisotropyMin, bool AnisotropyMag) +void m_IDirect3DDevice9Ex::DisableAnisotropicSamplerState(bool AnisotropyMin, bool AnisotropyMag) { DWORD Value = 0; for (int x = 0; x < 4; x++) @@ -2184,7 +2350,7 @@ inline void m_IDirect3DDevice9Ex::DisableAnisotropicSamplerState(bool Anisotropy } } -inline void m_IDirect3DDevice9Ex::ReeableAnisotropicSamplerState() +void m_IDirect3DDevice9Ex::ReeableAnisotropicSamplerState() { if (SHARED.AnisotropyDisabledFlag) { @@ -2390,17 +2556,16 @@ HRESULT m_IDirect3DDevice9Ex::FakeGetFrontBufferData(THIS_ UINT iSwapChain, IDir RectSrc.bottom = RectSrc.top + rcClient.bottom; // Create new surface to hold data - IDirect3DSurface9 *pSrcSurface = nullptr; - if (FAILED(ProxyInterface->CreateOffscreenPlainSurface(max(SHARED.screenWidth, RectSrc.right), max(SHARED.screenHeight, RectSrc.bottom), Desc.Format, Desc.Pool, &pSrcSurface, nullptr))) + ComPtr pSrcSurface; + if (FAILED(ProxyInterface->CreateOffscreenPlainSurface(max(SHARED.screenWidth, RectSrc.right), max(SHARED.screenHeight, RectSrc.bottom), Desc.Format, Desc.Pool, pSrcSurface.GetAddressOf(), nullptr))) { return D3DERR_INVALIDCALL; } // Get FrontBuffer data to new surface - HRESULT hr = ProxyInterface->GetFrontBufferData(iSwapChain, pSrcSurface); + HRESULT hr = ProxyInterface->GetFrontBufferData(iSwapChain, pSrcSurface.Get()); if (FAILED(hr)) { - pSrcSurface->Release(); return hr; } @@ -2409,27 +2574,25 @@ HRESULT m_IDirect3DDevice9Ex::FakeGetFrontBufferData(THIS_ UINT iSwapChain, IDir if (rcClient.left == 0 && rcClient.top == 0 && (LONG)Desc.Width == rcClient.right && (LONG)Desc.Height == rcClient.bottom) { POINT PointDest = { 0, 0 }; - hr = CopyRects(pSrcSurface, &RectSrc, 1, pDestSurface, &PointDest); + hr = CopyRects(pSrcSurface.Get(), &RectSrc, 1, pDestSurface, &PointDest); } // Try using StretchRect if (FAILED(hr)) { - IDirect3DSurface9 *pTmpSurface = nullptr; - if (SUCCEEDED(ProxyInterface->CreateOffscreenPlainSurface(Desc.Width, Desc.Height, Desc.Format, Desc.Pool, &pTmpSurface, nullptr))) + ComPtr pTmpSurface; + if (SUCCEEDED(ProxyInterface->CreateOffscreenPlainSurface(Desc.Width, Desc.Height, Desc.Format, Desc.Pool, pTmpSurface.GetAddressOf(), nullptr))) { - if (SUCCEEDED(ProxyInterface->StretchRect(pSrcSurface, &RectSrc, pTmpSurface, nullptr, D3DTEXF_NONE))) + if (SUCCEEDED(ProxyInterface->StretchRect(pSrcSurface.Get(), &RectSrc, pTmpSurface.Get(), nullptr, D3DTEXF_NONE))) { POINT PointDest = { 0, 0 }; RECT Rect = { 0, 0, (LONG)Desc.Width, (LONG)Desc.Height }; - hr = CopyRects(pTmpSurface, &Rect, 1, pDestSurface, &PointDest); + hr = CopyRects(pTmpSurface.Get(), &Rect, 1, pDestSurface, &PointDest); } - pTmpSurface->Release(); } } // Release surface - pSrcSurface->Release(); return hr; } @@ -2580,39 +2743,18 @@ HRESULT m_IDirect3DDevice9Ex::ComposeRects(THIS_ IDirect3DSurface9* pSrc, IDirec HRESULT m_IDirect3DDevice9Ex::PresentEx(THIS_ CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags) { - Utils::ResetInvalidFPUState(); // Check FPU state before presenting - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterfaceEx) - { - Logging::Log() << __FUNCTION__ << " Error: Calling extension function from a non-extension device!"; - return D3DERR_INVALIDCALL; - } - - if (SHARED.IsGammaSet) - { - ProxyInterface->BeginScene(); - ApplyBrightnessLevel(); - ProxyInterface->EndScene(); - } - - if (Config.LimitPerFrameFPS) - { - LimitFrameRate(); - } + ApplyPresentFixes(); HRESULT hr = ProxyInterfaceEx->PresentEx(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); if (SUCCEEDED(hr)) { -#ifdef ENABLE_DEBUGOVERLAY - if (Config.EnableImgui) + if (Config.ShowFPSCounter || Config.EnableImgui) { CalculateFPS(); - DOverlay.SetFPSCount(SHARED.AverageFPSCounter); } -#endif } return hr; @@ -2884,7 +3026,7 @@ HRESULT m_IDirect3DDevice9Ex::GetDisplayModeEx(THIS_ UINT iSwapChain, D3DDISPLAY } // Runs when device is created and on every successful Reset() -inline void m_IDirect3DDevice9Ex::ReInitInterface() const +void m_IDirect3DDevice9Ex::ReInitInterface() const { Utils::GetScreenSize(SHARED.DeviceWindow, SHARED.screenWidth, SHARED.screenHeight); @@ -2901,7 +3043,7 @@ inline void m_IDirect3DDevice9Ex::ReInitInterface() const } } -inline void m_IDirect3DDevice9Ex::LimitFrameRate() const +void m_IDirect3DDevice9Ex::LimitFrameRate() const { // Count the number of frames SHARED.Counter.FrameCounter++; @@ -2953,7 +3095,7 @@ inline void m_IDirect3DDevice9Ex::LimitFrameRate() const SHARED.Counter.LastPresentTime.QuadPart = TargetEndTicks; } -inline void m_IDirect3DDevice9Ex::CalculateFPS() const +void m_IDirect3DDevice9Ex::CalculateFPS() const { // Calculate frame time auto endTime = std::chrono::steady_clock::now(); @@ -2991,6 +3133,93 @@ inline void m_IDirect3DDevice9Ex::CalculateFPS() const SHARED.AverageFPSCounter = 1.0 / averageFrameTime; } +#ifdef ENABLE_DEBUGOVERLAY + DOverlay.SetFPSCount(SHARED.AverageFPSCounter); +#endif + // Output FPS Logging::LogDebug() << "Frames: " << SHARED.frameTimes.size() << " Average time: " << averageFrameTime << " FPS: " << SHARED.AverageFPSCounter; } + +void m_IDirect3DDevice9Ex::DrawFPS(float fps, const RECT& presentRect, DWORD position) const +{ + // Scale the font size based on the rect height (adjustable factor) + int fontSize = SHARED.BufferHeight / 40; + if (fontSize < 4) fontSize = 4; // Minimum font size + if (fontSize > 128) fontSize = 128; // Maximum font size + + // Create the font if not created + if (!SHARED.pFont && + FAILED(D3DXCreateFontW(ProxyInterface, fontSize, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + L"Arial", &SHARED.pFont))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create font!"); + return; + } + + // Create the sprite if not created + if (!SHARED.pSprite && FAILED(D3DXCreateSprite(ProxyInterface, &SHARED.pSprite))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create sprite!"); + return; + } + + // Format FPS text + wchar_t fpsText[16]; + swprintf(fpsText, 16, L"FPS: %.1f", fps); + + // Determine text position based on 'position' + int padding = fontSize / 2; + RECT textRect = presentRect; + + switch (position) + { + case 1: // Top-left + textRect.left = presentRect.left + padding; + textRect.top = presentRect.top + padding; + break; + case 2: // Top-right + textRect.right = presentRect.right - padding; + textRect.top = presentRect.top + padding; + break; + case 3: // Bottom-right + textRect.right = presentRect.right - padding; + textRect.bottom = presentRect.bottom - padding; + break; + case 4: // Bottom-left + textRect.left = presentRect.left + padding; + textRect.bottom = presentRect.bottom - padding; + break; + default: // Default to top-left if an invalid position is given + textRect.left = presentRect.left + padding; + textRect.top = presentRect.top + padding; + break; + } + + // Set alignment flags based on position + DWORD alignment = 0; + if (position == 2 || position == 3) + alignment |= DT_RIGHT; + else + alignment |= DT_LEFT; + + if (position == 3 || position == 4) + alignment |= DT_BOTTOM; + else + alignment |= DT_TOP; + + // Start drawing + SHARED.pSprite->Begin(D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE | D3DXSPRITE_DONOTSAVESTATE); + + // Draw the text + INT ret = SHARED.pFont->DrawTextW(SHARED.pSprite, fpsText, -1, &textRect, alignment, D3DCOLOR_XRGB(247, 247, 0)); + + // End drawing + SHARED.pSprite->End(); + + if (ret == 0) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not DrawText!"); + } +} diff --git a/d3d9/IDirect3DDevice9Ex.h b/d3d9/IDirect3DDevice9Ex.h index 34a8d055..f9e74791 100644 --- a/d3d9/IDirect3DDevice9Ex.h +++ b/d3d9/IDirect3DDevice9Ex.h @@ -7,11 +7,24 @@ const std::chrono::seconds FPS_CALCULATION_WINDOW(1); // Define a constant for t struct DEVICEDETAILS { + DEVICEDETAILS() + { + InitializeCriticalSection(&d9cs); + } + ~DEVICEDETAILS() + { + DeleteCriticalSection(&d9cs); + } + // Window handle and size + bool IsWindowMode = false; + bool IsDirectDrawDevice = false; HWND DeviceWindow = nullptr; LONG BufferWidth = 0, BufferHeight = 0; LONG screenWidth = 0, screenHeight = 0; + CRITICAL_SECTION d9cs = {}; + std::unordered_map DeviceMap; AddressLookupTableD3d9 ProxyAddressLookupTable9; @@ -20,6 +33,10 @@ struct DEVICEDETAILS D3DCAPS9 Caps = {}; + // Begin/End Scene + bool IsInScene = false; + bool BeginSceneCalled = false; + // Limit frame rate struct { DWORD FrameCounter = 0; @@ -31,6 +48,10 @@ struct DEVICEDETAILS std::deque>> frameTimes; // Store frame times in a deque std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); // Store start time for PFS counter + // FPS display + ID3DXFont* pFont = nullptr; + ID3DXSprite* pSprite = nullptr; + // For AntiAliasing bool DeviceMultiSampleFlag = false; bool SetSSAA = false; @@ -42,6 +63,10 @@ struct DEVICEDETAILS bool isAnisotropySet = false; bool AnisotropyDisabledFlag = false; // Tracks when Anisotropic Fintering was disabled becasue lack of multi-stage texture support + // State block + bool DontReleaseResources = false; + IDirect3DStateBlock9* pStateBlock = nullptr; + // For environment map cube bool isTextureMapCube[MAX_TEXTURE_STAGES] = {}; bool isTransformMapCube[MAX_TEXTURE_STAGES] = {}; @@ -83,12 +108,17 @@ class m_IDirect3DDevice9Ex : public IDirect3DDevice9Ex, public AddressLookupTabl UINT DDKey; void ApplyDrawFixes(); + void ApplyPresentFixes(); + + HRESULT CallBeginScene(); + HRESULT CallEndScene(); // Limit frame rate void LimitFrameRate() const; // Frame counter void CalculateFPS() const; + void DrawFPS(float fps, const RECT& presentRect, DWORD position) const; // Anisotropic Filtering void DisableAnisotropicSamplerState(bool AnisotropyMin, bool AnisotropyMag); @@ -289,8 +319,8 @@ class m_IDirect3DDevice9Ex : public IDirect3DDevice9Ex, public AddressLookupTabl STDMETHOD(GetDisplayModeEx)(THIS_ UINT iSwapChain, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation); // Helper functions - inline LPDIRECT3DDEVICE9 GetProxyInterface() const { return ProxyInterface; } - inline AddressLookupTableD3d9* GetLookupTable() const { return &SHARED.ProxyAddressLookupTable9; } + LPDIRECT3DDEVICE9 GetProxyInterface() const { return ProxyInterface; } + AddressLookupTableD3d9* GetLookupTable() const { return &SHARED.ProxyAddressLookupTable9; } REFIID GetIID() { return WrapperID; } }; #undef SHARED diff --git a/d3d9/IDirect3DIndexBuffer9.cpp b/d3d9/IDirect3DIndexBuffer9.cpp index 268520a2..bacb3486 100644 --- a/d3d9/IDirect3DIndexBuffer9.cpp +++ b/d3d9/IDirect3DIndexBuffer9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DPixelShader9.cpp b/d3d9/IDirect3DPixelShader9.cpp index 8206e2c7..97f971e8 100644 --- a/d3d9/IDirect3DPixelShader9.cpp +++ b/d3d9/IDirect3DPixelShader9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DQuery9.cpp b/d3d9/IDirect3DQuery9.cpp index 4bd68e8b..e3a7a88b 100644 --- a/d3d9/IDirect3DQuery9.cpp +++ b/d3d9/IDirect3DQuery9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DStateBlock9.cpp b/d3d9/IDirect3DStateBlock9.cpp index 1daa5b23..34b271b5 100644 --- a/d3d9/IDirect3DStateBlock9.cpp +++ b/d3d9/IDirect3DStateBlock9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DSurface9.cpp b/d3d9/IDirect3DSurface9.cpp index e46f69ab..bc279a05 100644 --- a/d3d9/IDirect3DSurface9.cpp +++ b/d3d9/IDirect3DSurface9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DSwapChain9Ex.cpp b/d3d9/IDirect3DSwapChain9Ex.cpp index 0fd6fbac..0da8af39 100644 --- a/d3d9/IDirect3DSwapChain9Ex.cpp +++ b/d3d9/IDirect3DSwapChain9Ex.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DTexture9.cpp b/d3d9/IDirect3DTexture9.cpp index cac782d1..3e3e9928 100644 --- a/d3d9/IDirect3DTexture9.cpp +++ b/d3d9/IDirect3DTexture9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DVertexBuffer9.cpp b/d3d9/IDirect3DVertexBuffer9.cpp index bec66a20..604eedd9 100644 --- a/d3d9/IDirect3DVertexBuffer9.cpp +++ b/d3d9/IDirect3DVertexBuffer9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DVertexDeclaration9.cpp b/d3d9/IDirect3DVertexDeclaration9.cpp index 34afc8dc..d38fcf44 100644 --- a/d3d9/IDirect3DVertexDeclaration9.cpp +++ b/d3d9/IDirect3DVertexDeclaration9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DVertexShader9.cpp b/d3d9/IDirect3DVertexShader9.cpp index 3542ceb6..ddc9729c 100644 --- a/d3d9/IDirect3DVertexShader9.cpp +++ b/d3d9/IDirect3DVertexShader9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DVolume9.cpp b/d3d9/IDirect3DVolume9.cpp index 08d6d54e..998858e2 100644 --- a/d3d9/IDirect3DVolume9.cpp +++ b/d3d9/IDirect3DVolume9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/IDirect3DVolumeTexture9.cpp b/d3d9/IDirect3DVolumeTexture9.cpp index 1f158783..c98ac66d 100644 --- a/d3d9/IDirect3DVolumeTexture9.cpp +++ b/d3d9/IDirect3DVolumeTexture9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/InterfaceQuery.cpp b/d3d9/InterfaceQuery.cpp index 2b3cf2b9..a5e011bd 100644 --- a/d3d9/InterfaceQuery.cpp +++ b/d3d9/InterfaceQuery.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -26,18 +26,15 @@ void WINAPI D3d9Wrapper::genericQueryInterface(REFIID riid, LPVOID *ppvObj, m_ID if (riid == IID_IDirect3D9 || riid == IID_IDirect3D9Ex) { - IDirect3D9 *pD3D9 = nullptr; - if (SUCCEEDED(m_pDeviceEx->GetDirect3D(&pD3D9))) + ComPtr pD3D9; + if (SUCCEEDED(m_pDeviceEx->GetDirect3D(pD3D9.GetAddressOf()))) { - IDirect3D9* pD3D9Ex = nullptr; - if (SUCCEEDED(pD3D9->QueryInterface(riid, (LPVOID*)&pD3D9Ex))) + ComPtr pD3D9Ex; + if (SUCCEEDED(pD3D9->QueryInterface(riid, (LPVOID*)pD3D9Ex.GetAddressOf()))) { - *ppvObj = pD3D9Ex; - pD3D9Ex->Release(); - pD3D9->Release(); + *ppvObj = pD3D9Ex.Get(); return; } - pD3D9->Release(); } LOG_LIMIT(100, __FUNCTION__ << " Warning: not wrapping interface: " << riid); return; @@ -45,11 +42,10 @@ void WINAPI D3d9Wrapper::genericQueryInterface(REFIID riid, LPVOID *ppvObj, m_ID if (riid == IID_IDirect3DDevice9 || riid == IID_IDirect3DDevice9Ex) { - IDirect3DDevice9 *pD3DDevice9 = nullptr; - if (SUCCEEDED(m_pDeviceEx->QueryInterface(riid, (LPVOID*)&pD3DDevice9))) + ComPtr pD3DDevice9; + if (SUCCEEDED(m_pDeviceEx->QueryInterface(riid, (LPVOID*)pD3DDevice9.GetAddressOf()))) { - *ppvObj = pD3DDevice9; - pD3DDevice9->Release(); + *ppvObj = pD3DDevice9.Get(); return; } LOG_LIMIT(100, __FUNCTION__ << " Warning: not wrapping interface: " << riid); diff --git a/d3d9/License.txt b/d3d9/License.txt index 53f73bd0..9cdb9d78 100644 --- a/d3d9/License.txt +++ b/d3d9/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/d3d9/d3d9.cpp b/d3d9/d3d9.cpp index c2bdfeed..f9fb12f1 100644 --- a/d3d9/d3d9.cpp +++ b/d3d9/d3d9.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -17,7 +17,6 @@ */ #include "d3d9.h" -#include "d3d9External.h" #include "External\Hooking\Hook.h" namespace D3d9Wrapper diff --git a/d3d9/d3d9.h b/d3d9/d3d9.h index b91dcd60..a0074c92 100644 --- a/d3d9/d3d9.h +++ b/d3d9/d3d9.h @@ -1,6 +1,8 @@ #pragma once -#include "d3d9External.h" +#include +#include "d3dx9.h" +#include "d3d9\d3d9External.h" #include "GDI\GDI.h" class m_IDirect3D9Ex; @@ -105,6 +107,9 @@ namespace D3d9Wrapper void WINAPI genericQueryInterface(REFIID riid, LPVOID* ppvObj, m_IDirect3DDevice9Ex* m_pDeviceEx); } +#include "ComPtr.h" +#include "ScopeGuard.h" + #include "IDirect3DDevice9Ex.h" #include "IDirect3DCubeTexture9.h" #include "IDirect3DIndexBuffer9.h" diff --git a/d3d9/d3d9External.h b/d3d9/d3d9External.h index 8c1ffcdf..8df528f2 100644 --- a/d3d9/d3d9External.h +++ b/d3d9/d3d9External.h @@ -20,6 +20,10 @@ struct __declspec(uuid("02177241-69FC-400C-8FF1-93A44DF6861D")) IDirect3D9Ex; #define MAX_D3D9ON12_QUEUES 2 +// Initial screen resolution +extern volatile LONG InitWidth; +extern volatile LONG InitHeight; + typedef struct _D3D9ON12_ARGS { BOOL Enable9On12; diff --git a/d3dddi/License.txt b/d3dddi/License.txt index 53f73bd0..9cdb9d78 100644 --- a/d3dddi/License.txt +++ b/d3dddi/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw-testing/IDirectDrawSurface.cpp b/ddraw-testing/IDirectDrawSurface.cpp index e80d344d..e2540628 100644 --- a/ddraw-testing/IDirectDrawSurface.cpp +++ b/ddraw-testing/IDirectDrawSurface.cpp @@ -177,8 +177,9 @@ void TestCreateSurfaceT(DDType* pDDraw) // Create primary surface DSDesc primaryDesc = {}; primaryDesc.dwSize = sizeof(primaryDesc); - primaryDesc.dwFlags = DDSD_CAPS; - primaryDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + primaryDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + primaryDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + primaryDesc.dwBackBufferCount = 1; // One back buffer DSType* pPrimarySurface = nullptr; HRESULT hr = pDDraw->CreateSurface(&primaryDesc, &pPrimarySurface, nullptr); @@ -196,6 +197,58 @@ void TestCreateSurfaceT(DDType* pDDraw) TestID = 201; LOG_TEST_RESULT(TestID, "DirectDraw Ref count ", GetRefCount(pDDraw), GetResults(TestID)); + // Assume pPrimarySurface was created with back buffers + DSType* pBackBuffer = nullptr; + if constexpr (std::is_same_v) + { + DDSCAPS ddscaps = {}; + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; // Request the attached back buffer + hr = pPrimarySurface->GetAttachedSurface(&ddscaps, &pBackBuffer); + } + else + { + DDSCAPS2 ddscaps = {}; + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; // Request the attached back buffer + hr = pPrimarySurface->GetAttachedSurface(&ddscaps, &pBackBuffer); + } + + // Get the surface description of primary surface + DWORD dwCaps = 0; + { + DSDesc ddsd = {}; + ddsd.dwSize = sizeof(ddsd); + + if (SUCCEEDED(pPrimarySurface->GetSurfaceDesc(&ddsd))) + { + dwCaps = ddsd.ddsCaps.dwCaps; + } + } + + // **** 233 **** + TestID = 233; + LOG_TEST_RESULT(TestID, "Primary DDS Caps: ", dwCaps, GetResults(TestID)); + + // Get the first back buffer + dwCaps = 0; + if (SUCCEEDED(hr) && pBackBuffer) + { + DSDesc ddsd = {}; + ddsd.dwSize = sizeof(ddsd); + + // Get the surface description of the back buffer + if (SUCCEEDED(pBackBuffer->GetSurfaceDesc(&ddsd))) + { + dwCaps = ddsd.ddsCaps.dwCaps; + } + + // Release the back buffer when done + pBackBuffer->Release(); + } + + // **** 234 **** + TestID = 234; + LOG_TEST_RESULT(TestID, "Backbuffer DDS Caps: ", dwCaps, GetResults(TestID)); + // Test GammaControl TestCreateGammaControl(pDDraw, pPrimarySurface, "Primary Surface", 400); diff --git a/ddraw-testing/resource.h b/ddraw-testing/resource.h index 9598db46..48b4c386 100644 --- a/ddraw-testing/resource.h +++ b/ddraw-testing/resource.h @@ -10,7 +10,7 @@ #define APP_REVISION 0 #define APP_COMPANYNAME "Sadrate Presents" #define APP_DESCRPTION "Tests specific funtions of DirectDraw and Direct3D." -#define APP_COPYRIGHT "Copyright (C) 2024 Elisha Riedlinger" +#define APP_COPYRIGHT "Copyright (C) 2025 Elisha Riedlinger" #define APP_ORIGINALVERSION "ddraw-testing.exe" #define APP_INTERNALNAME "ddraw-testing" diff --git a/ddraw-testing/testing-harness.h b/ddraw-testing/testing-harness.h index b5587719..3ac264d9 100644 --- a/ddraw-testing/testing-harness.h +++ b/ddraw-testing/testing-harness.h @@ -74,6 +74,8 @@ constexpr TESTMATRIX TestResults[] = { { 230, { 2, 2, 2, 2, 2, 2 } }, { 231, { 2, 2, 2, 2, 2, 2 } }, { 232, { 1, 1, 1, 1, 1, 1 } }, + { 233, { 268485176, 268485176, 0, 268485176, 268485176, 268485176 } }, + { 234, { 268451868, 268451868, 0, 268451868, 268451868, 268451868 } }, // IDirect3DTexture { 300, { 2, 2, 2, 2, 2, (DWORD)E_NOINTERFACE } }, diff --git a/ddraw/AddressLookupTable.h b/ddraw/AddressLookupTable.h index 380cd394..ef7fb4c4 100644 --- a/ddraw/AddressLookupTable.h +++ b/ddraw/AddressLookupTable.h @@ -10,16 +10,43 @@ inline void SaveInterfaceAddress(T*& Interface, T*& InterfaceBackup) { if (Interface) { - Interface->SetProxy(nullptr); + if constexpr (std::is_same_v) + { + Interface->SetProxy(nullptr, nullptr, 0, nullptr); + } + else if constexpr (std::is_same_v) + { + Interface->SetProxy(nullptr, nullptr, nullptr); + } + else if constexpr (std::is_same_v) + { + Interface->SetProxy(nullptr, nullptr, 0); + } + else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + { + Interface->SetProxy(nullptr, nullptr); + } + else + { + Interface->SetProxy(nullptr); + } if (InterfaceBackup) { InterfaceBackup->DeleteMe(); InterfaceBackup = nullptr; } InterfaceBackup = Interface; + Interface = nullptr; } } +template +inline void SaveInterfaceAddress(const T* Interface, T*& InterfaceBackup) +{ + T* NewInterface = const_cast(Interface); + SaveInterfaceAddress(NewInterface, InterfaceBackup); +} + template inline T* GetInterfaceAddress(T*& Interface, T*& InterfaceBackup, S* ProxyInterface, X* InterfaceX) { diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 0fde5ec6..a4fdfe36 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -17,9 +17,6 @@ #include "ddraw.h" #include "d3d9\d3d9External.h" -#define D3DSTATE D3DSTATE7 - -// Cached wrapper interface namespace { m_IDirect3DDevice* WrapperInterfaceBackup = nullptr; m_IDirect3DDevice2* WrapperInterfaceBackup2 = nullptr; @@ -27,6 +24,10 @@ namespace { m_IDirect3DDevice7* WrapperInterfaceBackup7 = nullptr; } +// ****************************** +// IUnknown functions +// ****************************** + HRESULT m_IDirect3DDeviceX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << riid; @@ -48,26 +49,13 @@ HRESULT m_IDirect3DDeviceX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWO return D3D_OK; } - if (DirectXVersion != 1 && DirectXVersion != 2 && DirectXVersion != 3 && DirectXVersion != 7) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirect3D7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; if (riid == GetWrapperType(DxVersion) || riid == IID_IUnknown) { *ppvObj = GetWrapperInterfaceX(DxVersion); - if (parent3DSurface.Interface) - { - parent3DSurface.Interface->AddRef(parent3DSurface.DxVersion); // Some Direct3DDevices share reference count with parent surfaces - } - else - { - AddRef(DxVersion); - } + AddRef(DxVersion); return D3D_OK; } @@ -75,29 +63,6 @@ HRESULT m_IDirect3DDeviceX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWO return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } -void *m_IDirect3DDeviceX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface7) return WrapperInterface7; - if (WrapperInterface3) return WrapperInterface3; - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DDEVICE)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DDEVICE2)ProxyInterface, this); - case 3: - return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3DDEVICE3)ProxyInterface, this); - case 7: - return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECT3DDEVICE7)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirect3DDeviceX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; @@ -133,10 +98,10 @@ ULONG m_IDirect3DDeviceX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - ULONG ref; - if (Config.Dd7to9) { + ULONG ref; + // Some Direct3DDevices share reference count with parent surfaces if (parent3DSurface.Interface) { @@ -167,25 +132,29 @@ ULONG m_IDirect3DDeviceX::Release(DWORD DirectXVersion) { delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } +// ****************************** +// IDirect3DDevice v1 functions +// ****************************** + HRESULT m_IDirect3DDeviceX::Initialize(LPDIRECT3D lpd3d, LPGUID lpGUID, LPD3DDEVICEDESC lpd3ddvdesc) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // Returns D3D_OK if successful, otherwise it returns an error. return D3D_OK; @@ -199,11 +168,133 @@ HRESULT m_IDirect3DDeviceX::Initialize(LPDIRECT3D lpd3d, LPGUID lpGUID, LPD3DDEV return GetProxyInterfaceV1()->Initialize(lpd3d, lpGUID, lpd3ddvdesc); } +HRESULT m_IDirect3DDeviceX::GetCaps(LPD3DDEVICEDESC lpD3DHWDevDesc, LPD3DDEVICEDESC lpD3DHELDevDesc) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if ((!lpD3DHWDevDesc && !lpD3DHELDevDesc) || + (lpD3DHWDevDesc && lpD3DHWDevDesc->dwSize != D3DDEVICEDESC1_SIZE && lpD3DHWDevDesc->dwSize != D3DDEVICEDESC5_SIZE && lpD3DHWDevDesc->dwSize != D3DDEVICEDESC6_SIZE) || + (lpD3DHELDevDesc && lpD3DHELDevDesc->dwSize != D3DDEVICEDESC1_SIZE && lpD3DHELDevDesc->dwSize != D3DDEVICEDESC5_SIZE && lpD3DHELDevDesc->dwSize != D3DDEVICEDESC6_SIZE)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Incorrect dwSize: " << ((lpD3DHWDevDesc) ? lpD3DHWDevDesc->dwSize : -1) << " " << ((lpD3DHELDevDesc) ? lpD3DHELDevDesc->dwSize : -1)); + return DDERR_INVALIDPARAMS; + } + + D3DDEVICEDESC7 D3DDevDesc; + HRESULT hr = GetCaps(&D3DDevDesc); + + if (SUCCEEDED(hr)) + { + if (lpD3DHWDevDesc) + { + ConvertDeviceDesc(*lpD3DHWDevDesc, D3DDevDesc); + } + + if (lpD3DHELDevDesc) + { + ConvertDeviceDesc(*lpD3DHELDevDesc, D3DDevDesc); + } + } + + return hr; + } + + switch (ProxyDirectXVersion) + { + case 1: + return GetProxyInterfaceV1()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc); + case 2: + return GetProxyInterfaceV2()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc); + case 3: + return GetProxyInterfaceV3()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc); + default: + return DDERR_GENERIC; + } +} + +HRESULT m_IDirect3DDeviceX::SwapTextureHandles(LPDIRECT3DTEXTURE2 lpD3DTex1, LPDIRECT3DTEXTURE2 lpD3DTex2) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpD3DTex1 || !lpD3DTex2) + { + return DDERR_INVALIDPARAMS; + } + + m_IDirect3DTextureX* pTextureX1 = nullptr; + lpD3DTex1->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pTextureX1); + + m_IDirect3DTextureX* pTextureX2 = nullptr; + lpD3DTex2->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pTextureX2); + + if (!pTextureX1 || !pTextureX2) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture wrapper!"); + return DDERR_INVALIDPARAMS; + } + + // Find handle associated with texture1 + D3DTEXTUREHANDLE TexHandle1 = 0; + if (FAILED(pTextureX1->GetHandle((LPDIRECT3DDEVICE2)GetWrapperInterfaceX(0), &TexHandle1))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not find texture1 handle!"); + return DDERR_INVALIDPARAMS; + } + + // Find handle associated with texture2 + D3DTEXTUREHANDLE TexHandle2 = 0; + if (FAILED(pTextureX2->GetHandle((LPDIRECT3DDEVICE2)GetWrapperInterfaceX(0), &TexHandle2))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not find texture2 handle!"); + return DDERR_INVALIDPARAMS; + } + + // Swap texture handle1 + pTextureX1->SetHandle(TexHandle2); + TextureHandleMap[TexHandle2] = pTextureX1; + + // Swap texture handle2 + pTextureX2->SetHandle(TexHandle1); + TextureHandleMap[TexHandle1] = pTextureX2; + + // If texture handle is set then use new texture + if (rsTextureHandle == TexHandle1 || rsTextureHandle == TexHandle2) + { + SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, rsTextureHandle); + } + + return D3D_OK; + } + + if (lpD3DTex1) + { + lpD3DTex1->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpD3DTex1); + } + if (lpD3DTex2) + { + lpD3DTex2->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpD3DTex2); + } + + switch (ProxyDirectXVersion) + { + case 1: + return GetProxyInterfaceV1()->SwapTextureHandles((LPDIRECT3DTEXTURE)lpD3DTex1, (LPDIRECT3DTEXTURE)lpD3DTex2); + case 2: + return GetProxyInterfaceV2()->SwapTextureHandles(lpD3DTex1, lpD3DTex2); + default: + return DDERR_GENERIC; + } +} + HRESULT m_IDirect3DDeviceX::CreateExecuteBuffer(LPD3DEXECUTEBUFFERDESC lpDesc, LPDIRECT3DEXECUTEBUFFER * lplpDirect3DExecuteBuffer, IUnknown * pUnkOuter) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { if (!lplpDirect3DExecuteBuffer || !lpDesc) { @@ -243,7 +334,7 @@ HRESULT m_IDirect3DDeviceX::CreateExecuteBuffer(LPD3DEXECUTEBUFFERDESC lpDesc, L LOG_LIMIT(100, __FUNCTION__ << " Warning: lpData is non-null, using application data."); } - m_IDirect3DExecuteBuffer* pExecuteBuffer = CreateDirect3DExecuteBuffer(*lplpDirect3DExecuteBuffer, this, lpDesc); + m_IDirect3DExecuteBuffer* pExecuteBuffer = m_IDirect3DExecuteBuffer::CreateDirect3DExecuteBuffer(*lplpDirect3DExecuteBuffer, this, lpDesc); *lplpDirect3DExecuteBuffer = pExecuteBuffer; @@ -254,253 +345,58 @@ HRESULT m_IDirect3DDeviceX::CreateExecuteBuffer(LPD3DEXECUTEBUFFERDESC lpDesc, L if (SUCCEEDED(hr) && lplpDirect3DExecuteBuffer) { - *lplpDirect3DExecuteBuffer = CreateDirect3DExecuteBuffer(*lplpDirect3DExecuteBuffer, nullptr, nullptr); + *lplpDirect3DExecuteBuffer = m_IDirect3DExecuteBuffer::CreateDirect3DExecuteBuffer(*lplpDirect3DExecuteBuffer, nullptr, nullptr); } return hr; } -void m_IDirect3DDeviceX::AddExecuteBuffer(m_IDirect3DExecuteBuffer* lpExecuteBuffer) +HRESULT m_IDirect3DDeviceX::GetStats(LPD3DSTATS lpD3DStats) { - if (!lpExecuteBuffer) - { - return; - } - - ExecuteBufferList.push_back(lpExecuteBuffer); -} + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; -void m_IDirect3DDeviceX::ClearExecuteBuffer(m_IDirect3DExecuteBuffer* lpExecuteBuffer) -{ - // Find and remove the buffer from the list - auto it = std::find(ExecuteBufferList.begin(), ExecuteBufferList.end(), lpExecuteBuffer); - if (it != ExecuteBufferList.end()) + if (Config.Dd7to9) { - ExecuteBufferList.erase(it); + // The method returns E_NOTIMPL / DDERR_UNSUPPORTED. + return DDERR_UNSUPPORTED; } -} -void m_IDirect3DDeviceX::CopyConvertExecuteVertex(BYTE*& DestVertex, DWORD& DestVertexCount, BYTE* SrcVertex, DWORD SrcIndex, DWORD VertexTypeDesc) -{ - // Primitive structures and related defines. Vertex offsets are to types D3DVERTEX, D3DLVERTEX, or D3DTLVERTEX. - if (VertexTypeDesc == D3DFVF_VERTEX) - { - DestVertexCount++; - *((D3DVERTEX*)DestVertex) = ((D3DVERTEX*)SrcVertex)[SrcIndex]; - DestVertex += sizeof(D3DVERTEX); - return; - } - else if (VertexTypeDesc == D3DFVF_LVERTEX) - { - DestVertexCount++; - *((D3DLVERTEX*)DestVertex) = ((D3DLVERTEX*)SrcVertex)[SrcIndex]; - DestVertex += sizeof(D3DLVERTEX); - return; - } - else if (VertexTypeDesc == D3DFVF_TLVERTEX) + switch (ProxyDirectXVersion) { - DestVertexCount++; - *((D3DTLVERTEX*)DestVertex) = ((D3DTLVERTEX*)SrcVertex)[SrcIndex]; - DestVertex += sizeof(D3DTLVERTEX); - return; + case 1: + return GetProxyInterfaceV1()->GetStats(lpD3DStats); + case 2: + return GetProxyInterfaceV2()->GetStats(lpD3DStats); + case 3: + return GetProxyInterfaceV3()->GetStats(lpD3DStats); + default: + return DDERR_GENERIC; } } -HRESULT m_IDirect3DDeviceX::DrawExecutePoint(D3DPOINT* point, WORD pointCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) +HRESULT m_IDirect3DDeviceX::Execute(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags) { - // Define vertices and setup vector - std::vector vertices; - vertices.resize(sizeof(D3DTLVERTEX) * pointCount); - BYTE* verticesData = vertices.data(); - DWORD verticesCount = 0; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Add vertices to vector - for (DWORD i = 0; i < pointCount; i++) + if (Config.Dd7to9) { - if ((DWORD)point[i].wFirst < vertexIndexCount) + if (!lpDirect3DExecuteBuffer || !lpDirect3DViewport) { - DWORD count = min(point[i].wCount, vertexIndexCount - point[i].wFirst); + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid params: " << lpDirect3DExecuteBuffer << " " << lpDirect3DViewport); + return DDERR_INVALIDPARAMS; + } - for (DWORD x = 0; x < count; x++) - { - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, point[i].wFirst + x, VertexTypeDesc); - } + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; } - } - if (verticesCount) - { - // Pass the vertex data to the rendering pipeline - DrawPrimitive(D3DPT_POINTLIST, VertexTypeDesc, vertices.data(), verticesCount, 0, 1); - } + // Flags + // D3DEXECUTE_CLIPPED - Clip any primitives in the buffer that are outside or partially outside the viewport. + // D3DEXECUTE_UNCLIPPED - All primitives in the buffer are contained within the viewport. - return D3D_OK; -} - -HRESULT m_IDirect3DDeviceX::DrawExecuteLine(D3DLINE* line, WORD lineCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) -{ - // Define vertices and setup vector - std::vector vertices; - vertices.resize(sizeof(D3DTLVERTEX) * lineCount * 2); - BYTE* verticesData = vertices.data(); - DWORD verticesCount = 0; - - for (DWORD i = 0; i < lineCount; i++) - { - if (line[i].v1 < vertexIndexCount && line[i].v2 < vertexIndexCount) - { - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, line[i].v1, VertexTypeDesc); - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, line[i].v2, VertexTypeDesc); - } - } - - if (verticesCount) - { - // Pass the vertex data to the rendering pipeline - DrawPrimitive(D3DPT_LINELIST, VertexTypeDesc, vertices.data(), verticesCount, 0, 1); - } - - return D3D_OK; -} - -HRESULT m_IDirect3DDeviceX::DrawExecuteTriangle(D3DTRIANGLE* triangle, WORD triangleCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) -{ - // Compute buffer size - DWORD BufferSize; - { - bool LastRecord = false; - DWORD Count = 0, MaxCount = 0; - for (DWORD i = 0; i < triangleCount; i++) - { - bool IsStartRecord = (triangle[i].wFlags & 0x1F) < D3DTRIFLAG_STARTFLAT(30); - if (IsStartRecord != LastRecord) - { - MaxCount = max(Count, MaxCount); - Count = (IsStartRecord) ? 3 : 4; - } - else - { - Count += (IsStartRecord) ? 3 : 1; - } - LastRecord = IsStartRecord; - } - BufferSize = sizeof(D3DTLVERTEX) * max(Count, MaxCount); - } - - std::vector vertices; - vertices.resize(BufferSize); - BYTE* verticesData = vertices.data(); - DWORD verticesCount = 0; - - D3DPRIMITIVETYPE PrimitiveType = D3DPT_TRIANGLELIST; - - LONG LastCullMode = D3DTRIFLAG_START; - LONG CullRecordCount = 0; - - for (DWORD i = 0; i < triangleCount; i++) - { - // Flags for this triangle - WORD TriFlags = (triangle[i].wFlags & 0x1F); - - // START loads all three vertices - if (TriFlags < D3DTRIFLAG_STARTFLAT(30)) - { - if (triangle[i].v1 < vertexIndexCount && triangle[i].v2 < vertexIndexCount && triangle[i].v3 < vertexIndexCount) - { - PrimitiveType = D3DPT_TRIANGLELIST; - - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v1, VertexTypeDesc); - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v2, VertexTypeDesc); - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v3, VertexTypeDesc); - - LastCullMode = D3DTRIFLAG_START; - CullRecordCount = TriFlags; - } - } - // EVEN and ODD load just v3 with even or odd culling - else if (TriFlags == D3DTRIFLAG_EVEN || TriFlags == D3DTRIFLAG_ODD) - { - // Set primative type - if (LastCullMode == D3DTRIFLAG_START) - { - // Even cull modes indicates a triangle fan - if (TriFlags == D3DTRIFLAG_EVEN) - { - PrimitiveType = D3DPT_TRIANGLEFAN; - } - // Odd or mismatching cull modes indicates a triangle strip - else - { - PrimitiveType = D3DPT_TRIANGLESTRIP; - } - } - // The primative type doesn't mismatch past cull mode - else if ((TriFlags == LastCullMode && PrimitiveType == D3DPT_TRIANGLESTRIP) || - (TriFlags != LastCullMode && PrimitiveType == D3DPT_TRIANGLEFAN)) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: vertex cull mode mismatch detected!"); - } - - if (triangle[i].v3 < vertexIndexCount) - { - CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v3, VertexTypeDesc); - } - - LastCullMode = TriFlags; - CullRecordCount--; - } - - // Check next records - bool AtEndOfList = !(i + 1U < triangleCount); - LONG NextRecord = (i + 1U < triangleCount) ? ((triangle[i + 1].wFlags & 0x1F) < 30 ? D3DTRIFLAG_START : D3DTRIFLAG_EVEN) : 0; - LONG NextNextRecord = (i + 2U < triangleCount) ? ((triangle[i + 2].wFlags & 0x1F) < 30 ? D3DTRIFLAG_START : D3DTRIFLAG_EVEN) : 0; - - // Draw primitaves once at the end of the list - if (verticesCount && // There primatives to draw - (AtEndOfList || // There are no more records, or - (NextRecord == D3DTRIFLAG_START && // Next record is a new START - (LastCullMode != D3DTRIFLAG_START || NextNextRecord != D3DTRIFLAG_START)))) - { - if (CullRecordCount > 0) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: drawing before all records have been culled: " << CullRecordCount); - } - - // Pass the vertex data to the rendering pipeline - DrawPrimitive(PrimitiveType, VertexTypeDesc, vertices.data(), verticesCount, 0, 1); - - // Reset variables for next list - verticesCount = 0; - verticesData = vertices.data(); - } - } - - return D3D_OK; -} - -HRESULT m_IDirect3DDeviceX::Execute(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (ProxyDirectXVersion != 1) - { - if (!lpDirect3DExecuteBuffer || !lpDirect3DViewport) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid params: " << lpDirect3DExecuteBuffer << " " << lpDirect3DViewport); - return DDERR_INVALIDPARAMS; - } - - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } - - // Flags - // D3DEXECUTE_CLIPPED - Clip any primitives in the buffer that are outside or partially outside the viewport. - // D3DEXECUTE_UNCLIPPED - All primitives in the buffer are contained within the viewport. - - m_IDirect3DExecuteBuffer* pExecuteBuffer = (m_IDirect3DExecuteBuffer*)lpDirect3DExecuteBuffer; + m_IDirect3DExecuteBuffer* pExecuteBuffer = (m_IDirect3DExecuteBuffer*)lpDirect3DExecuteBuffer; LPVOID lpData; D3DEXECUTEDATA ExecuteData; @@ -923,82 +819,309 @@ HRESULT m_IDirect3DDeviceX::Execute(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuf return GetProxyInterfaceV1()->Execute(lpDirect3DExecuteBuffer, lpDirect3DViewport, dwFlags); } -HRESULT m_IDirect3DDeviceX::Pick(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags, LPD3DRECT lpRect) +HRESULT m_IDirect3DDeviceX::AddViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + // This method will fail, returning DDERR_INVALIDPARAMS, if you attempt to add a viewport that has already been assigned to the device. + if (!lpDirect3DViewport || IsViewportAttached(lpDirect3DViewport)) + { + return DDERR_INVALIDPARAMS; + } - if (lpDirect3DExecuteBuffer) - { - lpDirect3DExecuteBuffer->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DExecuteBuffer); + // Check if assigning a viewport associated with this device + { + m_IDirect3DViewportX* lpViewportX = nullptr; + if (SUCCEEDED(lpDirect3DViewport->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpViewportX))) + { + m_IDirect3DDeviceX* pViewPort3DDevice = lpViewportX->GetD3DDevice(); + if (pViewPort3DDevice != this) + { + LOG_LIMIT(100, __FUNCTION__ << " (" << this << ") Warning: Viewport's Direct3D device doesn't match current one: " << pViewPort3DDevice); + } + } + } + + AttachedViewports.push_back(lpDirect3DViewport); + + lpDirect3DViewport->AddRef(); + + return D3D_OK; } + if (lpDirect3DViewport) { lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); } - return GetProxyInterfaceV1()->Pick(lpDirect3DExecuteBuffer, lpDirect3DViewport, dwFlags, lpRect); -} - -HRESULT m_IDirect3DDeviceX::GetPickRecords(LPDWORD lpCount, LPD3DPICKRECORD lpD3DPickRec) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (ProxyDirectXVersion != 1) + switch (ProxyDirectXVersion) { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; + case 1: + return GetProxyInterfaceV1()->AddViewport(lpDirect3DViewport); + case 2: + return GetProxyInterfaceV2()->AddViewport(lpDirect3DViewport); + case 3: + return GetProxyInterfaceV3()->AddViewport(lpDirect3DViewport); + default: + return DDERR_GENERIC; } - - return GetProxyInterfaceV1()->GetPickRecords(lpCount, lpD3DPickRec); } -HRESULT m_IDirect3DDeviceX::CreateMatrix(LPD3DMATRIXHANDLE lpD3DMatHandle) +HRESULT m_IDirect3DDeviceX::DeleteViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { - if (!lpD3DMatHandle) + if (!lpDirect3DViewport) { return DDERR_INVALIDPARAMS; } - D3DMATRIX Matrix = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; - - D3DMATRIXHANDLE D3DMatHandle = ComputeRND((DWORD)&Matrix, (DWORD)lpD3DMatHandle); + bool ret = DeleteAttachedViewport(lpDirect3DViewport); - // Make sure the material handle is unique - while (D3DMatHandle == NULL || GetMatrix(D3DMatHandle)) + if (!ret) { - D3DMatHandle += 4; + return DDERR_INVALIDPARAMS; } - MatrixMap[D3DMatHandle] = { true, Matrix }; + // ToDo: if deleting the current material then invalidate the material - *lpD3DMatHandle = D3DMatHandle; + if (lpDirect3DViewport == lpCurrentViewport) + { + lpCurrentViewport = nullptr; + lpCurrentViewportX = nullptr; + } + + lpDirect3DViewport->Release(); return D3D_OK; } - return GetProxyInterfaceV1()->CreateMatrix(lpD3DMatHandle); + if (lpDirect3DViewport) + { + lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); + } + + switch (ProxyDirectXVersion) + { + case 1: + return GetProxyInterfaceV1()->DeleteViewport(lpDirect3DViewport); + case 2: + return GetProxyInterfaceV2()->DeleteViewport(lpDirect3DViewport); + case 3: + return GetProxyInterfaceV3()->DeleteViewport(lpDirect3DViewport); + default: + return DDERR_GENERIC; + } } -HRESULT m_IDirect3DDeviceX::SetMatrix(D3DMATRIXHANDLE D3DMatHandle, const LPD3DMATRIX lpD3DMatrix) +HRESULT m_IDirect3DDeviceX::NextViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport, LPDIRECT3DVIEWPORT3* lplpDirect3DViewport, DWORD dwFlags, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) + { + if (!lplpDirect3DViewport || (dwFlags == D3DNEXT_NEXT && !lpDirect3DViewport)) + { + return DDERR_INVALIDPARAMS; + } + + *lplpDirect3DViewport = nullptr; + + if (AttachedViewports.size() == 0) + { + return D3DERR_NOVIEWPORTS; + } + + switch (dwFlags) + { + case D3DNEXT_HEAD: + // Retrieve the item at the beginning of the list. + *lplpDirect3DViewport = AttachedViewports.front(); + break; + case D3DNEXT_TAIL: + // Retrieve the item at the end of the list. + *lplpDirect3DViewport = AttachedViewports.back(); + break; + case D3DNEXT_NEXT: + // Retrieve the next item in the list. + // If you attempt to retrieve the next viewport in the list when you are at the end of the list, this method returns D3D_OK but lplpAnotherViewport is NULL. + for (UINT x = 1; x < AttachedViewports.size(); x++) + { + if (AttachedViewports[x - 1] == lpDirect3DViewport) + { + *lplpDirect3DViewport = AttachedViewports[x]; + break; + } + } + break; + default: + return DDERR_INVALIDPARAMS; + break; + } + + return D3D_OK; + } + + if (lpDirect3DViewport) + { + lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); + } + + HRESULT hr = DDERR_GENERIC; + + switch (ProxyDirectXVersion) + { + case 1: + hr = GetProxyInterfaceV1()->NextViewport(lpDirect3DViewport, (LPDIRECT3DVIEWPORT*)lplpDirect3DViewport, dwFlags); + break; + case 2: + hr = GetProxyInterfaceV2()->NextViewport(lpDirect3DViewport, (LPDIRECT3DVIEWPORT2*)lplpDirect3DViewport, dwFlags); + break; + case 3: + hr = GetProxyInterfaceV3()->NextViewport(lpDirect3DViewport, lplpDirect3DViewport, dwFlags); + break; + } + + if (SUCCEEDED(hr) && lplpDirect3DViewport) + { + *lplpDirect3DViewport = ProxyAddressLookupTable.FindAddress(*lplpDirect3DViewport, DirectXVersion); + } + + return hr; +} + +HRESULT m_IDirect3DDeviceX::Pick(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags, LPD3DRECT lpRect) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; + } + + if (lpDirect3DExecuteBuffer) + { + lpDirect3DExecuteBuffer->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DExecuteBuffer); + } + if (lpDirect3DViewport) + { + lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); + } + + return GetProxyInterfaceV1()->Pick(lpDirect3DExecuteBuffer, lpDirect3DViewport, dwFlags, lpRect); +} + +HRESULT m_IDirect3DDeviceX::GetPickRecords(LPDWORD lpCount, LPD3DPICKRECORD lpD3DPickRec) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; + } + + return GetProxyInterfaceV1()->GetPickRecords(lpCount, lpD3DPickRec); +} + +HRESULT m_IDirect3DDeviceX::EnumTextureFormats(LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc, LPVOID lpArg) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpd3dEnumTextureProc) + { + return DDERR_INVALIDPARAMS; + } + + struct EnumPixelFormat + { + LPVOID lpContext; + LPD3DENUMTEXTUREFORMATSCALLBACK lpCallback; + + static HRESULT CALLBACK ConvertCallback(LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext) + { + EnumPixelFormat* self = (EnumPixelFormat*)lpContext; + + // Only RGB formats are supported + if ((lpDDPixFmt->dwFlags & DDPF_RGB) == NULL) + { + return DDENUMRET_OK; + } + + DDSURFACEDESC Desc = {}; + Desc.dwSize = sizeof(DDSURFACEDESC); + Desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT; + Desc.ddpfPixelFormat = *lpDDPixFmt; + Desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + + return self->lpCallback(&Desc, self->lpContext); + } + } CallbackContext = {}; + CallbackContext.lpContext = lpArg; + CallbackContext.lpCallback = lpd3dEnumTextureProc; + + return EnumTextureFormats(EnumPixelFormat::ConvertCallback, &CallbackContext); + } + + switch (ProxyDirectXVersion) + { + case 1: + return GetProxyInterfaceV1()->EnumTextureFormats(lpd3dEnumTextureProc, lpArg); + case 2: + return GetProxyInterfaceV2()->EnumTextureFormats(lpd3dEnumTextureProc, lpArg); + default: + return DDERR_GENERIC; + } +} + +HRESULT m_IDirect3DDeviceX::CreateMatrix(LPD3DMATRIXHANDLE lpD3DMatHandle) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpD3DMatHandle) + { + return DDERR_INVALIDPARAMS; + } + + D3DMATRIX Matrix = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + D3DMATRIXHANDLE D3DMatHandle = ComputeRND((DWORD)&Matrix, (DWORD)lpD3DMatHandle); + + // Make sure the material handle is unique + while (D3DMatHandle == NULL || GetMatrix(D3DMatHandle)) + { + D3DMatHandle += 4; + } + + MatrixMap[D3DMatHandle] = { true, Matrix }; + + *lpD3DMatHandle = D3DMatHandle; + + return D3D_OK; + } + + return GetProxyInterfaceV1()->CreateMatrix(lpD3DMatHandle); +} + +HRESULT m_IDirect3DDeviceX::SetMatrix(D3DMATRIXHANDLE D3DMatHandle, const LPD3DMATRIX lpD3DMatrix) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { if (!lpD3DMatrix || !GetMatrix(D3DMatHandle)) { @@ -1017,7 +1140,7 @@ HRESULT m_IDirect3DDeviceX::GetMatrix(D3DMATRIXHANDLE D3DMatHandle, LPD3DMATRIX { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { if (!lpD3DMatrix || !GetMatrix(D3DMatHandle)) { @@ -1036,7 +1159,7 @@ HRESULT m_IDirect3DDeviceX::DeleteMatrix(D3DMATRIXHANDLE D3DMatHandle) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { if (!GetMatrix(D3DMatHandle)) { @@ -1051,1419 +1174,1153 @@ HRESULT m_IDirect3DDeviceX::DeleteMatrix(D3DMATRIXHANDLE D3DMatHandle) return GetProxyInterfaceV1()->DeleteMatrix(D3DMatHandle); } -HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix) +HRESULT m_IDirect3DDeviceX::BeginScene() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpD3DMatrix) - { - return DDERR_INVALIDPARAMS; - } - // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, true))) { return DDERR_INVALIDOBJECT; } - switch ((DWORD)dtstTransformStateType) - { - case D3DTRANSFORMSTATE_WORLD: - dtstTransformStateType = D3DTS_WORLD; - break; - case D3DTRANSFORMSTATE_WORLD1: - dtstTransformStateType = D3DTS_WORLD1; - break; - case D3DTRANSFORMSTATE_WORLD2: - dtstTransformStateType = D3DTS_WORLD2; - break; - case D3DTRANSFORMSTATE_WORLD3: - dtstTransformStateType = D3DTS_WORLD3; - break; - } + // Set 3D Enabled + ddrawParent->Enable3D(); - D3DMATRIX view; - if (Config.DdrawConvertHomogeneousW) - { - if (dtstTransformStateType == D3DTS_VIEW) - { - D3DVIEWPORT9 Viewport9; - if (SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9))) - { - const float width = (float)Viewport9.Width; - const float height = (float)Viewport9.Height; + HRESULT hr = (*d3d9Device)->BeginScene(); - // Replace the matrix with one that handles D3DFVF_XYZRHW geometry - ZeroMemory(&view, sizeof(D3DMATRIX)); - view._11 = 2.0f / width; - view._22 = -2.0f / height; - view._33 = 1.0f; - view._41 = -1.0f; // translate X - view._42 = 1.0f; // translate Y - view._44 = 1.0f; + if (SUCCEEDED(hr)) + { + IsInScene = true; - // Set flag - ConvertHomogeneous.IsTransformViewSet = true; +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr; + sceneTime = std::chrono::high_resolution_clock::now(); +#endif - if (Config.DdrawConvertHomogeneousToWorld) - { - DirectX::XMVECTOR position, direction; - float depthOffset = 0.0f; - if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) - { - // To reconstruct the 3D world, we need to know where the camera is and where it is looking - position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); - - const float x = lpD3DMatrix->_11; - const float y = lpD3DMatrix->_12; - const float z = lpD3DMatrix->_13; - - float pitch = std::atan2(y, z); - if (pitch < 0.0f && y * z > 0.0f) // check if y and z have the same sign - { - // handle flipping of the pitch. This is not because the camera is looking up. - pitch += DirectX::XM_PI; - } - - float yaw = std::asin(x); - if (yaw < 0.0f) - { - yaw += DirectX::XM_2PI; - } - - // mirror the transform - float pitchneg = -pitch; - - float pitch_cos = std::cos(pitchneg); - float x2 = 0.0f; //std::cos(yaw) * pitch_cos; - float y2 = std::sin(pitchneg); - float z2 = /*std::sin(yaw) **/ pitch_cos; - - direction = DirectX::XMVectorSet(x2, y2, z2, 0.0f); - - depthOffset = Config.DdrawConvertHomogeneousToWorldDepthOffset; - - ConvertHomogeneous.ToWorld_GameCameraYaw = yaw; - ConvertHomogeneous.ToWorld_GameCameraPitch = pitch; - } - else - { - position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); - direction = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); - } + if (Config.DdrawDisableLighting) + { + (*d3d9Device)->SetRenderState(D3DRS_LIGHTING, FALSE); + } + } - // Store the original matrix so it can be restored - ConvertHomogeneous.ToWorld_ViewMatrixOriginal = view; + return hr; + } - // The Black & White matrix is an ortho camera, so create a perspective one matching the game - const float fov = Config.DdrawConvertHomogeneousToWorldFOV; - const float nearplane = Config.DdrawConvertHomogeneousToWorldNearPlane; - const float farplane = Config.DdrawConvertHomogeneousToWorldFarPlane; - const float ratio = width / height; - DirectX::XMMATRIX proj = DirectX::XMMatrixPerspectiveFovLH(fov * (3.14159265359f / 180.0f), ratio, nearplane, farplane); + switch (ProxyDirectXVersion) + { + case 1: + return GetProxyInterfaceV1()->BeginScene(); + case 2: + return GetProxyInterfaceV2()->BeginScene(); + case 3: + return GetProxyInterfaceV3()->BeginScene(); + case 7: + return GetProxyInterfaceV7()->BeginScene(); + default: + return DDERR_GENERIC; + } +} - DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ProjectionMatrix, proj); +HRESULT m_IDirect3DDeviceX::EndScene() +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - DirectX::XMVECTOR upVector = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); - DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, upVector); + if (Config.Dd7to9) + { + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; + } - // Store the 3D view matrix so it can be set later - DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ViewMatrix, viewMatrix); + // The IDirect3DDevice7::EndScene method ends a scene that was begun by calling the IDirect3DDevice7::BeginScene method. + // When this method succeeds, the scene has been rendered, and the device surface holds the rendered scene. - // Store the view inverse matrix of the game, so we can transform the geometry with it - DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)&view); - DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj); - DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp); + HRESULT hr = (*d3d9Device)->EndScene(); - DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, depthOffset); + if (SUCCEEDED(hr)) + { + IsInScene = false; - ConvertHomogeneous.ToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); - } +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(sceneTime); +#endif - // Override original matrix pointer - lpD3DMatrix = &view; - } - } - else + m_IDirectDrawSurfaceX* PrimarySurface = ddrawParent->GetPrimarySurface(); + if (!PrimarySurface || FAILED(PrimarySurface->GetFlipStatus(DDGFS_CANFLIP, true)) || PrimarySurface == ddrawParent->GetRenderTargetSurface() || !PrimarySurface->IsRenderTarget()) { - return D3D_OK; + ddrawParent->PresentScene(nullptr); } } - HRESULT hr = SetD9Transform(dtstTransformStateType, lpD3DMatrix); - -#ifdef ENABLE_DEBUGOVERLAY - if (SUCCEEDED(hr) && !Config.DdrawConvertHomogeneousW) - { - DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix); - } -#endif - return hr; } switch (ProxyDirectXVersion) { case 1: - default: - return DDERR_GENERIC; + return GetProxyInterfaceV1()->EndScene(); case 2: - return GetProxyInterfaceV2()->SetTransform(dtstTransformStateType, lpD3DMatrix); + return GetProxyInterfaceV2()->EndScene(); case 3: - return GetProxyInterfaceV3()->SetTransform(dtstTransformStateType, lpD3DMatrix); + return GetProxyInterfaceV3()->EndScene(); case 7: - return GetProxyInterfaceV7()->SetTransform(dtstTransformStateType, lpD3DMatrix); + return GetProxyInterfaceV7()->EndScene(); + default: + return DDERR_GENERIC; } } -HRESULT m_IDirect3DDeviceX::GetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix) +HRESULT m_IDirect3DDeviceX::GetDirect3D(LPDIRECT3D7* lplpD3D, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpD3DMatrix) + if (!lplpD3D) { - return DDERR_INVALIDPARAMS; + return DDERR_INVALIDPARAMS; } + *lplpD3D = nullptr; // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + if (FAILED(CheckInterface(__FUNCTION__, false))) { return DDERR_INVALIDOBJECT; } - switch ((DWORD)dtstTransformStateType) + m_IDirect3DX** lplpD3DX = ddrawParent->GetCurrentD3D(); + + if (!(*lplpD3DX)) { - case D3DTRANSFORMSTATE_WORLD: - dtstTransformStateType = D3DTS_WORLD; - break; - case D3DTRANSFORMSTATE_WORLD1: - dtstTransformStateType = D3DTS_WORLD1; - break; - case D3DTRANSFORMSTATE_WORLD2: - dtstTransformStateType = D3DTS_WORLD2; - break; - case D3DTRANSFORMSTATE_WORLD3: - dtstTransformStateType = D3DTS_WORLD3; - break; + LOG_LIMIT(100, __FUNCTION__ << " Error: missing Direct3D wrapper!"); + return DDERR_GENERIC; } - return (*d3d9Device)->GetTransform(dtstTransformStateType, lpD3DMatrix); + *lplpD3D = (LPDIRECT3D7)(*lplpD3DX)->GetWrapperInterfaceX(DirectXVersion); + + if (!(*lplpD3D)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get Direct3D interface!"); + return DDERR_GENERIC; + } + + (*lplpD3D)->AddRef(); + + return D3D_OK; } + HRESULT hr = DDERR_GENERIC; + switch (ProxyDirectXVersion) { case 1: - default: - return DDERR_GENERIC; + hr = GetProxyInterfaceV1()->GetDirect3D((LPDIRECT3D*)lplpD3D); + break; case 2: - return GetProxyInterfaceV2()->GetTransform(dtstTransformStateType, lpD3DMatrix); + hr = GetProxyInterfaceV2()->GetDirect3D((LPDIRECT3D2*)lplpD3D); + break; case 3: - return GetProxyInterfaceV3()->GetTransform(dtstTransformStateType, lpD3DMatrix); + hr = GetProxyInterfaceV3()->GetDirect3D((LPDIRECT3D3*)lplpD3D); + break; case 7: - return GetProxyInterfaceV7()->GetTransform(dtstTransformStateType, lpD3DMatrix); - } -} - -HRESULT m_IDirect3DDeviceX::PreLoad(LPDIRECTDRAWSURFACE7 lpddsTexture) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (Config.Dd7to9) - { - // Textures are loaded as managed in Direct3D9, so there is no need to manualy preload textures - return D3D_OK; + hr = GetProxyInterfaceV7()->GetDirect3D(lplpD3D); + break; } - if (lpddsTexture) + if (SUCCEEDED(hr) && lplpD3D) { - lpddsTexture->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpddsTexture); + *lplpD3D = ProxyAddressLookupTable.FindAddress(*lplpD3D, DirectXVersion); } - return GetProxyInterfaceV7()->PreLoad(lpddsTexture); + return hr; } -HRESULT m_IDirect3DDeviceX::Load(LPDIRECTDRAWSURFACE7 lpDestTex, LPPOINT lpDestPoint, LPDIRECTDRAWSURFACE7 lpSrcTex, LPRECT lprcSrcRect, DWORD dwFlags) +// ****************************** +// IDirect3DDevice v2 functions +// ****************************** + +HRESULT m_IDirect3DDeviceX::SetCurrentViewport(LPDIRECT3DVIEWPORT3 lpd3dViewport) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpDestTex || !lpSrcTex) + // Before calling this method, applications must have already called the AddViewport method to add the viewport to the device. + if (!lpd3dViewport || !IsViewportAttached(lpd3dViewport)) { - return DDERR_INVALIDPARAMS; + return DDERR_INVALIDPARAMS; } - // ToDo: support the following dwFlags: - // DDSCAPS2_CUBEMAP_ALLFACES - All faces should be loaded with the image data within the source texture. - // DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_NEGATIVEY, or DDSCAPS2_CUBEMAP_NEGATIVEZ - // The negative x, y, or z faces should receive the image data. - // DDSCAPS2_CUBEMAP_POSITIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, or DDSCAPS2_CUBEMAP_POSITIVEZ - // The positive x, y, or z faces should receive the image data. - - if (dwFlags) + m_IDirect3DViewportX* lpViewportX = nullptr; + if (FAILED(lpd3dViewport->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpViewportX))) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: flags not supported. dwFlags: " << Logging::hex(dwFlags)); + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get ViewportX interface!"); + return DDERR_GENERIC; } - if (!lprcSrcRect && (!lpDestPoint || (lpDestPoint && lpDestPoint->x == 0 && lpDestPoint->y == 0))) + // Check if assigning a viewport associated with this device { - return lpDestTex->Blt(nullptr, lpSrcTex, nullptr, 0, nullptr); - } - else - { - // Get source rect - RECT SrcRect = {}; - if (lprcSrcRect) + m_IDirect3DDeviceX* pViewPort3DDevice = lpViewportX->GetD3DDevice(); + if (pViewPort3DDevice != this) { - SrcRect = *lprcSrcRect; + LOG_LIMIT(100, __FUNCTION__ << " (" << this << ") Warning: Viewport's Direct3D device doesn't match current one: " << pViewPort3DDevice); } - else - { - DDSURFACEDESC2 Desc2 = {}; - Desc2.dwSize = sizeof(DDSURFACEDESC2); - lpSrcTex->GetSurfaceDesc(&Desc2); + } - if ((Desc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT)) != (DDSD_WIDTH | DDSD_HEIGHT)) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: rect size doesn't match!"); - return DDERR_GENERIC; - } + D3DVIEWPORT Viewport = {}; + Viewport.dwSize = sizeof(D3DVIEWPORT); - SrcRect = { 0, 0, (LONG)Desc2.dwWidth, (LONG)Desc2.dwHeight }; - } + HRESULT hr = lpd3dViewport->GetViewport(&Viewport); + + if (SUCCEEDED(hr)) + { + D3DVIEWPORT7 Viewport7; - // Get destination point - POINT DestPoint = {}; - if (lpDestPoint) + ConvertViewport(Viewport7, Viewport); + + hr = SetViewport(&Viewport7); + + if (SUCCEEDED(hr)) { - DestPoint = *lpDestPoint; - } + lpCurrentViewport = lpd3dViewport; + + lpCurrentViewport->AddRef(); - // Get destination rect - RECT DestRect = { - DestPoint.x, // left - DestPoint.y, // top - DestPoint.x + (SrcRect.right - SrcRect.left), // right - DestPoint.y + (SrcRect.bottom - SrcRect.top), // bottom - }; + lpCurrentViewportX = lpViewportX; - return lpDestTex->Blt(&DestRect, lpSrcTex, &SrcRect, 0, nullptr); + lpCurrentViewportX->SetCurrentViewportActive(true, true, true); + } } - } - if (lpDestTex) - { - lpDestTex->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDestTex); + return hr; } - if (lpSrcTex) + + if (lpd3dViewport) { - lpSrcTex->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpSrcTex); + lpd3dViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpd3dViewport); } - return GetProxyInterfaceV7()->Load(lpDestTex, lpDestPoint, lpSrcTex, lprcSrcRect, dwFlags); -} + switch (ProxyDirectXVersion) + { + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->SetCurrentViewport(lpd3dViewport); + case 3: + return GetProxyInterfaceV3()->SetCurrentViewport(lpd3dViewport); + } +} -HRESULT m_IDirect3DDeviceX::SwapTextureHandles(LPDIRECT3DTEXTURE2 lpD3DTex1, LPDIRECT3DTEXTURE2 lpD3DTex2) +HRESULT m_IDirect3DDeviceX::GetCurrentViewport(LPDIRECT3DVIEWPORT3* lplpd3dViewport, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion > 2) + if (Config.Dd7to9) { - - if (!lpD3DTex1 || !lpD3DTex2) - { - return DDERR_INVALIDPARAMS; - } - - m_IDirect3DTextureX* pTextureX1 = nullptr; - lpD3DTex1->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pTextureX1); - - m_IDirect3DTextureX* pTextureX2 = nullptr; - lpD3DTex2->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pTextureX2); - - if (!pTextureX1 || !pTextureX2) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture wrapper!"); - return DDERR_INVALIDPARAMS; - } - - // Find handle associated with texture1 - D3DTEXTUREHANDLE TexHandle1 = 0; - if (FAILED(pTextureX1->GetHandle((LPDIRECT3DDEVICE2)GetWrapperInterfaceX(0), &TexHandle1))) + if (!lplpd3dViewport) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not find texture1 handle!"); return DDERR_INVALIDPARAMS; } - // Find handle associated with texture2 - D3DTEXTUREHANDLE TexHandle2 = 0; - if (FAILED(pTextureX2->GetHandle((LPDIRECT3DDEVICE2)GetWrapperInterfaceX(0), &TexHandle2))) + if (!lpCurrentViewport) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not find texture2 handle!"); - return DDERR_INVALIDPARAMS; + return D3DERR_NOCURRENTVIEWPORT; } - // Swap texture handle1 - pTextureX1->SetHandle(TexHandle2); - TextureHandleMap[TexHandle2] = pTextureX1; - - // Swap texture handle2 - pTextureX2->SetHandle(TexHandle1); - TextureHandleMap[TexHandle1] = pTextureX2; + *lplpd3dViewport = lpCurrentViewport; - // If texture handle is set then use new texture - if (rsTextureHandle == TexHandle1 || rsTextureHandle == TexHandle2) - { - SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, rsTextureHandle); - } + lpCurrentViewport->AddRef(); return D3D_OK; } - if (lpD3DTex1) - { - lpD3DTex1->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpD3DTex1); - } - if (lpD3DTex2) - { - lpD3DTex2->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpD3DTex2); - } + HRESULT hr = DDERR_GENERIC; switch (ProxyDirectXVersion) { - case 1: - return GetProxyInterfaceV1()->SwapTextureHandles((LPDIRECT3DTEXTURE)lpD3DTex1, (LPDIRECT3DTEXTURE)lpD3DTex2); case 2: - return GetProxyInterfaceV2()->SwapTextureHandles(lpD3DTex1, lpD3DTex2); - default: - return DDERR_GENERIC; + hr = GetProxyInterfaceV2()->GetCurrentViewport((LPDIRECT3DVIEWPORT2*)lplpd3dViewport); + break; + case 3: + hr = GetProxyInterfaceV3()->GetCurrentViewport(lplpd3dViewport); + break; } -} - -HRESULT m_IDirect3DDeviceX::EnumTextureFormats(LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc, LPVOID lpArg) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - switch (ProxyDirectXVersion) - { - case 1: - return GetProxyInterfaceV1()->EnumTextureFormats(lpd3dEnumTextureProc, lpArg); - case 2: - return GetProxyInterfaceV2()->EnumTextureFormats(lpd3dEnumTextureProc, lpArg); - case 3: - case 7: - case 9: + if (SUCCEEDED(hr) && lplpd3dViewport) { - if (!lpd3dEnumTextureProc) - { - return DDERR_INVALIDPARAMS; - } - - struct EnumPixelFormat - { - LPVOID lpContext; - LPD3DENUMTEXTUREFORMATSCALLBACK lpCallback; - - static HRESULT CALLBACK ConvertCallback(LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext) - { - EnumPixelFormat* self = (EnumPixelFormat*)lpContext; - - // Only RGB formats are supported - if ((lpDDPixFmt->dwFlags & DDPF_RGB) == NULL) - { - return DDENUMRET_OK; - } - - DDSURFACEDESC Desc = {}; - Desc.dwSize = sizeof(DDSURFACEDESC); - Desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT; - Desc.ddpfPixelFormat = *lpDDPixFmt; - Desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE; - - return self->lpCallback(&Desc, self->lpContext); - } - } CallbackContext = {}; - CallbackContext.lpContext = lpArg; - CallbackContext.lpCallback = lpd3dEnumTextureProc; - - return EnumTextureFormats(EnumPixelFormat::ConvertCallback, &CallbackContext); - } - default: - return DDERR_GENERIC; + *lplpd3dViewport = ProxyAddressLookupTable.FindAddress(*lplpd3dViewport, DirectXVersion); } + + return hr; } -HRESULT m_IDirect3DDeviceX::EnumTextureFormats(LPD3DENUMPIXELFORMATSCALLBACK lpd3dEnumPixelProc, LPVOID lpArg) +HRESULT m_IDirect3DDeviceX::SetRenderTarget(LPDIRECTDRAWSURFACE7 lpNewRenderTarget, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpd3dEnumPixelProc) + if (!lpNewRenderTarget) { return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, false))) + // Don't reset existing render target + if (CurrentRenderTarget == lpNewRenderTarget) { - return DDERR_INVALIDOBJECT; + return D3D_OK; } - LPDIRECT3D9 d3d9Object = ddrawParent->GetDirectD9Object(); + // dwFlags: Not currently used; set to 0. - if (!d3d9Object) + // ToDo: if DirectXVersion < 7 then invalidate the current material and viewport: + // Unlike this method's implementation in previous interfaces, IDirect3DDevice7::SetRenderTarget does not invalidate the current material or viewport for the device. + + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get d3d9 object!"); - return DDERR_GENERIC; + return DDERR_INVALIDOBJECT; } - // Get texture list - std::vector TextureList = { - D3DFMT_R5G6B5, - D3DFMT_X1R5G5B5, - D3DFMT_A1R5G5B5, - D3DFMT_A4R4G4B4, - //D3DFMT_R8G8B8, // Requires emulation - D3DFMT_X8R8G8B8, - D3DFMT_A8R8G8B8, - D3DFMT_V8U8, - D3DFMT_X8L8V8U8, - D3DFMT_L6V5U5, - D3DFMT_YUY2, - D3DFMT_UYVY, - D3DFMT_AYUV, - D3DFMT_DXT1, - D3DFMT_DXT2, - D3DFMT_DXT3, - D3DFMT_DXT4, - D3DFMT_DXT5, - D3DFMT_P8, - D3DFMT_L8, - D3DFMT_A8, - D3DFMT_A4L4, - D3DFMT_A8L8 }; + m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr; + lpNewRenderTarget->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX); - // Add FourCCs to texture list - for (D3DFORMAT format : FourCCTypes) + if (!lpDDSrcSurfaceX) { - TextureList.push_back(format); + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface wrapper!"); + return DDERR_INVALIDPARAMS; } - // Check for supported textures - DDPIXELFORMAT ddpfPixelFormat = {}; - ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - - bool IsDirectDraw8bit = (ddrawParent->GetDisplayBPP(nullptr) == 8); + HRESULT hr = ddrawParent->SetRenderTargetSurface(lpDDSrcSurfaceX); - for (D3DFORMAT format : TextureList) + if (SUCCEEDED(hr)) { - if (!IsUnsupportedFormat(format) && ((format == D3DFMT_P8 && IsDirectDraw8bit) || - SUCCEEDED(d3d9Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, format)))) + if (CurrentRenderTarget) { - SetPixelDisplayFormat(format, ddpfPixelFormat); - if (lpd3dEnumPixelProc(&ddpfPixelFormat, lpArg) == DDENUMRET_CANCEL) - { - return D3D_OK; - } + CurrentRenderTarget->Release(); } + + CurrentRenderTarget = lpNewRenderTarget; + + lpCurrentRenderTargetX = lpDDSrcSurfaceX; + + CurrentRenderTarget->AddRef(); } return D3D_OK; } + if (lpNewRenderTarget) + { + lpNewRenderTarget->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpNewRenderTarget); + } + switch (ProxyDirectXVersion) { case 1: - case 2: default: return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->SetRenderTarget((LPDIRECTDRAWSURFACE)lpNewRenderTarget, dwFlags); case 3: - return GetProxyInterfaceV3()->EnumTextureFormats(lpd3dEnumPixelProc, lpArg); + return GetProxyInterfaceV3()->SetRenderTarget((LPDIRECTDRAWSURFACE4)lpNewRenderTarget, dwFlags); case 7: - return GetProxyInterfaceV7()->EnumTextureFormats(lpd3dEnumPixelProc, lpArg); + return GetProxyInterfaceV7()->SetRenderTarget(lpNewRenderTarget, dwFlags); } } -HRESULT m_IDirect3DDeviceX::GetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2* lplpTexture) +HRESULT m_IDirect3DDeviceX::GetRenderTarget(LPDIRECTDRAWSURFACE7* lplpRenderTarget, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { - if (!lplpTexture || dwStage >= MaxTextureStages) - { - return DDERR_INVALIDPARAMS; - } - *lplpTexture = nullptr; - - // Get surface stage - LPDIRECTDRAWSURFACE7 pSurface = nullptr; - HRESULT hr = GetTexture(dwStage, &pSurface); - - if (FAILED(hr)) - { - return hr; - } - - // First relese ref for surface - pSurface->Release(); - - // Get surface wrapper - m_IDirectDrawSurfaceX* pSurfaceX = nullptr; - pSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pSurfaceX); - if (!pSurfaceX) + if (!lplpRenderTarget) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface wrapper!"); return DDERR_INVALIDPARAMS; } - // Get attached texture from surface - m_IDirect3DTextureX* pTextureX = pSurfaceX->GetAttachedTexture(); - if (!pTextureX) + if (!CurrentRenderTarget) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture!"); - return DDERR_INVALIDPARAMS; + LOG_LIMIT(100, __FUNCTION__ << " Error: render target not set."); + return DDERR_GENERIC; } - // Add ref to texture - pTextureX->AddRef(); + *lplpRenderTarget = CurrentRenderTarget; - *lplpTexture = (LPDIRECT3DTEXTURE2)pTextureX->GetWrapperInterfaceX(0); + CurrentRenderTarget->AddRef(); return D3D_OK; } - HRESULT hr = GetProxyInterfaceV3()->GetTexture(dwStage, lplpTexture); + HRESULT hr = DDERR_GENERIC; - if (SUCCEEDED(hr) && lplpTexture) + switch (ProxyDirectXVersion) { - *lplpTexture = ProxyAddressLookupTable.FindAddress(*lplpTexture, 2); - } - + case 2: + hr = GetProxyInterfaceV2()->GetRenderTarget((LPDIRECTDRAWSURFACE*)lplpRenderTarget); + break; + case 3: + hr = GetProxyInterfaceV3()->GetRenderTarget((LPDIRECTDRAWSURFACE4*)lplpRenderTarget); + break; + case 7: + hr = GetProxyInterfaceV7()->GetRenderTarget(lplpRenderTarget); + break; + } + + if (SUCCEEDED(hr) && lplpRenderTarget) + { + *lplpRenderTarget = ProxyAddressLookupTable.FindAddress(*lplpRenderTarget, DirectXVersion); + } + return hr; } -HRESULT m_IDirect3DDeviceX::GetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7* lplpTexture) +HRESULT m_IDirect3DDeviceX::Begin(D3DPRIMITIVETYPE d3dpt, DWORD d3dvt, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lplpTexture || dwStage >= MaxTextureStages) - { - return DDERR_INVALIDPARAMS; - } - *lplpTexture = nullptr; - - HRESULT hr = DDERR_GENERIC; - - if (AttachedTexture[dwStage]) - { - AttachedTexture[dwStage]->AddRef(); - - *lplpTexture = AttachedTexture[dwStage]; - - hr = D3D_OK; - } - - return hr; + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; } - HRESULT hr = GetProxyInterfaceV7()->GetTexture(dwStage, lplpTexture); - - if (SUCCEEDED(hr) && lplpTexture) + switch (ProxyDirectXVersion) { - *lplpTexture = ProxyAddressLookupTable.FindAddress(*lplpTexture, 7); + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->Begin(d3dpt, (D3DVERTEXTYPE)d3dvt, dwFlags); + case 3: + return GetProxyInterfaceV3()->Begin(d3dpt, d3dvt, dwFlags); } - - return hr; } -void m_IDirect3DDeviceX::ClearTextureHandle(D3DTEXTUREHANDLE tHandle) +HRESULT m_IDirect3DDeviceX::BeginIndexed(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dvtVertexType, LPVOID lpvVertices, DWORD dwNumVertices, DWORD dwFlags) { - if (tHandle) + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { - TextureHandleMap.erase(tHandle); + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; + } - // If texture handle is set then clear it - if (rsTextureHandle == tHandle) - { - SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, 0); - } + switch (ProxyDirectXVersion) + { + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->BeginIndexed(dptPrimitiveType, (D3DVERTEXTYPE)dvtVertexType, lpvVertices, dwNumVertices, dwFlags); + case 3: + return GetProxyInterfaceV3()->BeginIndexed(dptPrimitiveType, dvtVertexType, lpvVertices, dwNumVertices, dwFlags); } } -HRESULT m_IDirect3DDeviceX::SetTextureHandle(D3DTEXTUREHANDLE& tHandle, m_IDirect3DTextureX* pTextureX) +HRESULT m_IDirect3DDeviceX::Vertex(LPVOID lpVertexType) { - if (!tHandle || !pTextureX) + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { - LOG_LIMIT(100, __FUNCTION__ << " Error: NULL pointer found! " << pTextureX << " -> " << tHandle); - return DDERR_INVALIDPARAMS; + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; } - // Ensure that the handle is unique - while (GetTexture(tHandle)) + switch (ProxyDirectXVersion) { - tHandle += 4; + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->Vertex(lpVertexType); + case 3: + return GetProxyInterfaceV3()->Vertex(lpVertexType); } - - TextureHandleMap[tHandle] = pTextureX; - - return D3D_OK; } -HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2 lpTexture) +HRESULT m_IDirect3DDeviceX::Index(WORD wVertexIndex) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { - if (dwStage >= MaxTextureStages) - { - return DDERR_INVALIDPARAMS; - } - - if (!lpTexture) - { - return SetTexture(dwStage, (LPDIRECTDRAWSURFACE7)nullptr); - } - - m_IDirect3DTextureX *pTextureX = nullptr; - lpTexture->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pTextureX); - if (!pTextureX) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture wrapper!"); - return DDERR_INVALIDPARAMS; - } - - m_IDirectDrawSurfaceX *pSurfaceX = pTextureX->GetSurface(); - if (!pSurfaceX) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface!"); - return DDERR_INVALIDPARAMS; - } - - return SetTexture(dwStage, (LPDIRECTDRAWSURFACE7)pSurfaceX->GetWrapperInterfaceX(0)); + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; } - if (lpTexture) + switch (ProxyDirectXVersion) { - lpTexture->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpTexture); + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->Index(wVertexIndex); + case 3: + return GetProxyInterfaceV3()->Index(wVertexIndex); } - - return GetProxyInterfaceV3()->SetTexture(dwStage, lpTexture); } -HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpSurface) +HRESULT m_IDirect3DDeviceX::End(DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (dwStage >= MaxTextureStages) - { - return DDERR_INVALIDPARAMS; - } - - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } - - m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr; - - HRESULT hr; - - if (!lpSurface) - { - hr = (*d3d9Device)->SetTexture(dwStage, nullptr); - } - else - { - lpSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX); - if (!lpDDSrcSurfaceX) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface wrapper!"); - return DDERR_INVALIDPARAMS; - } - - IDirect3DTexture9* pTexture9 = lpDDSrcSurfaceX->GetD3d9Texture(); - if (!pTexture9) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture!"); - return DDERR_INVALIDPARAMS; - } - - if (lpCurrentRenderTargetX && lpCurrentRenderTargetX->IsPalette() && !lpDDSrcSurfaceX->IsPalette()) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: setting non-palette texture on a paletted render target!"); - } - - hr = (*d3d9Device)->SetTexture(dwStage, pTexture9); - } - - if (SUCCEEDED(hr)) - { - AttachedTexture[dwStage] = lpSurface; - CurrentTextureSurfaceX[dwStage] = lpDDSrcSurfaceX; - } - - return hr; + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; } - if (lpSurface) + switch (ProxyDirectXVersion) { - lpSurface->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpSurface); + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->End(dwFlags); + case 3: + return GetProxyInterfaceV3()->End(dwFlags); } - - return GetProxyInterfaceV7()->SetTexture(dwStage, lpSurface); } -HRESULT m_IDirect3DDeviceX::SetRenderTarget(LPDIRECTDRAWSURFACE7 lpNewRenderTarget, DWORD dwFlags) +HRESULT m_IDirect3DDeviceX::GetRenderState(D3DRENDERSTATETYPE dwRenderStateType, LPDWORD lpdwRenderState) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << dwRenderStateType; if (Config.Dd7to9) { - if (!lpNewRenderTarget) + if (!lpdwRenderState) { + LOG_LIMIT(100, __FUNCTION__ << " Warning: Render state called with nullptr: " << dwRenderStateType); return DDERR_INVALIDPARAMS; } - // Don't reset existing render target - if (CurrentRenderTarget == lpNewRenderTarget) - { - return D3D_OK; - } - - // dwFlags: Not currently used; set to 0. - - // ToDo: if DirectXVersion < 7 then invalidate the current material and viewport: - // Unlike this method's implementation in previous interfaces, IDirect3DDevice7::SetRenderTarget does not invalidate the current material or viewport for the device. - // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, true))) { return DDERR_INVALIDOBJECT; } - m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr; - lpNewRenderTarget->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX); - - if (!lpDDSrcSurfaceX) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface wrapper!"); - return DDERR_INVALIDPARAMS; - } - - HRESULT hr = ddrawParent->SetRenderTargetSurface(lpDDSrcSurfaceX); - - if (SUCCEEDED(hr)) + switch ((DWORD)dwRenderStateType) { - if (CurrentRenderTarget) - { - CurrentRenderTarget->Release(); - } - - lpNewRenderTarget = CurrentRenderTarget; - - CurrentRenderTarget->AddRef(); - - lpCurrentRenderTargetX = lpDDSrcSurfaceX; - } - - return D3D_OK; - } - - if (lpNewRenderTarget) - { - lpNewRenderTarget->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpNewRenderTarget); - } - - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->SetRenderTarget((LPDIRECTDRAWSURFACE)lpNewRenderTarget, dwFlags); - case 3: - return GetProxyInterfaceV3()->SetRenderTarget((LPDIRECTDRAWSURFACE4)lpNewRenderTarget, dwFlags); - case 7: - return GetProxyInterfaceV7()->SetRenderTarget(lpNewRenderTarget, dwFlags); - } -} - -HRESULT m_IDirect3DDeviceX::GetRenderTarget(LPDIRECTDRAWSURFACE7* lplpRenderTarget, DWORD DirectXVersion) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (Config.Dd7to9) - { - if (!lplpRenderTarget) - { - return DDERR_INVALIDPARAMS; + case D3DRENDERSTATE_TEXTUREHANDLE: // 1 + *lpdwRenderState = rsTextureHandle; + return D3D_OK; + case D3DRENDERSTATE_ANTIALIAS: // 2 + *lpdwRenderState = rsAntiAlias; + return D3D_OK; + case D3DRENDERSTATE_TEXTUREADDRESS: // 3 + return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESS, lpdwRenderState); + case D3DRENDERSTATE_TEXTUREPERSPECTIVE: // 4 + *lpdwRenderState = rsTexturePerspective; + return D3D_OK; + case D3DRENDERSTATE_WRAPU: // 5 + *lpdwRenderState = rsTextureWrappingU; + return D3D_OK; + case D3DRENDERSTATE_WRAPV: // 6 + *lpdwRenderState = rsTextureWrappingV; + return D3D_OK; + case D3DRENDERSTATE_LINEPATTERN: // 10 + *lpdwRenderState = 0; + return D3D_OK; + case D3DRENDERSTATE_MONOENABLE: // 11 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_ROP2: // 12 + *lpdwRenderState = R2_COPYPEN; + return D3D_OK; + case D3DRENDERSTATE_PLANEMASK: // 13 + *lpdwRenderState = (DWORD)-1; + return D3D_OK; + case D3DRENDERSTATE_TEXTUREMAG: // 17 + return (*d3d9Device)->GetSamplerState(0, D3DSAMP_MAGFILTER, lpdwRenderState); + case D3DRENDERSTATE_TEXTUREMIN: // 18 + *lpdwRenderState = rsTextureMin; + return D3D_OK; + case D3DRENDERSTATE_TEXTUREMAPBLEND: // 21 + *lpdwRenderState = rsTextureMapBlend; + return D3D_OK; + case D3DRENDERSTATE_ZVISIBLE: // 30 + // This render state is not supported. + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_SUBPIXEL: // 31 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_SUBPIXELX: // 32 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_STIPPLEDALPHA: // 33 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_STIPPLEENABLE: // 39 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_EDGEANTIALIAS: // 40 + *lpdwRenderState = rsEdgeAntiAlias; + return D3D_OK; + case D3DRENDERSTATE_COLORKEYENABLE: // 41 + *lpdwRenderState = rsColorKeyEnabled; + return D3D_OK; + case D3DRENDERSTATE_OLDALPHABLENDENABLE:// 42 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_BORDERCOLOR: // 43 + *lpdwRenderState = 0x00000000; + return D3D_OK; + case D3DRENDERSTATE_TEXTUREADDRESSU: // 44 + return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, lpdwRenderState); + case D3DRENDERSTATE_TEXTUREADDRESSV: // 45 + return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, lpdwRenderState); + case D3DRENDERSTATE_MIPMAPLODBIAS: // 46 + return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MIPMAPLODBIAS, lpdwRenderState); + case D3DRENDERSTATE_ZBIAS: // 47 + (*d3d9Device)->GetRenderState(D3DRS_DEPTHBIAS, lpdwRenderState); + *lpdwRenderState = static_cast(*reinterpret_cast(lpdwRenderState) * -200000.0f); + return D3D_OK; + case D3DRENDERSTATE_FLUSHBATCH: // 50 + *lpdwRenderState = 0; + return D3D_OK; + case D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT: // 51 + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_STIPPLEPATTERN00: // 64 + case D3DRENDERSTATE_STIPPLEPATTERN01: // 65 + case D3DRENDERSTATE_STIPPLEPATTERN02: // 66 + case D3DRENDERSTATE_STIPPLEPATTERN03: // 67 + case D3DRENDERSTATE_STIPPLEPATTERN04: // 68 + case D3DRENDERSTATE_STIPPLEPATTERN05: // 69 + case D3DRENDERSTATE_STIPPLEPATTERN06: // 70 + case D3DRENDERSTATE_STIPPLEPATTERN07: // 71 + case D3DRENDERSTATE_STIPPLEPATTERN08: // 72 + case D3DRENDERSTATE_STIPPLEPATTERN09: // 73 + case D3DRENDERSTATE_STIPPLEPATTERN10: // 74 + case D3DRENDERSTATE_STIPPLEPATTERN11: // 75 + case D3DRENDERSTATE_STIPPLEPATTERN12: // 76 + case D3DRENDERSTATE_STIPPLEPATTERN13: // 77 + case D3DRENDERSTATE_STIPPLEPATTERN14: // 78 + case D3DRENDERSTATE_STIPPLEPATTERN15: // 79 + case D3DRENDERSTATE_STIPPLEPATTERN16: // 80 + case D3DRENDERSTATE_STIPPLEPATTERN17: // 81 + case D3DRENDERSTATE_STIPPLEPATTERN18: // 82 + case D3DRENDERSTATE_STIPPLEPATTERN19: // 83 + case D3DRENDERSTATE_STIPPLEPATTERN20: // 84 + case D3DRENDERSTATE_STIPPLEPATTERN21: // 85 + case D3DRENDERSTATE_STIPPLEPATTERN22: // 86 + case D3DRENDERSTATE_STIPPLEPATTERN23: // 87 + case D3DRENDERSTATE_STIPPLEPATTERN24: // 88 + case D3DRENDERSTATE_STIPPLEPATTERN25: // 89 + case D3DRENDERSTATE_STIPPLEPATTERN26: // 90 + case D3DRENDERSTATE_STIPPLEPATTERN27: // 91 + case D3DRENDERSTATE_STIPPLEPATTERN28: // 92 + case D3DRENDERSTATE_STIPPLEPATTERN29: // 93 + case D3DRENDERSTATE_STIPPLEPATTERN30: // 94 + case D3DRENDERSTATE_STIPPLEPATTERN31: // 95 + *lpdwRenderState = 0; + return D3D_OK; + case D3DRENDERSTATE_EXTENTS: // 138 + // ToDo: use this to report on clip plane extents set by SetClipStatus() + *lpdwRenderState = FALSE; + return D3D_OK; + case D3DRENDERSTATE_COLORKEYBLENDENABLE:// 144 + *lpdwRenderState = FALSE; + return D3D_OK; } - if (!CurrentRenderTarget) + if (!CheckRenderStateType(dwRenderStateType)) { - LOG_LIMIT(100, __FUNCTION__ << " Error: render target not set."); - return DDERR_GENERIC; + LOG_LIMIT(100, __FUNCTION__ << " Warning: Render state type not implemented: " << dwRenderStateType); + *lpdwRenderState = 0; + return D3D_OK; // Just return OK for now! } - *lplpRenderTarget = CurrentRenderTarget; - - CurrentRenderTarget->AddRef(); - - return D3D_OK; + return (*d3d9Device)->GetRenderState(dwRenderStateType, lpdwRenderState); } - HRESULT hr = DDERR_GENERIC; - switch (ProxyDirectXVersion) { + case 1: + default: + return DDERR_GENERIC; case 2: - hr = GetProxyInterfaceV2()->GetRenderTarget((LPDIRECTDRAWSURFACE*)lplpRenderTarget); - break; + return GetProxyInterfaceV2()->GetRenderState(dwRenderStateType, lpdwRenderState); case 3: - hr = GetProxyInterfaceV3()->GetRenderTarget((LPDIRECTDRAWSURFACE4*)lplpRenderTarget); - break; + return GetProxyInterfaceV3()->GetRenderState(dwRenderStateType, lpdwRenderState); case 7: - hr = GetProxyInterfaceV7()->GetRenderTarget(lplpRenderTarget); - break; - } - - if (SUCCEEDED(hr) && lplpRenderTarget) - { - *lplpRenderTarget = ProxyAddressLookupTable.FindAddress(*lplpRenderTarget, DirectXVersion); + return GetProxyInterfaceV7()->GetRenderState(dwRenderStateType, lpdwRenderState); } - - return hr; } -HRESULT m_IDirect3DDeviceX::GetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, LPDWORD lpdwValue) +HRESULT m_IDirect3DDeviceX::SetRenderState(D3DRENDERSTATETYPE dwRenderStateType, DWORD dwRenderState) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << dwRenderStateType << " " << dwRenderState; if (Config.Dd7to9) { - if (!lpdwValue) - { - return DDERR_INVALIDPARAMS; - } - // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, true))) { return DDERR_INVALIDOBJECT; } - switch ((DWORD)dwState) + switch ((DWORD)dwRenderStateType) { - case D3DTSS_ADDRESS: + case D3DRENDERSTATE_TEXTUREHANDLE: // 1 { - DWORD ValueU = 0, ValueV = 0; - (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSU, &ValueU); - (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSV, &ValueV); - if (ValueU == ValueV) + rsTextureHandle = dwRenderState; + if (dwRenderState == NULL) { - *lpdwValue = ValueU; - return D3D_OK; + return SetTexture(0, (LPDIRECT3DTEXTURE2)nullptr); } - else + m_IDirect3DTextureX* pTextureX = GetTexture(dwRenderState); + if (pTextureX) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: AddressU and AddressV don't match"); - *lpdwValue = 0; - return D3D_OK; + IDirect3DTexture2* lpTexture = (IDirect3DTexture2*)pTextureX->GetWrapperInterfaceX(0); + if (!lpTexture) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture address!"); + return DDERR_INVALIDPARAMS; + } + + return SetTexture(0, lpTexture); } - } - case D3DTSS_ADDRESSU: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSU, lpdwValue); - case D3DTSS_ADDRESSV: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSV, lpdwValue); - case D3DTSS_ADDRESSW: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSW, lpdwValue); - case D3DTSS_BORDERCOLOR: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_BORDERCOLOR, lpdwValue); - case D3DTSS_MAGFILTER: - { - HRESULT hr = (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MAGFILTER, lpdwValue); - if (SUCCEEDED(hr) && *lpdwValue == D3DTEXF_ANISOTROPIC) + else { - *lpdwValue = D3DTFG_ANISOTROPIC; + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture handle!"); + return SetTexture(0, (LPDIRECT3DTEXTURE2)nullptr); } - return hr; + return D3D_OK; } - case D3DTSS_MINFILTER: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MINFILTER, lpdwValue); - case D3DTSS_MIPFILTER: - { - HRESULT hr = (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MIPFILTER, lpdwValue); - if (SUCCEEDED(hr)) + case D3DRENDERSTATE_ANTIALIAS: // 2 + rsAntiAliasChanged = true; + rsAntiAlias = dwRenderStateType; + return D3D_OK; + case D3DRENDERSTATE_TEXTUREADDRESS: // 3 + return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESS, dwRenderState); + case D3DRENDERSTATE_TEXTUREPERSPECTIVE: // 4 + if (dwRenderState != rsTexturePerspective) { - switch (*lpdwValue) - { - default: - case D3DTEXF_NONE: - *lpdwValue = D3DTFP_NONE; - break; - case D3DTEXF_POINT: - *lpdwValue = D3DTFP_POINT; - break; - case D3DTEXF_LINEAR: - *lpdwValue = D3DTFP_LINEAR; - break; - } + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_TEXTUREPERSPECTIVE' not implemented: " << dwRenderState); } - return hr; - } - case D3DTSS_MIPMAPLODBIAS: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MIPMAPLODBIAS, lpdwValue); - case D3DTSS_MAXMIPLEVEL: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MAXMIPLEVEL, lpdwValue); - case D3DTSS_MAXANISOTROPY: - return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MAXANISOTROPY, lpdwValue); - } - - if (!CheckTextureStageStateType(dwState)) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Texture Stage state type not implemented: " << dwState); - } - - return (*d3d9Device)->GetTextureStageState(dwStage, dwState, lpdwValue); - } - - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->GetTextureStageState(dwStage, dwState, lpdwValue); - case 7: - return GetProxyInterfaceV7()->GetTextureStageState(dwStage, dwState, lpdwValue); - } -} - -HRESULT m_IDirect3DDeviceX::SetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (Config.Dd7to9) - { - if (dwStage >= MaxTextureStages) - { - return DDERR_INVALIDPARAMS; - } - - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } - - switch ((DWORD)dwState) - { - case D3DTSS_ADDRESS: - SetD9SamplerState(dwStage, D3DSAMP_ADDRESSU, dwValue); - return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSV, dwValue); - case D3DTSS_ADDRESSU: - return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSU, dwValue); - case D3DTSS_ADDRESSV: - return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSV, dwValue); - case D3DTSS_ADDRESSW: - return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSW, dwValue); - case D3DTSS_BORDERCOLOR: - return SetD9SamplerState(dwStage, D3DSAMP_BORDERCOLOR, dwValue); - case D3DTSS_MAGFILTER: - if (dwValue == D3DTFG_ANISOTROPIC) + rsTexturePerspective = dwRenderState; + return D3D_OK; + case D3DRENDERSTATE_WRAPU: // 5 + rsTextureWrappingChanged = true; + rsTextureWrappingU = dwRenderState; + return D3D_OK; + case D3DRENDERSTATE_WRAPV: // 6 + rsTextureWrappingChanged = true; + rsTextureWrappingV = dwRenderState; + return D3D_OK; + case D3DRENDERSTATE_LINEPATTERN: // 10 + if (dwRenderState != 0) { - dwValue = D3DTEXF_ANISOTROPIC; + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_LINEPATTERN' not implemented: " << dwRenderState); } - else if (dwValue == D3DTFG_FLATCUBIC || dwValue == D3DTFG_GAUSSIANCUBIC) + return D3D_OK; + case D3DRENDERSTATE_MONOENABLE: // 11 + if (dwRenderState != FALSE) { - dwValue = D3DTEXF_LINEAR; + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_MONOENABLE' not implemented: " << dwRenderState); } - return SetD9SamplerState(dwStage, D3DSAMP_MAGFILTER, dwValue); - case D3DTSS_MINFILTER: - return SetD9SamplerState(dwStage, D3DSAMP_MINFILTER, dwValue); - case D3DTSS_MIPFILTER: - switch (dwValue) + return D3D_OK; + case D3DRENDERSTATE_ROP2: // 12 + if (dwRenderState != R2_COPYPEN) { - default: - case D3DTFP_NONE: - dwValue = D3DTEXF_NONE; - break; - case D3DTFP_POINT: - dwValue = D3DTEXF_POINT; - break; - case D3DTFP_LINEAR: - dwValue = D3DTEXF_LINEAR; - break; + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_ROP2' not implemented: " << dwRenderState); } - ssMipFilter[dwStage] = dwValue; - return SetD9SamplerState(dwStage, D3DSAMP_MIPFILTER, dwValue); - case D3DTSS_MIPMAPLODBIAS: - return SetD9SamplerState(dwStage, D3DSAMP_MIPMAPLODBIAS, dwValue); - case D3DTSS_MAXMIPLEVEL: - return SetD9SamplerState(dwStage, D3DSAMP_MAXMIPLEVEL, dwValue); - case D3DTSS_MAXANISOTROPY: - return SetD9SamplerState(dwStage, D3DSAMP_MAXANISOTROPY, dwValue); - } - - if (!CheckTextureStageStateType(dwState)) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Texture Stage state type not implemented: " << dwState); - return D3D_OK; // Just return OK for now! - } - - return SetD9TextureStageState(dwStage, dwState, dwValue); - } - - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->SetTextureStageState(dwStage, dwState, dwValue); - case 7: - return GetProxyInterfaceV7()->SetTextureStageState(dwStage, dwState, dwValue); - } -} - -HRESULT m_IDirect3DDeviceX::GetCaps(LPD3DDEVICEDESC lpD3DHWDevDesc, LPD3DDEVICEDESC lpD3DHELDevDesc) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - switch (ProxyDirectXVersion) - { - case 1: - return GetProxyInterfaceV1()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc); - case 2: - return GetProxyInterfaceV2()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc); - case 3: - return GetProxyInterfaceV3()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc); - case 7: - case 9: - { - if ((!lpD3DHWDevDesc && !lpD3DHELDevDesc) || - (lpD3DHWDevDesc && lpD3DHWDevDesc->dwSize != D3DDEVICEDESC1_SIZE && lpD3DHWDevDesc->dwSize != D3DDEVICEDESC5_SIZE && lpD3DHWDevDesc->dwSize != D3DDEVICEDESC6_SIZE) || - (lpD3DHELDevDesc && lpD3DHELDevDesc->dwSize != D3DDEVICEDESC1_SIZE && lpD3DHELDevDesc->dwSize != D3DDEVICEDESC5_SIZE && lpD3DHELDevDesc->dwSize != D3DDEVICEDESC6_SIZE)) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Incorrect dwSize: " << ((lpD3DHWDevDesc) ? lpD3DHWDevDesc->dwSize : -1) << " " << ((lpD3DHELDevDesc) ? lpD3DHELDevDesc->dwSize : -1)); - return DDERR_INVALIDPARAMS; - } - - D3DDEVICEDESC7 D3DDevDesc; - HRESULT hr = GetCaps(&D3DDevDesc); - - if (SUCCEEDED(hr)) - { - if (lpD3DHWDevDesc) + return D3D_OK; + case D3DRENDERSTATE_PLANEMASK: // 13 + if (dwRenderState != (DWORD)-1) { - ConvertDeviceDesc(*lpD3DHWDevDesc, D3DDevDesc); + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_PLANEMASK' not implemented: " << dwRenderState); } - - if (lpD3DHELDevDesc) + return D3D_OK; + case D3DRENDERSTATE_TEXTUREMAG: // 17 + // Only the first two (D3DFILTER_NEAREST and D3DFILTER_LINEAR) are valid with D3DRENDERSTATE_TEXTUREMAG. + switch (dwRenderState) { - ConvertDeviceDesc(*lpD3DHELDevDesc, D3DDevDesc); + case D3DFILTER_NEAREST: + case D3DFILTER_LINEAR: + return SetD9SamplerState(0, D3DSAMP_MAGFILTER, dwRenderState); + default: + LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DRENDERSTATE_TEXTUREMAG' state: " << dwRenderState); + return DDERR_INVALIDPARAMS; } - } - - return hr; - } - default: - return DDERR_GENERIC; - } -} + case D3DRENDERSTATE_TEXTUREMIN: // 18 + switch (dwRenderState) + { + case D3DFILTER_NEAREST: + case D3DFILTER_LINEAR: + rsTextureMin = dwRenderState; + ssMipFilter[0] = D3DTEXF_NONE; + SetD9SamplerState(0, D3DSAMP_MINFILTER, dwRenderState); + return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + case D3DFILTER_MIPNEAREST: + rsTextureMin = dwRenderState; + ssMipFilter[0] = D3DTEXF_POINT; + SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); + case D3DFILTER_MIPLINEAR: + rsTextureMin = dwRenderState; + ssMipFilter[0] = D3DTEXF_POINT; + SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); + case D3DFILTER_LINEARMIPNEAREST: + rsTextureMin = dwRenderState; + ssMipFilter[0] = D3DTEXF_LINEAR; + SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + case D3DFILTER_LINEARMIPLINEAR: + rsTextureMin = dwRenderState; + ssMipFilter[0] = D3DTEXF_LINEAR; + SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + default: + LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DRENDERSTATE_TEXTUREMIN' state: " << dwRenderState); + return DDERR_INVALIDPARAMS; + } + case D3DRENDERSTATE_SRCBLEND: // 19 + rsSrcBlend = dwRenderState; + break; + case D3DRENDERSTATE_DESTBLEND: // 20 + rsDestBlend = dwRenderState; + break; + case D3DRENDERSTATE_TEXTUREMAPBLEND: // 21 + switch (dwRenderState) + { + case D3DTBLEND_COPY: + case D3DTBLEND_DECAL: + // Reset states + SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT); -HRESULT m_IDirect3DDeviceX::GetCaps(LPD3DDEVICEDESC7 lpD3DDevDesc) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Decal texture-blending mode is supported. In this mode, the RGB and alpha values of the texture replace the colors that would have been used with no texturing. + SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); + SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); - if (Config.Dd7to9) - { - if (!lpD3DDevDesc) - { - return DDERR_INVALIDPARAMS; - } - - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } - - D3DCAPS9 Caps9 = {}; - - HRESULT hr = (*d3d9Device)->GetDeviceCaps(&Caps9); - - if (SUCCEEDED(hr)) - { - ConvertDeviceDesc(*lpD3DDevDesc, Caps9); - } - - return hr; - } - - return GetProxyInterfaceV7()->GetCaps(lpD3DDevDesc); -} - -HRESULT m_IDirect3DDeviceX::GetStats(LPD3DSTATS lpD3DStats, DWORD DirectXVersion) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - switch (ProxyDirectXVersion) - { - case 1: - return GetProxyInterfaceV1()->GetStats(lpD3DStats); - case 2: - return GetProxyInterfaceV2()->GetStats(lpD3DStats); - case 3: - return GetProxyInterfaceV3()->GetStats(lpD3DStats); - default: - - if (DirectXVersion == 3) - { - // The method returns E_NOTIMPL / DDERR_UNSUPPORTED. - return DDERR_UNSUPPORTED; - } - - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } -} - -HRESULT m_IDirect3DDeviceX::AddViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (Config.Dd7to9 || ProxyDirectXVersion == 7) - { - // This method will fail, returning DDERR_INVALIDPARAMS, if you attempt to add a viewport that has already been assigned to the device. - if (!lpDirect3DViewport || IsViewportAttached(lpDirect3DViewport)) - { - return DDERR_INVALIDPARAMS; - } - - AttachedViewports.push_back(lpDirect3DViewport); - - lpDirect3DViewport->AddRef(); - - return D3D_OK; - } - - if (lpDirect3DViewport) - { - lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); - } - - switch (ProxyDirectXVersion) - { - case 1: - return GetProxyInterfaceV1()->AddViewport(lpDirect3DViewport); - case 2: - return GetProxyInterfaceV2()->AddViewport(lpDirect3DViewport); - case 3: - return GetProxyInterfaceV3()->AddViewport(lpDirect3DViewport); - default: - return DDERR_GENERIC; - } -} - -void m_IDirect3DDeviceX::ClearViewport(m_IDirect3DViewportX* lpViewportX) -{ - if (lpViewportX == lpCurrentViewportX) - { - lpCurrentViewport = nullptr; - lpCurrentViewportX = nullptr; - } -} - -HRESULT m_IDirect3DDeviceX::DeleteViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (ProxyDirectXVersion > 3) - { - if (!lpDirect3DViewport) - { - return DDERR_INVALIDPARAMS; - } - - bool ret = DeleteAttachedViewport(lpDirect3DViewport); - - if (!ret) - { - return DDERR_INVALIDPARAMS; - } - - // ToDo: if deleting the current material then invalidate the material + // Save state + rsTextureMapBlend = dwRenderState; + return D3D_OK; + case D3DTBLEND_DECALALPHA: + // Reset states + SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - if (lpDirect3DViewport == lpCurrentViewport) - { - lpCurrentViewport = nullptr; - lpCurrentViewportX = nullptr; - } + // Decal-alpha texture-blending mode is supported. In this mode, the RGB and alpha values of the texture are + // blended with the colors that would have been used with no texturing. + SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); + SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); + SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - lpDirect3DViewport->Release(); + // Save state + rsTextureMapBlend = dwRenderState; + return D3D_OK; + case D3DTBLEND_DECALMASK: + // This blending mode is not supported. When the least-significant bit of the texture's alpha component is zero, + // the effect is as if texturing were disabled. + LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DTBLEND_DECALMASK' state: " << dwRenderState); - return D3D_OK; - } + // Save state + //rsTextureMapBlend = dwRenderState; + return D3D_OK; + case D3DTBLEND_MODULATE: + // Reset states + SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - if (lpDirect3DViewport) - { - lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); - } + // Modulate texture-blending mode is supported. In this mode, the RGB values of the texture are multiplied + // with the RGB values that would have been used with no texturing. Any alpha values in the texture replace + // the alpha values in the colors that would have been used with no texturing; if the texture does not contain + // an alpha component, alpha values at the vertices in the source are interpolated between vertices. + SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); + SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - switch (ProxyDirectXVersion) - { - case 1: - return GetProxyInterfaceV1()->DeleteViewport(lpDirect3DViewport); - case 2: - return GetProxyInterfaceV2()->DeleteViewport(lpDirect3DViewport); - case 3: - return GetProxyInterfaceV3()->DeleteViewport(lpDirect3DViewport); - default: - return DDERR_GENERIC; - } -} + // Save state + rsTextureMapBlend = dwRenderState; + return D3D_OK; + case D3DTBLEND_MODULATEALPHA: + // Reset states + SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); -HRESULT m_IDirect3DDeviceX::NextViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport, LPDIRECT3DVIEWPORT3* lplpDirect3DViewport, DWORD dwFlags, DWORD DirectXVersion) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Modulate-alpha texture-blending mode is supported. In this mode, the RGB values of the texture are multiplied + // with the RGB values that would have been used with no texturing, and the alpha values of the texture are multiplied + // with the alpha values that would have been used with no texturing. + SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); + SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - if (ProxyDirectXVersion > 3) - { - if (!lplpDirect3DViewport || (dwFlags == D3DNEXT_NEXT && !lpDirect3DViewport)) - { - return DDERR_INVALIDPARAMS; - } + // Save state + rsTextureMapBlend = dwRenderState; + return D3D_OK; + case D3DTBLEND_MODULATEMASK: + // This blending mode is not supported. When the least-significant bit of the texture's alpha component is zero, + // the effect is as if texturing were disabled. + LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DTBLEND_MODULATEMASK' state: " << dwRenderState); - *lplpDirect3DViewport = nullptr; + // Save state + //rsTextureMapBlend = dwRenderState; + return D3D_OK; + case D3DTBLEND_ADD: + // Reset states + SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - if (AttachedViewports.size() == 0) - { - return D3DERR_NOVIEWPORTS; - } + // Add the Gouraud interpolants to the texture lookup with saturation semantics + // (that is, if the color value overflows it is set to the maximum possible value). + SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); + SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD); + SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - switch (dwFlags) - { - case D3DNEXT_HEAD: - // Retrieve the item at the beginning of the list. - *lplpDirect3DViewport = AttachedViewports.front(); + // Save state + rsTextureMapBlend = dwRenderState; + return D3D_OK; + default: + LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DRENDERSTATE_TEXTUREMAPBLEND' state: " << dwRenderState); + return D3D_OK; + } + case D3DRENDERSTATE_ALPHAREF: // 24 + dwRenderState &= 0xFF; break; - case D3DNEXT_TAIL: - // Retrieve the item at the end of the list. - *lplpDirect3DViewport = AttachedViewports.back(); + case D3DRENDERSTATE_ALPHABLENDENABLE: // 27 + rsAlphaBlendEnabled = dwRenderState; break; - case D3DNEXT_NEXT: - // Retrieve the next item in the list. - // If you attempt to retrieve the next viewport in the list when you are at the end of the list, this method returns D3D_OK but lplpAnotherViewport is NULL. - for (UINT x = 1; x < AttachedViewports.size(); x++) + case D3DRENDERSTATE_ZVISIBLE: // 30 + if (dwRenderState != FALSE) { - if (AttachedViewports[x - 1] == lpDirect3DViewport) - { - *lplpDirect3DViewport = AttachedViewports[x]; - break; - } + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_ZVISIBLE' not implemented: " << dwRenderState); } + return D3D_OK; + case D3DRENDERSTATE_SUBPIXEL: // 31 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_SUBPIXEL' not implemented: " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_SUBPIXELX: // 32 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_SUBPIXELX' not implemented: " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_STIPPLEDALPHA: // 33 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEDALPHA' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_STIPPLEENABLE: // 39 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEENABLE' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_EDGEANTIALIAS: // 40 + rsAntiAliasChanged = true; + rsEdgeAntiAlias = dwRenderStateType; + return D3D_OK; + case D3DRENDERSTATE_COLORKEYENABLE: // 41 + rsColorKeyEnabled = dwRenderState; + return D3D_OK; + case D3DRENDERSTATE_OLDALPHABLENDENABLE:// 42 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_OLDALPHABLENDENABLE' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_BORDERCOLOR: // 43 + if (dwRenderState != 0x00000000) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_BORDERCOLOR' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_TEXTUREADDRESSU: // 44 + return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, dwRenderState); + case D3DRENDERSTATE_TEXTUREADDRESSV: // 45 + return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, dwRenderState); + case D3DRENDERSTATE_MIPMAPLODBIAS: // 46 + return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MIPMAPLODBIAS, dwRenderState); + case D3DRENDERSTATE_ZBIAS: // 47 + { + FLOAT Biased = static_cast(dwRenderState) * -0.000005f; + dwRenderState = *reinterpret_cast(&Biased); + dwRenderStateType = D3DRS_DEPTHBIAS; break; - default: - return DDERR_INVALIDPARAMS; - break; + } + case D3DRENDERSTATE_FLUSHBATCH: // 50 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_FLUSHBATCH' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT: // 51 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_STIPPLEPATTERN00: // 64 + case D3DRENDERSTATE_STIPPLEPATTERN01: // 65 + case D3DRENDERSTATE_STIPPLEPATTERN02: // 66 + case D3DRENDERSTATE_STIPPLEPATTERN03: // 67 + case D3DRENDERSTATE_STIPPLEPATTERN04: // 68 + case D3DRENDERSTATE_STIPPLEPATTERN05: // 69 + case D3DRENDERSTATE_STIPPLEPATTERN06: // 70 + case D3DRENDERSTATE_STIPPLEPATTERN07: // 71 + case D3DRENDERSTATE_STIPPLEPATTERN08: // 72 + case D3DRENDERSTATE_STIPPLEPATTERN09: // 73 + case D3DRENDERSTATE_STIPPLEPATTERN10: // 74 + case D3DRENDERSTATE_STIPPLEPATTERN11: // 75 + case D3DRENDERSTATE_STIPPLEPATTERN12: // 76 + case D3DRENDERSTATE_STIPPLEPATTERN13: // 77 + case D3DRENDERSTATE_STIPPLEPATTERN14: // 78 + case D3DRENDERSTATE_STIPPLEPATTERN15: // 79 + case D3DRENDERSTATE_STIPPLEPATTERN16: // 80 + case D3DRENDERSTATE_STIPPLEPATTERN17: // 81 + case D3DRENDERSTATE_STIPPLEPATTERN18: // 82 + case D3DRENDERSTATE_STIPPLEPATTERN19: // 83 + case D3DRENDERSTATE_STIPPLEPATTERN20: // 84 + case D3DRENDERSTATE_STIPPLEPATTERN21: // 85 + case D3DRENDERSTATE_STIPPLEPATTERN22: // 86 + case D3DRENDERSTATE_STIPPLEPATTERN23: // 87 + case D3DRENDERSTATE_STIPPLEPATTERN24: // 88 + case D3DRENDERSTATE_STIPPLEPATTERN25: // 89 + case D3DRENDERSTATE_STIPPLEPATTERN26: // 90 + case D3DRENDERSTATE_STIPPLEPATTERN27: // 91 + case D3DRENDERSTATE_STIPPLEPATTERN28: // 92 + case D3DRENDERSTATE_STIPPLEPATTERN29: // 93 + case D3DRENDERSTATE_STIPPLEPATTERN30: // 94 + case D3DRENDERSTATE_STIPPLEPATTERN31: // 95 + if (dwRenderState != 0) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEPATTERN00' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_LIGHTING: // 137 + if (Config.DdrawDisableLighting) + { + dwRenderState = FALSE; + } + break; + case D3DRENDERSTATE_EXTENTS: // 138 + // ToDo: use this to enable/disable clip plane extents set by SetClipStatus() + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_EXTENTS' not implemented! " << dwRenderState); + } + return D3D_OK; + case D3DRENDERSTATE_COLORKEYBLENDENABLE:// 144 + if (dwRenderState != FALSE) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_COLORKEYBLENDENABLE' not implemented! " << dwRenderState); + } + return D3D_OK; } - return D3D_OK; - } + if (!CheckRenderStateType(dwRenderStateType)) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: Render state type not implemented: " << dwRenderStateType << " " << dwRenderState); + return D3D_OK; // Just return OK for now! + } - if (lpDirect3DViewport) - { - lpDirect3DViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDirect3DViewport); + return SetD9RenderState(dwRenderStateType, dwRenderState); } - HRESULT hr = DDERR_GENERIC; - switch (ProxyDirectXVersion) { case 1: - hr = GetProxyInterfaceV1()->NextViewport(lpDirect3DViewport, (LPDIRECT3DVIEWPORT*)lplpDirect3DViewport, dwFlags); - break; + default: + return DDERR_GENERIC; case 2: - hr = GetProxyInterfaceV2()->NextViewport(lpDirect3DViewport, (LPDIRECT3DVIEWPORT2*)lplpDirect3DViewport, dwFlags); - break; + return GetProxyInterfaceV2()->SetRenderState(dwRenderStateType, dwRenderState); case 3: - hr = GetProxyInterfaceV3()->NextViewport(lpDirect3DViewport, lplpDirect3DViewport, dwFlags); - break; - } - - if (SUCCEEDED(hr) && lplpDirect3DViewport) - { - *lplpDirect3DViewport = ProxyAddressLookupTable.FindAddress(*lplpDirect3DViewport, DirectXVersion); + return GetProxyInterfaceV3()->SetRenderState(dwRenderStateType, dwRenderState); + case 7: + return GetProxyInterfaceV7()->SetRenderState(dwRenderStateType, dwRenderState); } - - return hr; } -HRESULT m_IDirect3DDeviceX::SetCurrentViewport(LPDIRECT3DVIEWPORT3 lpd3dViewport) +HRESULT m_IDirect3DDeviceX::GetLightState(D3DLIGHTSTATETYPE dwLightStateType, LPDWORD lpdwLightState) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (Config.Dd7to9 || ProxyDirectXVersion == 7) + if (Config.Dd7to9) { - // Before calling this method, applications must have already called the AddViewport method to add the viewport to the device. - if (!lpd3dViewport || !IsViewportAttached(lpd3dViewport)) + if (!lpdwLightState) { + LOG_LIMIT(100, __FUNCTION__ << " Warning: Light state called with nullptr: " << dwLightStateType); return DDERR_INVALIDPARAMS; } - m_IDirect3DViewportX* lpViewportX = nullptr; - if (FAILED(lpd3dViewport->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpViewportX))) + DWORD RenderState = 0; + switch (dwLightStateType) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get ViewportX interface!"); - return DDERR_GENERIC; + case D3DLIGHTSTATE_MATERIAL: + *lpdwLightState = lsMaterialHandle; + return D3D_OK; + case D3DLIGHTSTATE_AMBIENT: + RenderState = D3DRENDERSTATE_AMBIENT; + break; + case D3DLIGHTSTATE_COLORMODEL: + *lpdwLightState = D3DCOLOR_RGB; + return D3D_OK; + case D3DLIGHTSTATE_FOGMODE: + RenderState = D3DRENDERSTATE_FOGVERTEXMODE; + break; + case D3DLIGHTSTATE_FOGSTART: + RenderState = D3DRENDERSTATE_FOGSTART; + break; + case D3DLIGHTSTATE_FOGEND: + RenderState = D3DRENDERSTATE_FOGEND; + break; + case D3DLIGHTSTATE_FOGDENSITY: + RenderState = D3DRENDERSTATE_FOGDENSITY; + break; + case D3DLIGHTSTATE_COLORVERTEX: + RenderState = D3DRENDERSTATE_COLORVERTEX; + break; + default: + break; } - D3DVIEWPORT Viewport = {}; - Viewport.dwSize = sizeof(D3DVIEWPORT); - - HRESULT hr = lpd3dViewport->GetViewport(&Viewport); - - if (SUCCEEDED(hr)) + if (!RenderState) { - D3DVIEWPORT7 Viewport7; - - ConvertViewport(Viewport7, Viewport); - - hr = SetViewport(&Viewport7); - - if (SUCCEEDED(hr)) - { - lpCurrentViewport = lpd3dViewport; - - lpCurrentViewport->AddRef(); - - lpCurrentViewportX = lpViewportX; - - lpCurrentViewportX->SetCurrentViewportActive(true, true, true); - } + LOG_LIMIT(100, __FUNCTION__ << " Error: unknown LightStateType: " << dwLightStateType); + return DDERR_INVALIDPARAMS; } - return hr; - } - - if (lpd3dViewport) - { - lpd3dViewport->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpd3dViewport); + return GetRenderState((D3DRENDERSTATETYPE)RenderState, lpdwLightState); } switch (ProxyDirectXVersion) @@ -2472,98 +2329,125 @@ HRESULT m_IDirect3DDeviceX::SetCurrentViewport(LPDIRECT3DVIEWPORT3 lpd3dViewport default: return DDERR_GENERIC; case 2: - return GetProxyInterfaceV2()->SetCurrentViewport(lpd3dViewport); + return GetProxyInterfaceV2()->GetLightState(dwLightStateType, lpdwLightState); case 3: - return GetProxyInterfaceV3()->SetCurrentViewport(lpd3dViewport); + return GetProxyInterfaceV3()->GetLightState(dwLightStateType, lpdwLightState); } } -HRESULT m_IDirect3DDeviceX::GetCurrentViewport(LPDIRECT3DVIEWPORT3* lplpd3dViewport, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::SetLightState(D3DLIGHTSTATETYPE dwLightStateType, DWORD dwLightState) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (Config.Dd7to9 || ProxyDirectXVersion == 7) + if (Config.Dd7to9) { - if (!lplpd3dViewport) + DWORD RenderState = 0; + switch (dwLightStateType) { - return DDERR_INVALIDPARAMS; - } - - if (!lpCurrentViewport) + case D3DLIGHTSTATE_MATERIAL: { - return D3DERR_NOCURRENTVIEWPORT; - } - - *lplpd3dViewport = lpCurrentViewport; + lsMaterialHandle = dwLightState; - lpCurrentViewport->AddRef(); + D3DMATERIAL Material = {}; + Material.dwSize = sizeof(D3DMATERIAL); - return D3D_OK; - } + if (dwLightState) + { + m_IDirect3DMaterialX* pMaterialX = GetMaterial(dwLightState); + if (pMaterialX) + { + // Check if material associated with this device + { + m_IDirect3DDeviceX* pMaterial3DDevice = pMaterialX->GetD3DDevice(); + if (pMaterial3DDevice != this) + { + LOG_LIMIT(100, __FUNCTION__ << " (" << this << ") Warning: Material's Direct3D device doesn't match current one: " << pMaterial3DDevice); + } + } - HRESULT hr = DDERR_GENERIC; + if (FAILED(pMaterialX->GetMaterial(&Material))) + { + return DDERR_INVALIDPARAMS; + } + } + else + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get material handle!"); + return D3D_OK; + } + } - switch (ProxyDirectXVersion) - { - case 2: - hr = GetProxyInterfaceV2()->GetCurrentViewport((LPDIRECT3DVIEWPORT2*)lplpd3dViewport); - break; - case 3: - hr = GetProxyInterfaceV3()->GetCurrentViewport(lplpd3dViewport); - break; - } + D3DMATERIAL7 Material7; - if (SUCCEEDED(hr) && lplpd3dViewport) - { - *lplpd3dViewport = ProxyAddressLookupTable.FindAddress(*lplpd3dViewport, DirectXVersion); - } + ConvertMaterial(Material7, Material); - return hr; -} + SetMaterial(&Material7); -HRESULT m_IDirect3DDeviceX::SetViewport(LPD3DVIEWPORT7 lpViewport) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + if (Material.hTexture) + { + SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, Material.hTexture); + } - if (Config.Dd7to9) - { - if (!lpViewport) - { - return DDERR_INVALIDPARAMS; + return D3D_OK; + } + case D3DLIGHTSTATE_AMBIENT: + RenderState = D3DRENDERSTATE_AMBIENT; + break; + case D3DLIGHTSTATE_COLORMODEL: + if (dwLightState != D3DCOLOR_RGB) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DLIGHTSTATE_COLORMODEL' not implemented! " << dwLightState); + } + return D3D_OK; + case D3DLIGHTSTATE_FOGMODE: + RenderState = D3DRENDERSTATE_FOGVERTEXMODE; + break; + case D3DLIGHTSTATE_FOGSTART: + RenderState = D3DRENDERSTATE_FOGSTART; + break; + case D3DLIGHTSTATE_FOGEND: + RenderState = D3DRENDERSTATE_FOGEND; + break; + case D3DLIGHTSTATE_FOGDENSITY: + RenderState = D3DRENDERSTATE_FOGDENSITY; + break; + case D3DLIGHTSTATE_COLORVERTEX: + RenderState = D3DRENDERSTATE_COLORVERTEX; + break; + default: + break; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + if (!RenderState) { - return DDERR_INVALIDOBJECT; + LOG_LIMIT(100, __FUNCTION__ << " Error: unknown LightStateType: " << dwLightStateType); + return DDERR_INVALIDPARAMS; } - return SetD9Viewport((D3DVIEWPORT9*)lpViewport); + return SetRenderState((D3DRENDERSTATETYPE)RenderState, dwLightState); } - D3DVIEWPORT7 Viewport7; - if (Config.DdrawUseNativeResolution && lpViewport) + switch (ProxyDirectXVersion) { - ConvertViewport(Viewport7, *lpViewport); - Viewport7.dwX = (LONG)(Viewport7.dwX * ScaleDDWidthRatio) + ScaleDDPadX; - Viewport7.dwY = (LONG)(Viewport7.dwY * ScaleDDHeightRatio) + ScaleDDPadY; - Viewport7.dwWidth = (LONG)(Viewport7.dwWidth * ScaleDDWidthRatio); - Viewport7.dwHeight = (LONG)(Viewport7.dwHeight * ScaleDDHeightRatio); - lpViewport = &Viewport7; + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->SetLightState(dwLightStateType, dwLightState); + case 3: + return GetProxyInterfaceV3()->SetLightState(dwLightStateType, dwLightState); } - - return GetProxyInterfaceV7()->SetViewport(lpViewport); } -HRESULT m_IDirect3DDeviceX::GetViewport(LPD3DVIEWPORT7 lpViewport) +HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpViewport) + if (!lpD3DMatrix) { - return DDERR_INVALIDPARAMS; + return DDERR_INVALIDPARAMS; } // Check for device interface @@ -2572,153 +2456,138 @@ HRESULT m_IDirect3DDeviceX::GetViewport(LPD3DVIEWPORT7 lpViewport) return DDERR_INVALIDOBJECT; } - return (*d3d9Device)->GetViewport((D3DVIEWPORT9*)lpViewport); - } + switch ((DWORD)dtstTransformStateType) + { + case D3DTRANSFORMSTATE_WORLD: + dtstTransformStateType = D3DTS_WORLD; + break; + case D3DTRANSFORMSTATE_WORLD1: + dtstTransformStateType = D3DTS_WORLD1; + break; + case D3DTRANSFORMSTATE_WORLD2: + dtstTransformStateType = D3DTS_WORLD2; + break; + case D3DTRANSFORMSTATE_WORLD3: + dtstTransformStateType = D3DTS_WORLD3; + break; + } - return GetProxyInterfaceV7()->GetViewport(lpViewport); -} + D3DMATRIX view; + if (Config.DdrawConvertHomogeneousW) + { + if (dtstTransformStateType == D3DTS_VIEW) + { + D3DVIEWPORT9 Viewport9; + if (SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9))) + { + const float width = (float)Viewport9.Width; + const float height = (float)Viewport9.Height; -HRESULT m_IDirect3DDeviceX::Begin(D3DPRIMITIVETYPE d3dpt, DWORD d3dvt, DWORD dwFlags) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Replace the matrix with one that handles D3DFVF_XYZRHW geometry + ZeroMemory(&view, sizeof(D3DMATRIX)); + view._11 = 2.0f / width; + view._22 = -2.0f / height; + view._33 = 1.0f; + view._41 = -1.0f; // translate X + view._42 = 1.0f; // translate Y + view._44 = 1.0f; - if (ProxyDirectXVersion > 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + // Set flag + ConvertHomogeneous.IsTransformViewSet = true; - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->Begin(d3dpt, (D3DVERTEXTYPE)d3dvt, dwFlags); - case 3: - return GetProxyInterfaceV3()->Begin(d3dpt, d3dvt, dwFlags); - } -} + if (Config.DdrawConvertHomogeneousToWorld) + { + DirectX::XMVECTOR position, direction; + float depthOffset = 0.0f; + if (Config.DdrawConvertHomogeneousToWorldUseGameCamera) + { + // To reconstruct the 3D world, we need to know where the camera is and where it is looking + position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); -HRESULT m_IDirect3DDeviceX::BeginIndexed(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dvtVertexType, LPVOID lpvVertices, DWORD dwNumVertices, DWORD dwFlags) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + const float x = lpD3DMatrix->_11; + const float y = lpD3DMatrix->_12; + const float z = lpD3DMatrix->_13; - if (ProxyDirectXVersion > 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + float pitch = std::atan2(y, z); + if (pitch < 0.0f && y * z > 0.0f) // check if y and z have the same sign + { + // handle flipping of the pitch. This is not because the camera is looking up. + pitch += DirectX::XM_PI; + } - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->BeginIndexed(dptPrimitiveType, (D3DVERTEXTYPE)dvtVertexType, lpvVertices, dwNumVertices, dwFlags); - case 3: - return GetProxyInterfaceV3()->BeginIndexed(dptPrimitiveType, dvtVertexType, lpvVertices, dwNumVertices, dwFlags); - } -} + float yaw = std::asin(x); + if (yaw < 0.0f) + { + yaw += DirectX::XM_2PI; + } -HRESULT m_IDirect3DDeviceX::Vertex(LPVOID lpVertexType) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // mirror the transform + float pitchneg = -pitch; - if (ProxyDirectXVersion > 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + float pitch_cos = std::cos(pitchneg); + float x2 = 0.0f; //std::cos(yaw) * pitch_cos; + float y2 = std::sin(pitchneg); + float z2 = /*std::sin(yaw) **/ pitch_cos; - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->Vertex(lpVertexType); - case 3: - return GetProxyInterfaceV3()->Vertex(lpVertexType); - } -} + direction = DirectX::XMVectorSet(x2, y2, z2, 0.0f); -HRESULT m_IDirect3DDeviceX::Index(WORD wVertexIndex) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + depthOffset = Config.DdrawConvertHomogeneousToWorldDepthOffset; - if (ProxyDirectXVersion > 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + ConvertHomogeneous.ToWorld_GameCameraYaw = yaw; + ConvertHomogeneous.ToWorld_GameCameraPitch = pitch; + } + else + { + position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); + direction = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); + } - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->Index(wVertexIndex); - case 3: - return GetProxyInterfaceV3()->Index(wVertexIndex); - } -} + // Store the original matrix so it can be restored + ConvertHomogeneous.ToWorld_ViewMatrixOriginal = view; -HRESULT m_IDirect3DDeviceX::End(DWORD dwFlags) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // The Black & White matrix is an ortho camera, so create a perspective one matching the game + const float fov = Config.DdrawConvertHomogeneousToWorldFOV; + const float nearplane = Config.DdrawConvertHomogeneousToWorldNearPlane; + const float farplane = Config.DdrawConvertHomogeneousToWorldFarPlane; + const float ratio = width / height; + DirectX::XMMATRIX proj = DirectX::XMMatrixPerspectiveFovLH(fov * (3.14159265359f / 180.0f), ratio, nearplane, farplane); - if (ProxyDirectXVersion > 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ProjectionMatrix, proj); - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->End(dwFlags); - case 3: - return GetProxyInterfaceV3()->End(dwFlags); - } -} + DirectX::XMVECTOR upVector = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, upVector); -HRESULT m_IDirect3DDeviceX::BeginScene() -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Store the 3D view matrix so it can be set later + DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ViewMatrix, viewMatrix); - if (Config.Dd7to9) - { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } + // Store the view inverse matrix of the game, so we can transform the geometry with it + DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)&view); + DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj); + DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp); - // Set 3D Enabled - ddrawParent->Enable3D(); + DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, depthOffset); - HRESULT hr = (*d3d9Device)->BeginScene(); + ConvertHomogeneous.ToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv)); + } - if (Config.DdrawDisableLighting) - { - (*d3d9Device)->SetRenderState(D3DRS_LIGHTING, FALSE); + // Override original matrix pointer + lpD3DMatrix = &view; + } + } + else + { + return D3D_OK; + } } - if (SUCCEEDED(hr)) - { - IsInScene = true; + HRESULT hr = SetD9Transform(dtstTransformStateType, lpD3DMatrix); -#ifdef ENABLE_PROFILING - Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr; - sceneTime = std::chrono::high_resolution_clock::now(); -#endif +#ifdef ENABLE_DEBUGOVERLAY + if (SUCCEEDED(hr) && !Config.DdrawConvertHomogeneousW) + { + DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix); } +#endif return hr; } @@ -2726,71 +2595,67 @@ HRESULT m_IDirect3DDeviceX::BeginScene() switch (ProxyDirectXVersion) { case 1: - return GetProxyInterfaceV1()->BeginScene(); - + default: + return DDERR_GENERIC; case 2: - return GetProxyInterfaceV2()->BeginScene(); - + return GetProxyInterfaceV2()->SetTransform(dtstTransformStateType, lpD3DMatrix); case 3: - return GetProxyInterfaceV3()->BeginScene(); - + return GetProxyInterfaceV3()->SetTransform(dtstTransformStateType, lpD3DMatrix); case 7: - default: - return GetProxyInterfaceV7()->BeginScene(); + return GetProxyInterfaceV7()->SetTransform(dtstTransformStateType, lpD3DMatrix); } } - -HRESULT m_IDirect3DDeviceX::EndScene() +HRESULT m_IDirect3DDeviceX::GetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { + if (!lpD3DMatrix) + { + return DDERR_INVALIDPARAMS; + } + // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, true))) { return DDERR_INVALIDOBJECT; } - // The IDirect3DDevice7::EndScene method ends a scene that was begun by calling the IDirect3DDevice7::BeginScene method. - // When this method succeeds, the scene has been rendered, and the device surface holds the rendered scene. - - HRESULT hr = (*d3d9Device)->EndScene(); - - if (SUCCEEDED(hr)) + switch ((DWORD)dtstTransformStateType) { - IsInScene = false; - -#ifdef ENABLE_PROFILING - Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(sceneTime); -#endif - - m_IDirectDrawSurfaceX* PrimarySurface = ddrawParent->GetPrimarySurface(); - if (!PrimarySurface || FAILED(PrimarySurface->GetFlipStatus(DDGFS_CANFLIP, true)) || PrimarySurface == ddrawParent->GetRenderTargetSurface() || !PrimarySurface->IsRenderTarget()) - { - ddrawParent->PresentScene(nullptr); - } + case D3DTRANSFORMSTATE_WORLD: + dtstTransformStateType = D3DTS_WORLD; + break; + case D3DTRANSFORMSTATE_WORLD1: + dtstTransformStateType = D3DTS_WORLD1; + break; + case D3DTRANSFORMSTATE_WORLD2: + dtstTransformStateType = D3DTS_WORLD2; + break; + case D3DTRANSFORMSTATE_WORLD3: + dtstTransformStateType = D3DTS_WORLD3; + break; } - return hr; + return (*d3d9Device)->GetTransform(dtstTransformStateType, lpD3DMatrix); } switch (ProxyDirectXVersion) { case 1: - return GetProxyInterfaceV1()->EndScene(); + default: + return DDERR_GENERIC; case 2: - return GetProxyInterfaceV2()->EndScene(); + return GetProxyInterfaceV2()->GetTransform(dtstTransformStateType, lpD3DMatrix); case 3: - return GetProxyInterfaceV3()->EndScene(); + return GetProxyInterfaceV3()->GetTransform(dtstTransformStateType, lpD3DMatrix); case 7: - return GetProxyInterfaceV7()->EndScene(); - default: - return DDERR_GENERIC; + return GetProxyInterfaceV7()->GetTransform(dtstTransformStateType, lpD3DMatrix); } } -HRESULT m_IDirect3DDeviceX::Clear(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlags, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil) +HRESULT m_IDirect3DDeviceX::MultiplyTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -2802,229 +2667,304 @@ HRESULT m_IDirect3DDeviceX::Clear(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlag return DDERR_INVALIDOBJECT; } - if ((dwFlags & D3DCLEAR_TARGET) && lpCurrentRenderTargetX) + switch ((DWORD)dtstTransformStateType) { - lpCurrentRenderTargetX->PrepareRenderTarget(); + case D3DTRANSFORMSTATE_WORLD: + dtstTransformStateType = D3DTS_WORLD; + break; + case D3DTRANSFORMSTATE_WORLD1: + dtstTransformStateType = D3DTS_WORLD1; + break; + case D3DTRANSFORMSTATE_WORLD2: + dtstTransformStateType = D3DTS_WORLD2; + break; + case D3DTRANSFORMSTATE_WORLD3: + dtstTransformStateType = D3DTS_WORLD3; + break; } - ddrawParent->ReSetRenderTarget(); - - return (*d3d9Device)->Clear(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); + return (*d3d9Device)->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); } - return GetProxyInterfaceV7()->Clear(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); + switch (ProxyDirectXVersion) + { + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); + case 3: + return GetProxyInterfaceV3()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); + case 7: + return GetProxyInterfaceV7()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); + } } -HRESULT m_IDirect3DDeviceX::GetDirect3D(LPDIRECT3D7* lplpD3D, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::DrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpVertices, DWORD dwVertexCount, DWORD dwFlags, DWORD DirectXVersion) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << + " VertexType = " << Logging::hex(dptPrimitiveType) << + " VertexDesc = " << Logging::hex(dwVertexTypeDesc) << + " Vertices = " << lpVertices << + " VertexCount = " << dwVertexCount << + " Flags = " << Logging::hex(dwFlags) << + " Version = " << DirectXVersion; if (Config.Dd7to9) { - if (!lplpD3D) + if (!lpVertices) { return DDERR_INVALIDPARAMS; } - *lplpD3D = nullptr; + + if (DirectXVersion == 2) + { + if (dwVertexTypeDesc != D3DVT_VERTEX && dwVertexTypeDesc != D3DVT_LVERTEX && dwVertexTypeDesc != D3DVT_TLVERTEX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid Vertex type: " << dwVertexTypeDesc); + return D3DERR_INVALIDVERTEXTYPE; + } + dwVertexTypeDesc = ConvertVertexTypeToFVF((D3DVERTEXTYPE)dwVertexTypeDesc); + } // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, false))) + if (FAILED(CheckInterface(__FUNCTION__, true))) { return DDERR_INVALIDOBJECT; } - m_IDirect3DX** lplpD3DX = ddrawParent->GetCurrentD3D(); +#ifdef ENABLE_PROFILING + auto startTime = std::chrono::high_resolution_clock::now(); +#endif - if (!(*lplpD3DX)) + ScopedDDCriticalSection ThreadLockDD; + + dwFlags = (dwFlags & D3DDP_FORCE_DWORD); + + // Update vertices for Direct3D9 (needs to be first) + UpdateVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); + + // Set fixed function vertex type + if (FAILED((*d3d9Device)->SetFVF(dwVertexTypeDesc))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: missing Direct3D wrapper!"); - return DDERR_GENERIC; + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); + return DDERR_INVALIDPARAMS; } - *lplpD3D = (LPDIRECT3D7)(*lplpD3DX)->GetWrapperInterfaceX(DirectXVersion); + // Handle dwFlags + SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - if (!(*lplpD3D)) + // Draw primitive UP + HRESULT hr = (*d3d9Device)->DrawPrimitiveUP(dptPrimitiveType, GetNumberOfPrimitives(dptPrimitiveType, dwVertexCount), lpVertices, GetVertexStride(dwVertexTypeDesc)); + + // Handle dwFlags + RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + + if (FAILED(hr)) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get Direct3D interface!"); - return DDERR_GENERIC; + LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawPrimitiveUP' call failed: " << (D3DERR)hr); } - (*lplpD3D)->AddRef(); +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); +#endif - return D3D_OK; + return hr; } - HRESULT hr = DDERR_GENERIC; + if (Config.DdrawUseNativeResolution) + { + ScaleVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); + } switch (ProxyDirectXVersion) { case 1: - hr = GetProxyInterfaceV1()->GetDirect3D((LPDIRECT3D*)lplpD3D); - break; + default: + return DDERR_GENERIC; case 2: - hr = GetProxyInterfaceV2()->GetDirect3D((LPDIRECT3D2*)lplpD3D); - break; + return GetProxyInterfaceV2()->DrawPrimitive(dptPrimitiveType, (D3DVERTEXTYPE)dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags); case 3: - hr = GetProxyInterfaceV3()->GetDirect3D((LPDIRECT3D3*)lplpD3D); - break; + return GetProxyInterfaceV3()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags); case 7: - hr = GetProxyInterfaceV7()->GetDirect3D(lplpD3D); - break; - } - - if (SUCCEEDED(hr) && lplpD3D) - { - *lplpD3D = ProxyAddressLookupTable.FindAddress(*lplpD3D, DirectXVersion); + return GetProxyInterfaceV7()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags); } - - return hr; } -HRESULT m_IDirect3DDeviceX::GetLightState(D3DLIGHTSTATETYPE dwLightStateType, LPDWORD lpdwLightState) +HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpVertices, DWORD dwVertexCount, LPWORD lpIndices, DWORD dwIndexCount, DWORD dwFlags, DWORD DirectXVersion) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << + " VertexType = " << Logging::hex(dptPrimitiveType) << + " VertexDesc = " << Logging::hex(dwVertexTypeDesc) << + " Vertices = " << lpVertices << + " VertexCount = " << dwVertexCount << + " Indices = " << lpIndices << + " IndexCount = " << dwIndexCount << + " Flags = " << Logging::hex(dwFlags) << + " Version = " << DirectXVersion; - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { - if (!lpdwLightState) + if (!lpVertices || !lpIndices) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Light state called with nullptr: " << dwLightStateType); return DDERR_INVALIDPARAMS; } - DWORD RenderState = 0; - switch (dwLightStateType) + if (DirectXVersion == 2) { - case D3DLIGHTSTATE_MATERIAL: - *lpdwLightState = lsMaterialHandle; - return D3D_OK; - case D3DLIGHTSTATE_AMBIENT: - RenderState = D3DRENDERSTATE_AMBIENT; - break; - case D3DLIGHTSTATE_COLORMODEL: - *lpdwLightState = D3DCOLOR_RGB; - return D3D_OK; - case D3DLIGHTSTATE_FOGMODE: - RenderState = D3DRENDERSTATE_FOGVERTEXMODE; - break; - case D3DLIGHTSTATE_FOGSTART: - RenderState = D3DRENDERSTATE_FOGSTART; - break; - case D3DLIGHTSTATE_FOGEND: - RenderState = D3DRENDERSTATE_FOGEND; - break; - case D3DLIGHTSTATE_FOGDENSITY: - RenderState = D3DRENDERSTATE_FOGDENSITY; - break; - case D3DLIGHTSTATE_COLORVERTEX: - RenderState = D3DRENDERSTATE_COLORVERTEX; - break; - default: - break; + if (dwVertexTypeDesc != D3DVT_VERTEX && dwVertexTypeDesc != D3DVT_LVERTEX && dwVertexTypeDesc != D3DVT_TLVERTEX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid Vertex type: " << dwVertexTypeDesc); + return D3DERR_INVALIDVERTEXTYPE; + } + dwVertexTypeDesc = ConvertVertexTypeToFVF((D3DVERTEXTYPE)dwVertexTypeDesc); } - if (!RenderState) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: unknown LightStateType: " << dwLightStateType); - return DDERR_INVALIDPARAMS; + return DDERR_INVALIDOBJECT; } - return GetRenderState((D3DRENDERSTATETYPE)RenderState, lpdwLightState); - } +#ifdef ENABLE_PROFILING + auto startTime = std::chrono::high_resolution_clock::now(); +#endif - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->GetLightState(dwLightStateType, lpdwLightState); - case 3: - return GetProxyInterfaceV3()->GetLightState(dwLightStateType, lpdwLightState); - } -} + ScopedDDCriticalSection ThreadLockDD; -HRESULT m_IDirect3DDeviceX::SetLightState(D3DLIGHTSTATETYPE dwLightStateType, DWORD dwLightState) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + dwFlags = (dwFlags & D3DDP_FORCE_DWORD); - if (ProxyDirectXVersion > 3) - { - DWORD RenderState = 0; - switch (dwLightStateType) - { - case D3DLIGHTSTATE_MATERIAL: + // Update vertices for Direct3D9 (needs to be first) + UpdateVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); + + // Handle PositionT + if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) { - lsMaterialHandle = dwLightState; + if (!ConvertHomogeneous.IsTransformViewSet) + { + D3DMATRIX Matrix = {}; + GetTransform(D3DTS_VIEW, &Matrix); + SetTransform(D3DTS_VIEW, &Matrix); + } - D3DMATERIAL Material = {}; - Material.dwSize = sizeof(D3DMATERIAL); + if (!Config.DdrawConvertHomogeneousToWorld) + { + /*UINT8 *vertex = (UINT8*)lpVertices; + for (UINT x = 0; x < dwVertexCount; x++) + { + float *pos = (float*) vertex; + pos[3] = 1.0f; + vertex += stride; + }*/ - if (dwLightState) + // Update the FVF + dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; + } + else { - m_IDirect3DMaterialX* pMaterialX = GetMaterial(dwLightState); - if (pMaterialX) + const UINT stride = GetVertexStride(dwVertexTypeDesc); + + const UINT targetStride = stride - sizeof(float); + const UINT restSize = stride - sizeof(float) * 4; + + ConvertHomogeneous.ToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); + + UINT8* sourceVertex = (UINT8*)lpVertices; + UINT8* targetVertex = (UINT8*)ConvertHomogeneous.ToWorld_IntermediateGeometry.data(); + + lpVertices = targetVertex; + + for (UINT x = 0; x < dwVertexCount; x++) { - if (FAILED(pMaterialX->GetMaterial(&Material))) - { - return DDERR_INVALIDPARAMS; - } + // Transform the vertices into world space + float* srcpos = (float*)sourceVertex; + float* trgtpos = (float*)targetVertex; + + DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]); + + DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, ConvertHomogeneous.ToWorld_ViewMatrixInverse); + + xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global)); + + trgtpos[0] = DirectX::XMVectorGetX(xpos_global); + trgtpos[1] = DirectX::XMVectorGetY(xpos_global); + trgtpos[2] = DirectX::XMVectorGetZ(xpos_global); + + // Copy the rest + std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize); + + // Move to next vertex + sourceVertex += stride; + targetVertex += targetStride; } - else + + // Set transform + (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix); + + // Update the FVF + const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; + + // Set fixed function vertex type + if (FAILED((*d3d9Device)->SetFVF(newVertexTypeDesc))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get material handle!"); - return D3D_OK; + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); + return D3DERR_INVALIDVERTEXTYPE; } - } - D3DMATERIAL7 Material7; + // Handle dwFlags + SetDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); - ConvertMaterial(Material7, Material); + // Draw indexed primitive UP + HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); - SetMaterial(&Material7); + // Handle dwFlags + RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); - if (Material.hTexture) - { - SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, Material.hTexture); - } + // Restore transform + D3DMATRIX identityMatrix = {}; + identityMatrix._11 = 1.0f; + identityMatrix._22 = 1.0f; + identityMatrix._33 = 1.0f; - return D3D_OK; - } - case D3DLIGHTSTATE_AMBIENT: - RenderState = D3DRENDERSTATE_AMBIENT; - break; - case D3DLIGHTSTATE_COLORMODEL: - if (dwLightState != D3DCOLOR_RGB) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DLIGHTSTATE_COLORMODEL' not implemented! " << dwLightState); + (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal); + (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); + + return hr; } - return D3D_OK; - case D3DLIGHTSTATE_FOGMODE: - RenderState = D3DRENDERSTATE_FOGVERTEXMODE; - break; - case D3DLIGHTSTATE_FOGSTART: - RenderState = D3DRENDERSTATE_FOGSTART; - break; - case D3DLIGHTSTATE_FOGEND: - RenderState = D3DRENDERSTATE_FOGEND; - break; - case D3DLIGHTSTATE_FOGDENSITY: - RenderState = D3DRENDERSTATE_FOGDENSITY; - break; - case D3DLIGHTSTATE_COLORVERTEX: - RenderState = D3DRENDERSTATE_COLORVERTEX; - break; - default: - break; } - if (!RenderState) + // Set fixed function vertex type + if (FAILED((*d3d9Device)->SetFVF(dwVertexTypeDesc))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: unknown LightStateType: " << dwLightStateType); + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); return DDERR_INVALIDPARAMS; } - return SetRenderState((D3DRENDERSTATETYPE)RenderState, dwLightState); + // Handle dwFlags + SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + + // Draw indexed primitive UP + HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, GetVertexStride(dwVertexTypeDesc)); + + // Handle dwFlags + RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawIndexedPrimitiveUP' call failed: " << (D3DERR)hr); + } + +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); +#endif + + return hr; + } + + if (Config.DdrawUseNativeResolution) + { + ScaleVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); } switch (ProxyDirectXVersion) @@ -3033,250 +2973,277 @@ HRESULT m_IDirect3DDeviceX::SetLightState(D3DLIGHTSTATETYPE dwLightStateType, DW default: return DDERR_GENERIC; case 2: - return GetProxyInterfaceV2()->SetLightState(dwLightStateType, dwLightState); + return GetProxyInterfaceV2()->DrawIndexedPrimitive(dptPrimitiveType, (D3DVERTEXTYPE)dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, dwFlags); case 3: - return GetProxyInterfaceV3()->SetLightState(dwLightStateType, dwLightState); + return GetProxyInterfaceV3()->DrawIndexedPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, dwFlags); + case 7: + return GetProxyInterfaceV7()->DrawIndexedPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, dwFlags); } } -void m_IDirect3DDeviceX::ClearLight(m_IDirect3DLight* lpLight) +HRESULT m_IDirect3DDeviceX::SetClipStatus(LPD3DCLIPSTATUS lpD3DClipStatus) { - // Find handle associated with Light - auto it = LightIndexMap.begin(); - while (it != LightIndexMap.end()) + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { - if (it->second == lpLight) + // D3DCLIPSTATUS_EXTENTS2 flag cannot be combined with D3DCLIPSTATUS_EXTENTS3. + if (!lpD3DClipStatus || (lpD3DClipStatus->dwFlags & (D3DCLIPSTATUS_EXTENTS2 | D3DCLIPSTATUS_EXTENTS3)) == (D3DCLIPSTATUS_EXTENTS2 | D3DCLIPSTATUS_EXTENTS3)) { - // Disable light before removing - LightEnable(it->first, FALSE); + return DDERR_INVALIDPARAMS; + } - // Remove entry from map - it = LightIndexMap.erase(it); + // D3DCLIPSTATUS_EXTENTS3 is Not currently implemented in DirectDraw. + if (lpD3DClipStatus->dwFlags & D3DCLIPSTATUS_EXTENTS3) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: only clip status flag is supported. Using unsupported dwFlags combination: " << Logging::hex(lpD3DClipStatus->dwFlags)); + return DDERR_INVALIDPARAMS; } - else + else if (lpD3DClipStatus->dwFlags & D3DCLIPSTATUS_EXTENTS2) { - ++it; + LOG_LIMIT(100, __FUNCTION__ << " Warning: Extents 2D flag Not Implemented: " << *lpD3DClipStatus); + D3DClipStatus = *lpD3DClipStatus; } - } -} - -HRESULT m_IDirect3DDeviceX::SetLight(m_IDirect3DLight* lpLightInterface, LPD3DLIGHT lpLight) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (!lpLightInterface || !lpLight || (lpLight->dwSize != sizeof(D3DLIGHT) && lpLight->dwSize != sizeof(D3DLIGHT2))) - { - return DDERR_INVALIDPARAMS; - } - - D3DLIGHT7 Light7; - // ToDo: the dvAttenuation members are interpreted differently in D3DLIGHT2 than they were for D3DLIGHT. + // For now just save clip status + if (lpD3DClipStatus->dwFlags & D3DCLIPSTATUS_STATUS) + { + D3DClipStatus = *lpD3DClipStatus; + D3DClipStatus.dwFlags = D3DCLIPSTATUS_STATUS; + D3DClipStatus.dwStatus = 0; + return D3D_OK; + } - ConvertLight(Light7, *lpLight); + // ToDo: set clip status from dwStatus - DWORD dwLightIndex = 0; + // ToDo: check the D3DRENDERSTATE_EXTENTS flag and use that to enable or disable extents clip planes + // The default setting for this state, FALSE, disables extent updates. Applications that intend to use the + // IDirect3DDevice7::GetClipStatus and IDirect3DDevice7::SetClipStatus methods to manipulate the viewport extents + // can enable extents updates by setting D3DRENDERSTATE_EXTENTS to TRUE. - // Check if Light exists in the map - for (auto& entry : LightIndexMap) - { - if (entry.second == lpLightInterface) + // Check for device interface + /*if (FAILED(CheckInterface(__FUNCTION__, true))) { - dwLightIndex = entry.first; - break; + return DDERR_INVALIDOBJECT; } - } - // Create index and add light to the map - if (dwLightIndex == 0) - { - BYTE Start = (BYTE)((DWORD)lpLightInterface & 0xff); - for (BYTE x = Start; x != Start - 1; x++) - { - bool Flag = true; - for (auto& entry : LightIndexMap) - { - if (entry.first == x) - { - Flag = false; - break; - } - } - if (x != 0 && Flag) - { - dwLightIndex = x; - break; - } - } - } + // Calculate the center of the bounding box + float centerX = (lpD3DClipStatus->minx + lpD3DClipStatus->maxx) * 0.5f; + float centerY = (lpD3DClipStatus->miny + lpD3DClipStatus->maxy) * 0.5f; + float centerZ = (lpD3DClipStatus->minz + lpD3DClipStatus->maxz) * 0.5f; - if (dwLightIndex == 0) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to find an available Light Index"); - return DDERR_INVALIDPARAMS; - } + // Calculate the extents (half-width, half-height, and half-depth) of the bounding box + float halfWidth = (lpD3DClipStatus->maxx - lpD3DClipStatus->minx) * 0.5f; + float halfHeight = (lpD3DClipStatus->maxy - lpD3DClipStatus->miny) * 0.5f; + float halfDepth = (lpD3DClipStatus->maxz - lpD3DClipStatus->minz) * 0.5f; - // Add light to index map - LightIndexMap[dwLightIndex] = lpLightInterface; + // Calculate the front clipping plane coefficients + float frontNormalX = -1.0f; // Clipping towards the negative X direction + float frontNormalY = 0.0f; + float frontNormalZ = 0.0f; + float frontDistance = centerX - halfWidth; - HRESULT hr = SetLight(dwLightIndex, &Light7); + float frontClipPlane[4] = { frontNormalX, frontNormalY, frontNormalZ, frontDistance }; - if (SUCCEEDED(hr)) - { - if (((LPD3DLIGHT2)lpLight)->dwSize == sizeof(D3DLIGHT2) && (((LPD3DLIGHT2)lpLight)->dwFlags & D3DLIGHT_ACTIVE) == NULL) - { - LightEnable(dwLightIndex, FALSE); - } - else - { - LightEnable(dwLightIndex, TRUE); - } - } + // Calculate the back clipping plane coefficients + float backNormalX = 1.0f; // Clipping towards the positive X direction + float backNormalY = 0.0f; + float backNormalZ = 0.0f; + float backDistance = -(centerX + halfWidth); - return hr; -} + float backClipPlane[4] = { backNormalX, backNormalY, backNormalZ, backDistance }; -HRESULT m_IDirect3DDeviceX::SetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Calculate the top clipping plane coefficients + float topNormalX = 0.0f; + float topNormalY = 1.0f; // Clipping towards the positive Y direction + float topNormalZ = 0.0f; + float topDistance = -(centerY + halfHeight); - if (Config.Dd7to9) - { - if (!lpLight) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: called with nullptr: " << lpLight); - return DDERR_INVALIDPARAMS; - } + float topClipPlane[4] = { topNormalX, topNormalY, topNormalZ, topDistance }; - if (lpLight->dltType == D3DLIGHT_PARALLELPOINT || lpLight->dltType == D3DLIGHT_GLSPOT) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Light Type: " << lpLight->dltType << " Not Implemented"); - return D3D_OK; - } + // Calculate the bottom clipping plane coefficients + float bottomNormalX = 0.0f; + float bottomNormalY = -1.0f; // Clipping towards the negative Y direction + float bottomNormalZ = 0.0f; + float bottomDistance = centerY - halfHeight; - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } + float bottomClipPlane[4] = { bottomNormalX, bottomNormalY, bottomNormalZ, bottomDistance }; - D3DLIGHT9 Light = *(D3DLIGHT9*)lpLight; + // Calculate the near clipping plane coefficients + float nearNormalX = 0.0f; + float nearNormalY = 0.0f; + float nearNormalZ = -1.0f; // Clipping towards the negative Z direction + float nearDistance = centerZ - halfDepth; - // Make spot light work more like it did in Direct3D7 - if (Light.Type == D3DLIGHTTYPE::D3DLIGHT_SPOT) - { - // Theta must be in the range from 0 through the value specified by Phi - if (Light.Theta <= Light.Phi) - { - Light.Theta /= 1.75f; - } - } + float nearClipPlane[4] = { nearNormalX, nearNormalY, nearNormalZ, nearDistance }; - HRESULT hr = SetD9Light(dwLightIndex, &Light); + // Calculate the far clipping plane coefficients + float farNormalX = 0.0f; + float farNormalY = 0.0f; + float farNormalZ = 1.0f; // Clipping towards the positive Z direction + float farDistance = -(centerZ + halfDepth); - if (SUCCEEDED(hr)) + float farClipPlane[4] = { farNormalX, farNormalY, farNormalZ, farDistance }; + + // Set the clip planes + int x = 0; + for (auto clipPlane : { frontClipPlane, backClipPlane, topClipPlane, bottomClipPlane, nearClipPlane, farClipPlane }) { -#ifdef ENABLE_DEBUGOVERLAY - if (Config.EnableImgui) + HRESULT hr = (*d3d9Device)->SetClipPlane(x, clipPlane); + if (FAILED(hr)) { - DOverlay.SetLight(dwLightIndex, lpLight); + LOG_LIMIT(100, __FUNCTION__ << " Error: 'SetClipPlane' call failed: " << (D3DERR)hr << + " call: { " << clipPlane[0] << ", " << clipPlane[1] << ", " << clipPlane[2] << ", " << clipPlane[3] << "}"); + return hr; } -#endif + x++; } - return hr; + // To enable a clipping plane, set the corresponding bit in the DWORD value applied to the D3DRS_CLIPPLANEENABLE render state. + SetD9RenderState(D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0 | D3DCLIPPLANE1 | D3DCLIPPLANE2 | D3DCLIPPLANE3 | D3DCLIPPLANE4 | D3DCLIPPLANE5);*/ + + return D3D_OK; } - return GetProxyInterfaceV7()->SetLight(dwLightIndex, lpLight); + switch (ProxyDirectXVersion) + { + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->SetClipStatus(lpD3DClipStatus); + case 3: + return GetProxyInterfaceV3()->SetClipStatus(lpD3DClipStatus); + case 7: + return GetProxyInterfaceV7()->SetClipStatus(lpD3DClipStatus); + } } -HRESULT m_IDirect3DDeviceX::GetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight) +HRESULT m_IDirect3DDeviceX::GetClipStatus(LPD3DCLIPSTATUS lpD3DClipStatus) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpLight) + if (!lpD3DClipStatus) { return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; - } + *lpD3DClipStatus = D3DClipStatus; - return (*d3d9Device)->GetLight(dwLightIndex, (D3DLIGHT9*)lpLight); + return D3D_OK; } - return GetProxyInterfaceV7()->GetLight(dwLightIndex, lpLight); + switch (ProxyDirectXVersion) + { + case 1: + default: + return DDERR_GENERIC; + case 2: + return GetProxyInterfaceV2()->GetClipStatus(lpD3DClipStatus); + case 3: + return GetProxyInterfaceV3()->GetClipStatus(lpD3DClipStatus); + case 7: + return GetProxyInterfaceV7()->GetClipStatus(lpD3DClipStatus); + } } -HRESULT m_IDirect3DDeviceX::LightEnable(DWORD dwLightIndex, BOOL bEnable) +// ****************************** +// IDirect3DDevice v3 functions +// ****************************** + +HRESULT m_IDirect3DDeviceX::DrawPrimitiveStrided(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwVertexCount, DWORD dwFlags, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; + } + + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, dwFlags); + case 7: + if (DirectXVersion != 7) { - return DDERR_INVALIDOBJECT; - } + // Handle dwFlags + SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - HRESULT hr = LightD9Enable(dwLightIndex, bEnable); + DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); + HRESULT hr = GetProxyInterfaceV7()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, Flags); - if (SUCCEEDED(hr)) + // Handle dwFlags + RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + + return hr; + } + else { -#ifdef ENABLE_DEBUGOVERLAY - if (Config.EnableImgui) - { - DOverlay.LightEnable(dwLightIndex, bEnable); - } -#endif + return GetProxyInterfaceV7()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, dwFlags); } - - return hr; } - - return GetProxyInterfaceV7()->LightEnable(dwLightIndex, bEnable); } -HRESULT m_IDirect3DDeviceX::GetLightEnable(m_IDirect3DLight* lpLightInterface, BOOL* pbEnable) +HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitiveStrided(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwVertexCount, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags, DWORD DirectXVersion) { - if (!lpLightInterface || !pbEnable) + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { - return DDERR_INVALIDPARAMS; + LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); + return DDERR_UNSUPPORTED; } - DWORD dwLightIndex = 0; - - // Check if Light exists in the map - for (auto& entry : LightIndexMap) + switch (ProxyDirectXVersion) { - if (entry.second == lpLightInterface) + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->DrawIndexedPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, dwFlags); + case 7: + if (DirectXVersion != 7) { - dwLightIndex = entry.first; - break; - } - } + // Handle dwFlags + SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - if (dwLightIndex == 0) - { - return DDERR_INVALIDPARAMS; - } + DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); + HRESULT hr = GetProxyInterfaceV7()->DrawIndexedPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, Flags); - return GetLightEnable(dwLightIndex, pbEnable); + // Handle dwFlags + RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + + return hr; + } + else + { + return GetProxyInterfaceV7()->DrawIndexedPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, dwFlags); + } + } } -HRESULT m_IDirect3DDeviceX::GetLightEnable(DWORD dwLightIndex, BOOL* pbEnable) +HRESULT m_IDirect3DDeviceX::DrawPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType, LPDIRECT3DVERTEXBUFFER7 lpd3dVertexBuffer, DWORD dwStartVertex, DWORD dwNumVertices, DWORD dwFlags, DWORD DirectXVersion) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << + " VertexType = " << Logging::hex(dptPrimitiveType) << + " VertexBuffer = " << lpd3dVertexBuffer << + " StartVertex = " << dwStartVertex << + " NumVertices = " << dwNumVertices << + " Flags = " << Logging::hex(dwFlags) << + " Version = " << DirectXVersion; if (Config.Dd7to9) { - if (!pbEnable) + if (!lpd3dVertexBuffer) { return DDERR_INVALIDPARAMS; } @@ -3287,131 +3254,95 @@ HRESULT m_IDirect3DDeviceX::GetLightEnable(DWORD dwLightIndex, BOOL* pbEnable) return DDERR_INVALIDOBJECT; } - return (*d3d9Device)->GetLightEnable(dwLightIndex, pbEnable); - } +#ifdef ENABLE_PROFILING + auto startTime = std::chrono::high_resolution_clock::now(); +#endif - return GetProxyInterfaceV7()->GetLightEnable(dwLightIndex, pbEnable); -} + ScopedDDCriticalSection ThreadLockDD; -HRESULT m_IDirect3DDeviceX::MultiplyTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + dwFlags = (dwFlags & D3DDP_FORCE_DWORD); - if (Config.Dd7to9) - { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + m_IDirect3DVertexBufferX* pVertexBufferX = nullptr; + lpd3dVertexBuffer->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pVertexBufferX); + if (!pVertexBufferX) { - return DDERR_INVALIDOBJECT; + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get vertex buffer wrapper!"); + return DDERR_GENERIC; } - switch ((DWORD)dtstTransformStateType) + LPDIRECT3DVERTEXBUFFER9 d3d9VertexBuffer = pVertexBufferX->GetCurrentD9VertexBuffer(); + if (!d3d9VertexBuffer) { - case D3DTRANSFORMSTATE_WORLD: - dtstTransformStateType = D3DTS_WORLD; - break; - case D3DTRANSFORMSTATE_WORLD1: - dtstTransformStateType = D3DTS_WORLD1; - break; - case D3DTRANSFORMSTATE_WORLD2: - dtstTransformStateType = D3DTS_WORLD2; - break; - case D3DTRANSFORMSTATE_WORLD3: - dtstTransformStateType = D3DTS_WORLD3; - break; + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get d3d9 vertex buffer!"); + return DDERR_GENERIC; } - return (*d3d9Device)->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); - } - - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); - case 3: - return GetProxyInterfaceV3()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); - case 7: - return GetProxyInterfaceV7()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix); - } -} - -void m_IDirect3DDeviceX::ClearMaterialHandle(D3DMATERIALHANDLE mHandle) -{ - if (mHandle) - { - TextureHandleMap.erase(mHandle); + DWORD FVF = pVertexBufferX->GetFVF9(); - // If material handle is set then clear it - if (lsMaterialHandle == mHandle) + // Set fixed function vertex type + if (FAILED((*d3d9Device)->SetFVF(FVF))) { - SetLightState(D3DLIGHTSTATE_MATERIAL, 0); + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(FVF)); + return DDERR_INVALIDPARAMS; } - } -} - -HRESULT m_IDirect3DDeviceX::SetMaterialHandle(D3DMATERIALHANDLE& mHandle, m_IDirect3DMaterialX* lpMaterial) -{ - if (!mHandle || !lpMaterial) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: NULL pointer found! " << lpMaterial << " -> " << mHandle); - return DDERR_GENERIC; - } - - // Ensure that the handle is unique - while (GetMaterial(mHandle)) - { - mHandle += 4; - } - MaterialHandleMap[mHandle] = lpMaterial; - - return D3D_OK; -} + // Set stream source + (*d3d9Device)->SetStreamSource(0, d3d9VertexBuffer, 0, GetVertexStride(FVF)); -HRESULT m_IDirect3DDeviceX::SetMaterial(LPD3DMATERIAL lpMaterial) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Handle dwFlags + SetDrawStates(FVF, dwFlags, DirectXVersion); - if (!lpMaterial) - { - return DDERR_INVALIDPARAMS; - } + // Draw primitive + HRESULT hr = (*d3d9Device)->DrawPrimitive(dptPrimitiveType, dwStartVertex, GetNumberOfPrimitives(dptPrimitiveType, dwNumVertices)); - D3DMATERIAL7 Material7; + // Handle dwFlags + RestoreDrawStates(FVF, dwFlags, DirectXVersion); - ConvertMaterial(Material7, *lpMaterial); + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawPrimitive' call failed: " << (D3DERR)hr); + } - HRESULT hr = SetMaterial(&Material7); +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); +#endif - if (FAILED(hr)) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to set material: " << (D3DERR)hr); return hr; } - if (lpMaterial->dwRampSize) + if (lpd3dVertexBuffer) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: RampSize Not Implemented: " << lpMaterial->dwRampSize); + lpd3dVertexBuffer->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpd3dVertexBuffer); } - if (lpMaterial->hTexture) + switch (ProxyDirectXVersion) { - SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, lpMaterial->hTexture); + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->DrawPrimitiveVB(dptPrimitiveType, (LPDIRECT3DVERTEXBUFFER)lpd3dVertexBuffer, dwStartVertex, dwNumVertices, dwFlags); + case 7: + return GetProxyInterfaceV7()->DrawPrimitiveVB(dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, dwFlags); } - - return D3D_OK; } -HRESULT m_IDirect3DDeviceX::SetMaterial(LPD3DMATERIAL7 lpMaterial) +HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType, LPDIRECT3DVERTEXBUFFER7 lpd3dVertexBuffer, DWORD dwStartVertex, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags, DWORD DirectXVersion) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << + " VertexType = " << Logging::hex(dptPrimitiveType) << + " VertexBuffer = " << lpd3dVertexBuffer << + " StartVertex = " << dwStartVertex << + " NumVertices = " << dwNumVertices << + " Indices = " << lpwIndices << + " IndexCount = " << dwIndexCount << + " Flags = " << Logging::hex(dwFlags) << + " Version = " << DirectXVersion; if (Config.Dd7to9) { - if (!lpMaterial) + if (!lpd3dVertexBuffer || !lpwIndices) { return DDERR_INVALIDPARAMS; } @@ -3422,456 +3353,492 @@ HRESULT m_IDirect3DDeviceX::SetMaterial(LPD3DMATERIAL7 lpMaterial) return DDERR_INVALIDOBJECT; } - return SetD9Material((D3DMATERIAL9*)lpMaterial); - } +#ifdef ENABLE_PROFILING + auto startTime = std::chrono::high_resolution_clock::now(); +#endif - return GetProxyInterfaceV7()->SetMaterial(lpMaterial); -} + ScopedDDCriticalSection ThreadLockDD; -HRESULT m_IDirect3DDeviceX::GetMaterial(LPD3DMATERIAL7 lpMaterial) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + dwFlags = (dwFlags & D3DDP_FORCE_DWORD); - if (Config.Dd7to9) - { - if (!lpMaterial) + m_IDirect3DVertexBufferX* pVertexBufferX = nullptr; + lpd3dVertexBuffer->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pVertexBufferX); + if (!pVertexBufferX) { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get vertex buffer wrapper!"); return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + LPDIRECT3DVERTEXBUFFER9 d3d9VertexBuffer = pVertexBufferX->GetCurrentD9VertexBuffer(); + if (!d3d9VertexBuffer) { - return DDERR_INVALIDOBJECT; + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get d3d9 vertex buffer!"); + return DDERR_GENERIC; } - return (*d3d9Device)->GetMaterial((D3DMATERIAL9*)lpMaterial); - } - - return GetProxyInterfaceV7()->GetMaterial(lpMaterial); -} + DWORD FVF = pVertexBufferX->GetFVF9(); -HRESULT m_IDirect3DDeviceX::SetRenderState(D3DRENDERSTATETYPE dwRenderStateType, DWORD dwRenderState) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << dwRenderStateType << " " << dwRenderState; + // Set fixed function vertex type + if (FAILED((*d3d9Device)->SetFVF(FVF))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(FVF)); + return DDERR_INVALIDPARAMS; + } + + // No operation to performed + if (dwIndexCount == 0) + { + return D3D_OK; + } + + LPDIRECT3DINDEXBUFFER9 d3d9IndexBuffer = ddrawParent->GetIndexBuffer(lpwIndices, dwIndexCount); + if (!d3d9IndexBuffer) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get d3d9 index buffer!"); + return DDERR_GENERIC; + } + + // Set stream source + (*d3d9Device)->SetStreamSource(0, d3d9VertexBuffer, 0, GetVertexStride(FVF)); + + // Set Index data + (*d3d9Device)->SetIndices(d3d9IndexBuffer); + + // Handle dwFlags + SetDrawStates(FVF, dwFlags, DirectXVersion); + + // Draw primitive + HRESULT hr = (*d3d9Device)->DrawIndexedPrimitive(dptPrimitiveType, dwStartVertex, 0, dwNumVertices, 0, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount)); + + // Handle dwFlags + RestoreDrawStates(FVF, dwFlags, DirectXVersion); + + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawIndexedPrimitive' call failed: " << (D3DERR)hr); + } + +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); +#endif + + return hr; + } + + if (lpd3dVertexBuffer) + { + lpd3dVertexBuffer->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpd3dVertexBuffer); + } + + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->DrawIndexedPrimitiveVB(dptPrimitiveType, (LPDIRECT3DVERTEXBUFFER)lpd3dVertexBuffer, lpwIndices, dwIndexCount, dwFlags); + case 7: + return GetProxyInterfaceV7()->DrawIndexedPrimitiveVB(dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags); + } +} + +HRESULT m_IDirect3DDeviceX::ComputeSphereVisibility(LPD3DVECTOR lpCenters, LPD3DVALUE lpRadii, DWORD dwNumSpheres, DWORD dwFlags, LPDWORD lpdwReturnValues) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + if (!lpCenters || !lpRadii || !dwNumSpheres || !lpdwReturnValues) { - return DDERR_INVALIDOBJECT; + return DDERR_INVALIDPARAMS; } - switch ((DWORD)dwRenderStateType) + LOG_LIMIT(100, __FUNCTION__ << " Warning: function not fully implemented"); + + // Sphere visibility is computed by back-transforming the viewing frustum to the model space, using the inverse of the combined world, view, or projection matrices. + // If the combined matrix can't be inverted (if the determinant is 0), the method will fail, returning D3DERR_INVALIDMATRIX. + for (UINT x = 0; x < dwNumSpheres; x++) { - case D3DRENDERSTATE_TEXTUREHANDLE: // 1 + // If a sphere is completely visible, the corresponding entry in lpdwReturnValues is 0. + lpdwReturnValues[x] = 0; // Just return all is visible for now + } + + return D3D_OK; + } + + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->ComputeSphereVisibility(lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues); + case 7: + return GetProxyInterfaceV7()->ComputeSphereVisibility(lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues); + } +} + +HRESULT m_IDirect3DDeviceX::GetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2* lplpTexture) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lplpTexture || dwStage >= MaxTextureStages) { - rsTextureHandle = dwRenderState; - if (dwRenderState == NULL) - { - return SetTexture(0, (LPDIRECT3DTEXTURE2)nullptr); - } - m_IDirect3DTextureX* pTextureX = GetTexture(dwRenderState); - if (pTextureX) - { - IDirect3DTexture2* lpTexture = (IDirect3DTexture2*)pTextureX->GetWrapperInterfaceX(0); - if (!lpTexture) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture address!"); - return DDERR_INVALIDPARAMS; - } + return DDERR_INVALIDPARAMS; + } + *lplpTexture = nullptr; - return SetTexture(0, lpTexture); - } - else - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture handle!"); - return SetTexture(0, (LPDIRECT3DTEXTURE2)nullptr); - } - return D3D_OK; + // Get surface stage + ComPtr pSurface; + HRESULT hr = GetTexture(dwStage, pSurface.GetAddressOf()); + + if (FAILED(hr)) + { + return hr; } - case D3DRENDERSTATE_ANTIALIAS: // 2 - rsAntiAliasChanged = true; - rsAntiAlias = dwRenderStateType; - return D3D_OK; - case D3DRENDERSTATE_TEXTUREADDRESS: // 3 - return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESS, dwRenderState); - case D3DRENDERSTATE_TEXTUREPERSPECTIVE: // 4 - if (dwRenderState != rsTexturePerspective) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_ZVISIBLE' not implemented: " << dwRenderState); - } - rsTexturePerspective = dwRenderState; - return D3D_OK; - case D3DRENDERSTATE_WRAPU: // 5 - rsTextureWrappingChanged = true; - rsTextureWrappingU = dwRenderState; - return D3D_OK; - case D3DRENDERSTATE_WRAPV: // 6 - rsTextureWrappingChanged = true; - rsTextureWrappingV = dwRenderState; - return D3D_OK; - case D3DRENDERSTATE_LINEPATTERN: // 10 - if (dwRenderState != 0) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_LINEPATTERN' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_MONOENABLE: // 11 - if (dwRenderState != FALSE) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_MONOENABLE' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_ROP2: // 12 - if (dwRenderState != R2_COPYPEN) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_ROP2' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_PLANEMASK: // 13 - if (dwRenderState != (DWORD)-1) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_PLANEMASK' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_TEXTUREMAG: // 17 - // Only the first two (D3DFILTER_NEAREST and D3DFILTER_LINEAR) are valid with D3DRENDERSTATE_TEXTUREMAG. - switch (dwRenderState) - { - case D3DFILTER_NEAREST: - case D3DFILTER_LINEAR: - return SetD9SamplerState(0, D3DSAMP_MAGFILTER, dwRenderState); - default: - LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DRENDERSTATE_TEXTUREMAG' state: " << dwRenderState); - return DDERR_INVALIDPARAMS; - } - case D3DRENDERSTATE_TEXTUREMIN: // 18 - switch (dwRenderState) - { - case D3DFILTER_NEAREST: - case D3DFILTER_LINEAR: - rsTextureMin = dwRenderState; - ssMipFilter[0] = D3DTEXF_NONE; - SetD9SamplerState(0, D3DSAMP_MINFILTER, dwRenderState); - return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - case D3DFILTER_MIPNEAREST: - rsTextureMin = dwRenderState; - ssMipFilter[0] = D3DTEXF_POINT; - SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); - case D3DFILTER_MIPLINEAR: - rsTextureMin = dwRenderState; - ssMipFilter[0] = D3DTEXF_POINT; - SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); - case D3DFILTER_LINEARMIPNEAREST: - rsTextureMin = dwRenderState; - ssMipFilter[0] = D3DTEXF_LINEAR; - SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); - case D3DFILTER_LINEARMIPLINEAR: - rsTextureMin = dwRenderState; - ssMipFilter[0] = D3DTEXF_LINEAR; - SetD9SamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - return SetD9SamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); - default: - LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DRENDERSTATE_TEXTUREMIN' state: " << dwRenderState); - return DDERR_INVALIDPARAMS; - } - case D3DRENDERSTATE_SRCBLEND: // 19 - rsSrcBlend = dwRenderState; - break; - case D3DRENDERSTATE_DESTBLEND: // 20 - rsDestBlend = dwRenderState; - break; - case D3DRENDERSTATE_TEXTUREMAPBLEND: // 21 - switch (dwRenderState) - { - case D3DTBLEND_COPY: - case D3DTBLEND_DECAL: - // Reset states - SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); - SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT); - // Decal texture-blending mode is supported. In this mode, the RGB and alpha values of the texture replace the colors that would have been used with no texturing. - SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); - SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + // Get surface wrapper + m_IDirectDrawSurfaceX* pSurfaceX = nullptr; + pSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pSurfaceX); + if (!pSurfaceX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface wrapper!"); + return DDERR_INVALIDPARAMS; + } - // Save state - rsTextureMapBlend = dwRenderState; - return D3D_OK; - case D3DTBLEND_DECALALPHA: - // Reset states - SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + // Get attached texture from surface + m_IDirect3DTextureX* pTextureX = pSurfaceX->GetAttachedTexture(); + if (!pTextureX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture!"); + return DDERR_INVALIDPARAMS; + } - // Decal-alpha texture-blending mode is supported. In this mode, the RGB and alpha values of the texture are - // blended with the colors that would have been used with no texturing. - SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); - SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); - SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); - SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + // Add ref to texture + pTextureX->AddRef(); - // Save state - rsTextureMapBlend = dwRenderState; - return D3D_OK; - case D3DTBLEND_DECALMASK: - // This blending mode is not supported. When the least-significant bit of the texture's alpha component is zero, - // the effect is as if texturing were disabled. - LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DTBLEND_DECALMASK' state: " << dwRenderState); + *lplpTexture = (LPDIRECT3DTEXTURE2)pTextureX->GetWrapperInterfaceX(0); - // Save state - //rsTextureMapBlend = dwRenderState; - return D3D_OK; - case D3DTBLEND_MODULATE: - // Reset states - SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + return D3D_OK; + } - // Modulate texture-blending mode is supported. In this mode, the RGB values of the texture are multiplied - // with the RGB values that would have been used with no texturing. Any alpha values in the texture replace - // the alpha values in the colors that would have been used with no texturing; if the texture does not contain - // an alpha component, alpha values at the vertices in the source are interpolated between vertices. - SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); - SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); - SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + HRESULT hr = GetProxyInterfaceV3()->GetTexture(dwStage, lplpTexture); - // Save state - rsTextureMapBlend = dwRenderState; - return D3D_OK; - case D3DTBLEND_MODULATEALPHA: - // Reset states - SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + if (SUCCEEDED(hr) && lplpTexture) + { + *lplpTexture = ProxyAddressLookupTable.FindAddress(*lplpTexture, 2); + } - // Modulate-alpha texture-blending mode is supported. In this mode, the RGB values of the texture are multiplied - // with the RGB values that would have been used with no texturing, and the alpha values of the texture are multiplied - // with the alpha values that would have been used with no texturing. - SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); - SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + return hr; +} - // Save state - rsTextureMapBlend = dwRenderState; - return D3D_OK; - case D3DTBLEND_MODULATEMASK: - // This blending mode is not supported. When the least-significant bit of the texture's alpha component is zero, - // the effect is as if texturing were disabled. - LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DTBLEND_MODULATEMASK' state: " << dwRenderState); +HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2 lpTexture) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Save state - //rsTextureMapBlend = dwRenderState; - return D3D_OK; - case D3DTBLEND_ADD: - // Reset states - SetD9TextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - SetD9TextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + if (Config.Dd7to9) + { + if (dwStage >= MaxTextureStages) + { + return DDERR_INVALIDPARAMS; + } - // Add the Gouraud interpolants to the texture lookup with saturation semantics - // (that is, if the color value overflows it is set to the maximum possible value). - SetD9RenderState(D3DRS_ALPHABLENDENABLE, TRUE); - SetD9RenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - SetD9RenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); - SetD9TextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD); - SetD9TextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - SetD9TextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); - SetD9TextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + if (!lpTexture) + { + return SetTexture(dwStage, (LPDIRECTDRAWSURFACE7)nullptr); + } - // Save state - rsTextureMapBlend = dwRenderState; - return D3D_OK; - default: - LOG_LIMIT(100, __FUNCTION__ << " Warning: unsupported 'D3DRENDERSTATE_TEXTUREMAPBLEND' state: " << dwRenderState); - return D3D_OK; - } - case D3DRENDERSTATE_ALPHAREF: // 24 - dwRenderState &= 0xFF; - break; - case D3DRENDERSTATE_ALPHABLENDENABLE: // 27 - rsAlphaBlendEnabled = dwRenderState; - break; - case D3DRENDERSTATE_ZVISIBLE: // 30 - if (dwRenderState != FALSE) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_ZVISIBLE' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_SUBPIXEL: // 31 - if (dwRenderState != FALSE) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_SUBPIXEL' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_SUBPIXELX: // 32 - if (dwRenderState != FALSE) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_SUBPIXELX' not implemented: " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_STIPPLEDALPHA: // 33 - if (dwRenderState != FALSE) + m_IDirect3DTextureX* pTextureX = nullptr; + lpTexture->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pTextureX); + if (!pTextureX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture wrapper!"); + return DDERR_INVALIDPARAMS; + } + + m_IDirectDrawSurfaceX* pSurfaceX = pTextureX->GetSurface(); + if (!pSurfaceX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface!"); + return DDERR_INVALIDPARAMS; + } + + return SetTexture(dwStage, (LPDIRECTDRAWSURFACE7)pSurfaceX->GetWrapperInterfaceX(0)); + } + + if (lpTexture) + { + lpTexture->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpTexture); + } + + return GetProxyInterfaceV3()->SetTexture(dwStage, lpTexture); +} + +HRESULT m_IDirect3DDeviceX::GetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, LPDWORD lpdwValue) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpdwValue) + { + return DDERR_INVALIDPARAMS; + } + + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; + } + + switch ((DWORD)dwState) + { + case D3DTSS_ADDRESS: + { + DWORD ValueU = 0, ValueV = 0; + (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSU, &ValueU); + (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSV, &ValueV); + if (ValueU == ValueV) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEDALPHA' not implemented! " << dwRenderState); + *lpdwValue = ValueU; + return D3D_OK; } - return D3D_OK; - case D3DRENDERSTATE_STIPPLEENABLE: // 39 - if (dwRenderState != FALSE) + else { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEENABLE' not implemented! " << dwRenderState); + LOG_LIMIT(100, __FUNCTION__ << " Warning: AddressU and AddressV don't match"); + *lpdwValue = 0; + return D3D_OK; } - return D3D_OK; - case D3DRENDERSTATE_EDGEANTIALIAS: // 40 - rsAntiAliasChanged = true; - rsEdgeAntiAlias = dwRenderStateType; - return D3D_OK; - case D3DRENDERSTATE_COLORKEYENABLE: // 41 - rsColorKeyEnabled = dwRenderState; - return D3D_OK; - case D3DRENDERSTATE_OLDALPHABLENDENABLE:// 42 - if (dwRenderState != FALSE) + } + case D3DTSS_ADDRESSU: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSU, lpdwValue); + case D3DTSS_ADDRESSV: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSV, lpdwValue); + case D3DTSS_ADDRESSW: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_ADDRESSW, lpdwValue); + case D3DTSS_BORDERCOLOR: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_BORDERCOLOR, lpdwValue); + case D3DTSS_MAGFILTER: + { + HRESULT hr = (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MAGFILTER, lpdwValue); + if (SUCCEEDED(hr) && *lpdwValue == D3DTEXF_ANISOTROPIC) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_OLDALPHABLENDENABLE' not implemented! " << dwRenderState); + *lpdwValue = D3DTFG_ANISOTROPIC; } - return D3D_OK; - case D3DRENDERSTATE_BORDERCOLOR: // 43 - if (dwRenderState != 0x00000000) + return hr; + } + case D3DTSS_MINFILTER: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MINFILTER, lpdwValue); + case D3DTSS_MIPFILTER: + { + HRESULT hr = (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MIPFILTER, lpdwValue); + if (SUCCEEDED(hr)) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_BORDERCOLOR' not implemented! " << dwRenderState); + switch (*lpdwValue) + { + default: + case D3DTEXF_NONE: + *lpdwValue = D3DTFP_NONE; + break; + case D3DTEXF_POINT: + *lpdwValue = D3DTFP_POINT; + break; + case D3DTEXF_LINEAR: + *lpdwValue = D3DTFP_LINEAR; + break; + } } - return D3D_OK; - case D3DRENDERSTATE_TEXTUREADDRESSU: // 44 - return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, dwRenderState); - case D3DRENDERSTATE_TEXTUREADDRESSV: // 45 - return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, dwRenderState); - case D3DRENDERSTATE_MIPMAPLODBIAS: // 46 - return SetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MIPMAPLODBIAS, dwRenderState); - case D3DRENDERSTATE_ZBIAS: // 47 + return hr; + } + case D3DTSS_MIPMAPLODBIAS: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MIPMAPLODBIAS, lpdwValue); + case D3DTSS_MAXMIPLEVEL: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MAXMIPLEVEL, lpdwValue); + case D3DTSS_MAXANISOTROPY: + return (*d3d9Device)->GetSamplerState(dwStage, D3DSAMP_MAXANISOTROPY, lpdwValue); + } + + if (!CheckTextureStageStateType(dwState)) { - FLOAT Biased = static_cast(dwRenderState) * -0.000005f; - dwRenderState = *reinterpret_cast(&Biased); - dwRenderStateType = D3DRS_DEPTHBIAS; - break; + LOG_LIMIT(100, __FUNCTION__ << " Warning: Texture Stage state type not implemented: " << dwState); } - case D3DRENDERSTATE_FLUSHBATCH: // 50 - if (dwRenderState != FALSE) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_FLUSHBATCH' not implemented! " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT: // 51 - if (dwRenderState != FALSE) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT' not implemented! " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_STIPPLEPATTERN00: // 64 - case D3DRENDERSTATE_STIPPLEPATTERN01: // 65 - case D3DRENDERSTATE_STIPPLEPATTERN02: // 66 - case D3DRENDERSTATE_STIPPLEPATTERN03: // 67 - case D3DRENDERSTATE_STIPPLEPATTERN04: // 68 - case D3DRENDERSTATE_STIPPLEPATTERN05: // 69 - case D3DRENDERSTATE_STIPPLEPATTERN06: // 70 - case D3DRENDERSTATE_STIPPLEPATTERN07: // 71 - case D3DRENDERSTATE_STIPPLEPATTERN08: // 72 - case D3DRENDERSTATE_STIPPLEPATTERN09: // 73 - case D3DRENDERSTATE_STIPPLEPATTERN10: // 74 - case D3DRENDERSTATE_STIPPLEPATTERN11: // 75 - case D3DRENDERSTATE_STIPPLEPATTERN12: // 76 - case D3DRENDERSTATE_STIPPLEPATTERN13: // 77 - case D3DRENDERSTATE_STIPPLEPATTERN14: // 78 - case D3DRENDERSTATE_STIPPLEPATTERN15: // 79 - case D3DRENDERSTATE_STIPPLEPATTERN16: // 80 - case D3DRENDERSTATE_STIPPLEPATTERN17: // 81 - case D3DRENDERSTATE_STIPPLEPATTERN18: // 82 - case D3DRENDERSTATE_STIPPLEPATTERN19: // 83 - case D3DRENDERSTATE_STIPPLEPATTERN20: // 84 - case D3DRENDERSTATE_STIPPLEPATTERN21: // 85 - case D3DRENDERSTATE_STIPPLEPATTERN22: // 86 - case D3DRENDERSTATE_STIPPLEPATTERN23: // 87 - case D3DRENDERSTATE_STIPPLEPATTERN24: // 88 - case D3DRENDERSTATE_STIPPLEPATTERN25: // 89 - case D3DRENDERSTATE_STIPPLEPATTERN26: // 90 - case D3DRENDERSTATE_STIPPLEPATTERN27: // 91 - case D3DRENDERSTATE_STIPPLEPATTERN28: // 92 - case D3DRENDERSTATE_STIPPLEPATTERN29: // 93 - case D3DRENDERSTATE_STIPPLEPATTERN30: // 94 - case D3DRENDERSTATE_STIPPLEPATTERN31: // 95 - if (dwRenderState != 0) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEPATTERN00' not implemented! " << dwRenderState); - } - return D3D_OK; - case D3DRENDERSTATE_LIGHTING: // 137 - if (Config.DdrawDisableLighting) + + return (*d3d9Device)->GetTextureStageState(dwStage, dwState, lpdwValue); + } + + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->GetTextureStageState(dwStage, dwState, lpdwValue); + case 7: + return GetProxyInterfaceV7()->GetTextureStageState(dwStage, dwState, lpdwValue); + } +} + +HRESULT m_IDirect3DDeviceX::SetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (dwStage >= MaxTextureStages) + { + return DDERR_INVALIDPARAMS; + } + + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; + } + + switch ((DWORD)dwState) + { + case D3DTSS_ADDRESS: + SetD9SamplerState(dwStage, D3DSAMP_ADDRESSU, dwValue); + return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSV, dwValue); + case D3DTSS_ADDRESSU: + return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSU, dwValue); + case D3DTSS_ADDRESSV: + return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSV, dwValue); + case D3DTSS_ADDRESSW: + return SetD9SamplerState(dwStage, D3DSAMP_ADDRESSW, dwValue); + case D3DTSS_BORDERCOLOR: + return SetD9SamplerState(dwStage, D3DSAMP_BORDERCOLOR, dwValue); + case D3DTSS_MAGFILTER: + if (dwValue == D3DTFG_ANISOTROPIC) { - dwRenderState = FALSE; + dwValue = D3DTEXF_ANISOTROPIC; } - break; - case D3DRENDERSTATE_EXTENTS: // 138 - // ToDo: use this to enable/disable clip plane extents set by SetClipStatus() - if (dwRenderState != FALSE) + else if (dwValue == D3DTFG_FLATCUBIC || dwValue == D3DTFG_GAUSSIANCUBIC) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_EXTENTS' not implemented! " << dwRenderState); + dwValue = D3DTEXF_LINEAR; } - return D3D_OK; - case D3DRENDERSTATE_COLORKEYBLENDENABLE:// 144 - if (dwRenderState != FALSE) + return SetD9SamplerState(dwStage, D3DSAMP_MAGFILTER, dwValue); + case D3DTSS_MINFILTER: + return SetD9SamplerState(dwStage, D3DSAMP_MINFILTER, dwValue); + case D3DTSS_MIPFILTER: + switch (dwValue) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_COLORKEYBLENDENABLE' not implemented! " << dwRenderState); + default: + case D3DTFP_NONE: + dwValue = D3DTEXF_NONE; + break; + case D3DTFP_POINT: + dwValue = D3DTEXF_POINT; + break; + case D3DTFP_LINEAR: + dwValue = D3DTEXF_LINEAR; + break; } - return D3D_OK; + ssMipFilter[dwStage] = dwValue; + return SetD9SamplerState(dwStage, D3DSAMP_MIPFILTER, dwValue); + case D3DTSS_MIPMAPLODBIAS: + return SetD9SamplerState(dwStage, D3DSAMP_MIPMAPLODBIAS, dwValue); + case D3DTSS_MAXMIPLEVEL: + return SetD9SamplerState(dwStage, D3DSAMP_MAXMIPLEVEL, dwValue); + case D3DTSS_MAXANISOTROPY: + return SetD9SamplerState(dwStage, D3DSAMP_MAXANISOTROPY, dwValue); + } + + if (!CheckTextureStageStateType(dwState)) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: Texture Stage state type not implemented: " << dwState); + return D3D_OK; // Just return OK for now! + } + + return SetD9TextureStageState(dwStage, dwState, dwValue); + } + + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->SetTextureStageState(dwStage, dwState, dwValue); + case 7: + return GetProxyInterfaceV7()->SetTextureStageState(dwStage, dwState, dwValue); + } +} + +HRESULT m_IDirect3DDeviceX::ValidateDevice(LPDWORD lpdwPasses) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpdwPasses) + { + return DDERR_INVALIDPARAMS; } - if (!CheckRenderStateType(dwRenderStateType)) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Render state type not implemented: " << dwRenderStateType << " " << dwRenderState); - return D3D_OK; // Just return OK for now! + return DDERR_INVALIDOBJECT; } - return SetD9RenderState(dwRenderStateType, dwRenderState); + DWORD FVF, Size; + IDirect3DVertexBuffer9* vertexBuffer = ddrawParent->GetValidateDeviceVertexBuffer(FVF, Size); + + if (!vertexBuffer) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to get vertex buffer!"); + return DDERR_GENERIC; + } + + // Bind the vertex buffer to the device + (*d3d9Device)->SetStreamSource(0, vertexBuffer, 0, Size); + + // Set a simple FVF (Flexible Vertex Format) + (*d3d9Device)->SetFVF(FVF); + + // Call ValidateDevice + HRESULT hr = (*d3d9Device)->ValidateDevice(lpdwPasses); + + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: ValidateDevice() function failed: " << (DDERR)hr); + } + + return hr; } switch (ProxyDirectXVersion) { case 1: + case 2: default: return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->SetRenderState(dwRenderStateType, dwRenderState); case 3: - return GetProxyInterfaceV3()->SetRenderState(dwRenderStateType, dwRenderState); + return GetProxyInterfaceV3()->ValidateDevice(lpdwPasses); case 7: - return GetProxyInterfaceV7()->SetRenderState(dwRenderStateType, dwRenderState); + return GetProxyInterfaceV7()->ValidateDevice(lpdwPasses); } } -HRESULT m_IDirect3DDeviceX::GetRenderState(D3DRENDERSTATETYPE dwRenderStateType, LPDWORD lpdwRenderState) +// ****************************** +// IDirect3DDevice v7 functions +// ****************************** + +HRESULT m_IDirect3DDeviceX::GetCaps(LPD3DDEVICEDESC7 lpD3DDevDesc) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << dwRenderStateType; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpdwRenderState) + if (!lpD3DDevDesc) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Render state called with nullptr: " << dwRenderStateType); return DDERR_INVALIDPARAMS; } @@ -3881,157 +3848,139 @@ HRESULT m_IDirect3DDeviceX::GetRenderState(D3DRENDERSTATETYPE dwRenderStateType, return DDERR_INVALIDOBJECT; } - switch ((DWORD)dwRenderStateType) + D3DCAPS9 Caps9 = {}; + + HRESULT hr = (*d3d9Device)->GetDeviceCaps(&Caps9); + + if (SUCCEEDED(hr)) { - case D3DRENDERSTATE_TEXTUREHANDLE: // 1 - *lpdwRenderState = rsTextureHandle; - return D3D_OK; - case D3DRENDERSTATE_ANTIALIAS: // 2 - *lpdwRenderState = rsAntiAlias; - return D3D_OK; - case D3DRENDERSTATE_TEXTUREADDRESS: // 3 - return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESS, lpdwRenderState); - case D3DRENDERSTATE_TEXTUREPERSPECTIVE: // 4 - *lpdwRenderState = rsTexturePerspective; - return D3D_OK; - case D3DRENDERSTATE_WRAPU: // 5 - *lpdwRenderState = rsTextureWrappingU; - return D3D_OK; - case D3DRENDERSTATE_WRAPV: // 6 - *lpdwRenderState = rsTextureWrappingV; - return D3D_OK; - case D3DRENDERSTATE_LINEPATTERN: // 10 - *lpdwRenderState = 0; - return D3D_OK; - case D3DRENDERSTATE_MONOENABLE: // 11 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_ROP2: // 12 - *lpdwRenderState = R2_COPYPEN; - return D3D_OK; - case D3DRENDERSTATE_PLANEMASK: // 13 - *lpdwRenderState = (DWORD)-1; - return D3D_OK; - case D3DRENDERSTATE_TEXTUREMAG: // 17 - return (*d3d9Device)->GetSamplerState(0, D3DSAMP_MAGFILTER, lpdwRenderState); - case D3DRENDERSTATE_TEXTUREMIN: // 18 - *lpdwRenderState = rsTextureMin; - return D3D_OK; - case D3DRENDERSTATE_TEXTUREMAPBLEND: // 21 - *lpdwRenderState = rsTextureMapBlend; - return D3D_OK; - case D3DRENDERSTATE_ZVISIBLE: // 30 - // This render state is not supported. - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_SUBPIXEL: // 31 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_SUBPIXELX: // 32 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_STIPPLEDALPHA: // 33 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_STIPPLEENABLE: // 39 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_EDGEANTIALIAS: // 40 - *lpdwRenderState = rsEdgeAntiAlias; - return D3D_OK; - case D3DRENDERSTATE_COLORKEYENABLE: // 41 - *lpdwRenderState = rsColorKeyEnabled; - return D3D_OK; - case D3DRENDERSTATE_OLDALPHABLENDENABLE:// 42 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_BORDERCOLOR: // 43 - *lpdwRenderState = 0x00000000; - return D3D_OK; - case D3DRENDERSTATE_TEXTUREADDRESSU: // 44 - return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, lpdwRenderState); - case D3DRENDERSTATE_TEXTUREADDRESSV: // 45 - return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, lpdwRenderState); - case D3DRENDERSTATE_MIPMAPLODBIAS: // 46 - return GetTextureStageState(0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MIPMAPLODBIAS, lpdwRenderState); - case D3DRENDERSTATE_ZBIAS: // 47 - (*d3d9Device)->GetRenderState(D3DRS_DEPTHBIAS, lpdwRenderState); - *lpdwRenderState = static_cast(*reinterpret_cast(lpdwRenderState) * -200000.0f); - return D3D_OK; - case D3DRENDERSTATE_FLUSHBATCH: // 50 - *lpdwRenderState = 0; - return D3D_OK; - case D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT: // 51 - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_STIPPLEPATTERN00: // 64 - case D3DRENDERSTATE_STIPPLEPATTERN01: // 65 - case D3DRENDERSTATE_STIPPLEPATTERN02: // 66 - case D3DRENDERSTATE_STIPPLEPATTERN03: // 67 - case D3DRENDERSTATE_STIPPLEPATTERN04: // 68 - case D3DRENDERSTATE_STIPPLEPATTERN05: // 69 - case D3DRENDERSTATE_STIPPLEPATTERN06: // 70 - case D3DRENDERSTATE_STIPPLEPATTERN07: // 71 - case D3DRENDERSTATE_STIPPLEPATTERN08: // 72 - case D3DRENDERSTATE_STIPPLEPATTERN09: // 73 - case D3DRENDERSTATE_STIPPLEPATTERN10: // 74 - case D3DRENDERSTATE_STIPPLEPATTERN11: // 75 - case D3DRENDERSTATE_STIPPLEPATTERN12: // 76 - case D3DRENDERSTATE_STIPPLEPATTERN13: // 77 - case D3DRENDERSTATE_STIPPLEPATTERN14: // 78 - case D3DRENDERSTATE_STIPPLEPATTERN15: // 79 - case D3DRENDERSTATE_STIPPLEPATTERN16: // 80 - case D3DRENDERSTATE_STIPPLEPATTERN17: // 81 - case D3DRENDERSTATE_STIPPLEPATTERN18: // 82 - case D3DRENDERSTATE_STIPPLEPATTERN19: // 83 - case D3DRENDERSTATE_STIPPLEPATTERN20: // 84 - case D3DRENDERSTATE_STIPPLEPATTERN21: // 85 - case D3DRENDERSTATE_STIPPLEPATTERN22: // 86 - case D3DRENDERSTATE_STIPPLEPATTERN23: // 87 - case D3DRENDERSTATE_STIPPLEPATTERN24: // 88 - case D3DRENDERSTATE_STIPPLEPATTERN25: // 89 - case D3DRENDERSTATE_STIPPLEPATTERN26: // 90 - case D3DRENDERSTATE_STIPPLEPATTERN27: // 91 - case D3DRENDERSTATE_STIPPLEPATTERN28: // 92 - case D3DRENDERSTATE_STIPPLEPATTERN29: // 93 - case D3DRENDERSTATE_STIPPLEPATTERN30: // 94 - case D3DRENDERSTATE_STIPPLEPATTERN31: // 95 - *lpdwRenderState = 0; - return D3D_OK; - case D3DRENDERSTATE_EXTENTS: // 138 - // ToDo: use this to report on clip plane extents set by SetClipStatus() - *lpdwRenderState = FALSE; - return D3D_OK; - case D3DRENDERSTATE_COLORKEYBLENDENABLE:// 144 - *lpdwRenderState = FALSE; - return D3D_OK; + ConvertDeviceDesc(*lpD3DDevDesc, Caps9); + } + + return hr; + } + + return GetProxyInterfaceV7()->GetCaps(lpD3DDevDesc); +} + +HRESULT m_IDirect3DDeviceX::EnumTextureFormats(LPD3DENUMPIXELFORMATSCALLBACK lpd3dEnumPixelProc, LPVOID lpArg) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpd3dEnumPixelProc) + { + return DDERR_INVALIDPARAMS; + } + + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, false))) + { + return DDERR_INVALIDOBJECT; + } + + LPDIRECT3D9 d3d9Object = ddrawParent->GetDirectD9Object(); + + if (!d3d9Object) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get d3d9 object!"); + return DDERR_GENERIC; + } + + // Get texture list + std::vector TextureList = { + D3DFMT_R5G6B5, + D3DFMT_X1R5G5B5, + D3DFMT_A1R5G5B5, + D3DFMT_A4R4G4B4, + //D3DFMT_R8G8B8, // Requires emulation + D3DFMT_X8R8G8B8, + D3DFMT_A8R8G8B8, + D3DFMT_V8U8, + D3DFMT_X8L8V8U8, + D3DFMT_L6V5U5, + D3DFMT_DXT1, + D3DFMT_DXT2, + D3DFMT_DXT3, + D3DFMT_DXT4, + D3DFMT_DXT5, + D3DFMT_P8, + D3DFMT_L8, + D3DFMT_A8, + D3DFMT_A4L4, + D3DFMT_A8L8 }; + + // If textures are being trimmed + if (Config.DdrawLimitTextureFormats) + { + // Trim texture list + std::vector TrimTextureList = { + D3DFMT_V8U8, // May be trimmed if normal maps are unused + D3DFMT_X8L8V8U8, // Rare normal map format + D3DFMT_L6V5U5, // Uncommon format + D3DFMT_DXT5, // Newer texture format + D3DFMT_P8, // 8-bit palettized (Direct3D9 deprecated this) + D3DFMT_A4L4 }; // Rare grayscale+alpha format + + // Remove trimmed texture from list + for (auto it = TextureList.begin(); it != TextureList.end(); ) + { + if (std::find(TrimTextureList.begin(), TrimTextureList.end(), *it) != TrimTextureList.end()) + { + it = TextureList.erase(it); // Remove and update iterator + } + else + { + ++it; // Move to next element + } + } + } + // Add FourCCs to texture list + else + { + for (D3DFORMAT format : FourCCTypes) + { + TextureList.push_back(format); + } } - if (!CheckRenderStateType(dwRenderStateType)) + // Check for supported textures + DDPIXELFORMAT ddpfPixelFormat = {}; + ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + + bool IsDirectDraw8bit = (ddrawParent->GetDisplayBPP(nullptr) == 8); + + for (D3DFORMAT format : TextureList) { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Render state type not implemented: " << dwRenderStateType); - *lpdwRenderState = 0; - return D3D_OK; // Just return OK for now! + if (!IsUnsupportedFormat(format) && ((format == D3DFMT_P8 && IsDirectDraw8bit) || + SUCCEEDED(d3d9Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, format)))) + { + SetPixelDisplayFormat(format, ddpfPixelFormat); + if (lpd3dEnumPixelProc(&ddpfPixelFormat, lpArg) == DDENUMRET_CANCEL) + { + return D3D_OK; + } + } } - return (*d3d9Device)->GetRenderState(dwRenderStateType, lpdwRenderState); + return D3D_OK; } switch (ProxyDirectXVersion) { case 1: + case 2: default: return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->GetRenderState(dwRenderStateType, lpdwRenderState); case 3: - return GetProxyInterfaceV3()->GetRenderState(dwRenderStateType, lpdwRenderState); + return GetProxyInterfaceV3()->EnumTextureFormats(lpd3dEnumPixelProc, lpArg); case 7: - return GetProxyInterfaceV7()->GetRenderState(dwRenderStateType, lpdwRenderState); + return GetProxyInterfaceV7()->EnumTextureFormats(lpd3dEnumPixelProc, lpArg); } } -HRESULT m_IDirect3DDeviceX::BeginStateBlock() +HRESULT m_IDirect3DDeviceX::Clear(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlags, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -4043,40 +3992,29 @@ HRESULT m_IDirect3DDeviceX::BeginStateBlock() return DDERR_INVALIDOBJECT; } - if (IsRecordingState) + if ((dwFlags & D3DCLEAR_TARGET) && lpCurrentRenderTargetX) { - return DDERR_GENERIC; + lpCurrentRenderTargetX->PrepareRenderTarget(); } - HRESULT hr = (*d3d9Device)->BeginStateBlock(); - - if (SUCCEEDED(hr)) - { - IsRecordingState = true; - } + ddrawParent->ReSetRenderTarget(); - return hr; + return (*d3d9Device)->Clear(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); } - return GetProxyInterfaceV7()->BeginStateBlock(); + return GetProxyInterfaceV7()->Clear(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); } -HRESULT m_IDirect3DDeviceX::EndStateBlock(LPDWORD lpdwBlockHandle) +HRESULT m_IDirect3DDeviceX::SetViewport(LPD3DVIEWPORT7 lpViewport) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpdwBlockHandle) + if (!lpViewport) { return DDERR_INVALIDPARAMS; } - *lpdwBlockHandle = NULL; - - if (!IsRecordingState) - { - return DDERR_GENERIC; - } // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, true))) @@ -4084,43 +4022,30 @@ HRESULT m_IDirect3DDeviceX::EndStateBlock(LPDWORD lpdwBlockHandle) return DDERR_INVALIDOBJECT; } - HRESULT hr = (*d3d9Device)->EndStateBlock(reinterpret_cast(lpdwBlockHandle)); - - if (SUCCEEDED(hr)) - { - IsRecordingState = false; - StateBlockTokens.insert(*lpdwBlockHandle); - } + return SetD9Viewport((D3DVIEWPORT9*)lpViewport); + } - return hr; + D3DVIEWPORT7 Viewport7; + if (Config.DdrawUseNativeResolution && lpViewport) + { + ConvertViewport(Viewport7, *lpViewport); + Viewport7.dwX = (LONG)(Viewport7.dwX * ScaleDDWidthRatio) + ScaleDDPadX; + Viewport7.dwY = (LONG)(Viewport7.dwY * ScaleDDHeightRatio) + ScaleDDPadY; + Viewport7.dwWidth = (LONG)(Viewport7.dwWidth * ScaleDDWidthRatio); + Viewport7.dwHeight = (LONG)(Viewport7.dwHeight * ScaleDDHeightRatio); + lpViewport = &Viewport7; } - return GetProxyInterfaceV7()->EndStateBlock(lpdwBlockHandle); + return GetProxyInterfaceV7()->SetViewport(lpViewport); } -HRESULT m_IDirect3DDeviceX::DrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpVertices, DWORD dwVertexCount, DWORD dwFlags, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::GetViewport(LPD3DVIEWPORT7 lpViewport) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << - " VertexType = " << Logging::hex(dptPrimitiveType) << - " VertexDesc = " << Logging::hex(dwVertexTypeDesc) << - " Vertices = " << lpVertices << - " VertexCount = " << dwVertexCount << - " Flags = " << Logging::hex(dwFlags) << - " Version = " << DirectXVersion; - - if (DirectXVersion == 2 && ProxyDirectXVersion > 2) - { - if (dwVertexTypeDesc != D3DVT_VERTEX && dwVertexTypeDesc != D3DVT_LVERTEX && dwVertexTypeDesc != D3DVT_TLVERTEX) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid Vertex type: " << dwVertexTypeDesc); - return D3DERR_INVALIDVERTEXTYPE; - } - dwVertexTypeDesc = ConvertVertexTypeToFVF((D3DVERTEXTYPE)dwVertexTypeDesc); - } + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpVertices) + if (!lpViewport) { return DDERR_INVALIDPARAMS; } @@ -4131,130 +4056,119 @@ HRESULT m_IDirect3DDeviceX::DrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType, DWO return DDERR_INVALIDOBJECT; } -#ifdef ENABLE_PROFILING - auto startTime = std::chrono::high_resolution_clock::now(); -#endif + return (*d3d9Device)->GetViewport((D3DVIEWPORT9*)lpViewport); + } - dwFlags = (dwFlags & D3DDP_FORCE_DWORD); + return GetProxyInterfaceV7()->GetViewport(lpViewport); +} - // Update vertices for Direct3D9 (needs to be first) - UpdateVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); +HRESULT m_IDirect3DDeviceX::SetMaterial(LPD3DMATERIAL7 lpMaterial) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Set fixed function vertex type - if (FAILED((*d3d9Device)->SetFVF(dwVertexTypeDesc))) + if (Config.Dd7to9) + { + if (!lpMaterial) { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); return DDERR_INVALIDPARAMS; } - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - // Draw primitive UP - HRESULT hr = (*d3d9Device)->DrawPrimitiveUP(dptPrimitiveType, GetNumberOfPrimitives(dptPrimitiveType, dwVertexCount), lpVertices, GetVertexStride(dwVertexTypeDesc)); - - // Handle dwFlags - RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - if (FAILED(hr)) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawPrimitiveUP' call failed: " << (D3DERR)hr); + return DDERR_INVALIDOBJECT; } -#ifdef ENABLE_PROFILING - Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); -#endif - - return hr; + return SetD9Material((D3DMATERIAL9*)lpMaterial); } - if (Config.DdrawUseNativeResolution) - { - ScaleVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); - } + return GetProxyInterfaceV7()->SetMaterial(lpMaterial); +} - switch (ProxyDirectXVersion) +HRESULT m_IDirect3DDeviceX::GetMaterial(LPD3DMATERIAL7 lpMaterial) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->DrawPrimitive(dptPrimitiveType, (D3DVERTEXTYPE)dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags); - case 3: - return GetProxyInterfaceV3()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags); - case 7: - if (DirectXVersion != 7) + if (!lpMaterial) { - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); - HRESULT hr = GetProxyInterfaceV7()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, Flags); - - // Handle dwFlags - RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - return hr; + return DDERR_INVALIDPARAMS; } - else + + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - return GetProxyInterfaceV7()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags); + return DDERR_INVALIDOBJECT; } + + return (*d3d9Device)->GetMaterial((D3DMATERIAL9*)lpMaterial); } + + return GetProxyInterfaceV7()->GetMaterial(lpMaterial); } -HRESULT m_IDirect3DDeviceX::DrawPrimitiveStrided(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwVertexCount, DWORD dwFlags, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::SetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } + if (!lpLight) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: called with nullptr: " << lpLight); + return DDERR_INVALIDPARAMS; + } - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, dwFlags); - case 7: - if (DirectXVersion != 7) + if (lpLight->dltType == D3DLIGHT_PARALLELPOINT || lpLight->dltType == D3DLIGHT_GLSPOT) { - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + LOG_LIMIT(100, __FUNCTION__ << " Warning: Light Type: " << lpLight->dltType << " Not Implemented"); + return D3D_OK; + } - DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); - HRESULT hr = GetProxyInterfaceV7()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, Flags); + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; + } - // Handle dwFlags - RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + D3DLIGHT9 Light = *(D3DLIGHT9*)lpLight; - return hr; + // Make spot light work more like it did in Direct3D7 + if (Light.Type == D3DLIGHTTYPE::D3DLIGHT_SPOT) + { + // Theta must be in the range from 0 through the value specified by Phi + if (Light.Theta <= Light.Phi) + { + Light.Theta /= 1.75f; + } } - else + + HRESULT hr = SetD9Light(dwLightIndex, &Light); + + if (SUCCEEDED(hr)) { - return GetProxyInterfaceV7()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, dwFlags); +#ifdef ENABLE_DEBUGOVERLAY + if (Config.EnableImgui) + { + DOverlay.SetLight(dwLightIndex, lpLight); + } +#endif } + + return hr; } + + return GetProxyInterfaceV7()->SetLight(dwLightIndex, lpLight); } -HRESULT m_IDirect3DDeviceX::DrawPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType, LPDIRECT3DVERTEXBUFFER7 lpd3dVertexBuffer, DWORD dwStartVertex, DWORD dwNumVertices, DWORD dwFlags, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::GetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << - " VertexType = " << Logging::hex(dptPrimitiveType) << - " VertexBuffer = " << lpd3dVertexBuffer << - " StartVertex = " << dwStartVertex << - " NumVertices = " << dwNumVertices << - " Flags = " << Logging::hex(dwFlags) << - " Version = " << DirectXVersion; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpd3dVertexBuffer) + if (!lpLight) { return DDERR_INVALIDPARAMS; } @@ -4265,127 +4179,57 @@ HRESULT m_IDirect3DDeviceX::DrawPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType, L return DDERR_INVALIDOBJECT; } -#ifdef ENABLE_PROFILING - auto startTime = std::chrono::high_resolution_clock::now(); -#endif + return (*d3d9Device)->GetLight(dwLightIndex, (D3DLIGHT9*)lpLight); + } - dwFlags = (dwFlags & D3DDP_FORCE_DWORD); + return GetProxyInterfaceV7()->GetLight(dwLightIndex, lpLight); +} - m_IDirect3DVertexBufferX* pVertexBufferX = nullptr; - lpd3dVertexBuffer->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pVertexBufferX); - if (!pVertexBufferX) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get vertex buffer wrapper!"); - return DDERR_GENERIC; - } +HRESULT m_IDirect3DDeviceX::BeginStateBlock() +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - LPDIRECT3DVERTEXBUFFER9 d3d9VertexBuffer = pVertexBufferX->GetCurrentD9VertexBuffer(); - if (!d3d9VertexBuffer) + if (Config.Dd7to9) + { + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get d3d9 vertex buffer!"); - return DDERR_GENERIC; + return DDERR_INVALIDOBJECT; } - DWORD FVF = pVertexBufferX->GetFVF9(); - - // Set fixed function vertex type - if (FAILED((*d3d9Device)->SetFVF(FVF))) + if (IsRecordingState) { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(FVF)); - return DDERR_INVALIDPARAMS; + return DDERR_GENERIC; } - // Set stream source - (*d3d9Device)->SetStreamSource(0, d3d9VertexBuffer, 0, GetVertexStride(FVF)); - - // Handle dwFlags - SetDrawStates(FVF, dwFlags, DirectXVersion); - - // Draw primitive - HRESULT hr = (*d3d9Device)->DrawPrimitive(dptPrimitiveType, dwStartVertex, GetNumberOfPrimitives(dptPrimitiveType, dwNumVertices)); - - // Handle dwFlags - RestoreDrawStates(FVF, dwFlags, DirectXVersion); + HRESULT hr = (*d3d9Device)->BeginStateBlock(); - if (FAILED(hr)) + if (SUCCEEDED(hr)) { - LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawPrimitive' call failed: " << (D3DERR)hr); + IsRecordingState = true; } -#ifdef ENABLE_PROFILING - Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); -#endif - return hr; } - if (lpd3dVertexBuffer) - { - lpd3dVertexBuffer->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpd3dVertexBuffer); - } - - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->DrawPrimitiveVB(dptPrimitiveType, (LPDIRECT3DVERTEXBUFFER)lpd3dVertexBuffer, dwStartVertex, dwNumVertices, dwFlags); - case 7: - if (DirectXVersion != 7) - { - D3DVERTEXBUFFERDESC BufferDesc = {}; - if (lpd3dVertexBuffer) - { - lpd3dVertexBuffer->GetVertexBufferDesc(&BufferDesc); - } - - // Handle dwFlags - SetDrawStates(BufferDesc.dwFVF, dwFlags, DirectXVersion); - - DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); - HRESULT hr = GetProxyInterfaceV7()->DrawPrimitiveVB(dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, Flags); - - // Handle dwFlags - RestoreDrawStates(BufferDesc.dwFVF, dwFlags, DirectXVersion); - - return hr; - } - else - { - return GetProxyInterfaceV7()->DrawPrimitiveVB(dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, dwFlags); - } - } + return GetProxyInterfaceV7()->BeginStateBlock(); } -HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpVertices, DWORD dwVertexCount, LPWORD lpIndices, DWORD dwIndexCount, DWORD dwFlags, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::EndStateBlock(LPDWORD lpdwBlockHandle) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << - " VertexType = " << Logging::hex(dptPrimitiveType) << - " VertexDesc = " << Logging::hex(dwVertexTypeDesc) << - " Vertices = " << lpVertices << - " VertexCount = " << dwVertexCount << - " Indices = " << lpIndices << - " IndexCount = " << dwIndexCount << - " Flags = " << Logging::hex(dwFlags) << - " Version = " << DirectXVersion; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (DirectXVersion == 2 && ProxyDirectXVersion > 2) + if (Config.Dd7to9) { - if (dwVertexTypeDesc != D3DVT_VERTEX && dwVertexTypeDesc != D3DVT_LVERTEX && dwVertexTypeDesc != D3DVT_TLVERTEX) + if (!lpdwBlockHandle) { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid Vertex type: " << dwVertexTypeDesc); - return D3DERR_INVALIDVERTEXTYPE; + return DDERR_INVALIDPARAMS; } - dwVertexTypeDesc = ConvertVertexTypeToFVF((D3DVERTEXTYPE)dwVertexTypeDesc); - } + *lpdwBlockHandle = NULL; - if (Config.Dd7to9) - { - if (!lpVertices || !lpIndices) + if (!IsRecordingState) { - return DDERR_INVALIDPARAMS; + return DDERR_GENERIC; } // Check for device interface @@ -4394,396 +4238,358 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy return DDERR_INVALIDOBJECT; } -#ifdef ENABLE_PROFILING - auto startTime = std::chrono::high_resolution_clock::now(); -#endif - - dwFlags = (dwFlags & D3DDP_FORCE_DWORD); + HRESULT hr = (*d3d9Device)->EndStateBlock(reinterpret_cast(lpdwBlockHandle)); - // Handle PositionT - if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW) + if (SUCCEEDED(hr)) { - if (!ConvertHomogeneous.IsTransformViewSet) - { - D3DMATRIX Matrix = {}; - GetTransform(D3DTS_VIEW, &Matrix); - SetTransform(D3DTS_VIEW, &Matrix); - } - - if (!Config.DdrawConvertHomogeneousToWorld) - { - /*UINT8 *vertex = (UINT8*)lpVertices; - - for (UINT x = 0; x < dwVertexCount; x++) - { - float *pos = (float*) vertex; - - pos[3] = 1.0f; - - vertex += stride; - }*/ - - // Update the FVF - dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW; - } - else - { - const UINT stride = GetVertexStride(dwVertexTypeDesc); - - const UINT targetStride = stride - sizeof(float); - const UINT restSize = stride - sizeof(float) * 4; + IsRecordingState = false; + StateBlockTokens.insert(*lpdwBlockHandle); + } - ConvertHomogeneous.ToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount); + return hr; + } - UINT8* sourceVertex = (UINT8*)lpVertices; - UINT8* targetVertex = (UINT8*)ConvertHomogeneous.ToWorld_IntermediateGeometry.data(); + return GetProxyInterfaceV7()->EndStateBlock(lpdwBlockHandle); +} - lpVertices = targetVertex; +HRESULT m_IDirect3DDeviceX::PreLoad(LPDIRECTDRAWSURFACE7 lpddsTexture) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - for (UINT x = 0; x < dwVertexCount; x++) - { - // Transform the vertices into world space - float* srcpos = (float*)sourceVertex; - float* trgtpos = (float*)targetVertex; + if (Config.Dd7to9) + { + // Textures are loaded as managed in Direct3D9, so there is no need to manualy preload textures + return D3D_OK; + } - DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]); + if (lpddsTexture) + { + lpddsTexture->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpddsTexture); + } - DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, ConvertHomogeneous.ToWorld_ViewMatrixInverse); + return GetProxyInterfaceV7()->PreLoad(lpddsTexture); +} - xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global)); +HRESULT m_IDirect3DDeviceX::GetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7* lplpTexture) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - trgtpos[0] = DirectX::XMVectorGetX(xpos_global); - trgtpos[1] = DirectX::XMVectorGetY(xpos_global); - trgtpos[2] = DirectX::XMVectorGetZ(xpos_global); + if (Config.Dd7to9) + { + if (!lplpTexture || dwStage >= MaxTextureStages) + { + return DDERR_INVALIDPARAMS; + } + *lplpTexture = nullptr; - // Copy the rest - std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize); + HRESULT hr = DDERR_GENERIC; - // Move to next vertex - sourceVertex += stride; - targetVertex += targetStride; - } + if (AttachedTexture[dwStage]) + { + AttachedTexture[dwStage]->AddRef(); - // Set transform - (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix); - (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix); + *lplpTexture = AttachedTexture[dwStage]; - // Update the FVF - const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ; + hr = D3D_OK; + } - // Set fixed function vertex type - if (FAILED((*d3d9Device)->SetFVF(newVertexTypeDesc))) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); - return D3DERR_INVALIDVERTEXTYPE; - } + return hr; + } - // Handle dwFlags - SetDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); + HRESULT hr = GetProxyInterfaceV7()->GetTexture(dwStage, lplpTexture); - // Draw indexed primitive UP - HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); + if (SUCCEEDED(hr) && lplpTexture) + { + *lplpTexture = ProxyAddressLookupTable.FindAddress(*lplpTexture, 7); + } - // Handle dwFlags - RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); + return hr; +} - // Restore transform - D3DMATRIX identityMatrix = {}; - identityMatrix._11 = 1.0f; - identityMatrix._22 = 1.0f; - identityMatrix._33 = 1.0f; +HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpSurface) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - (*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal); - (*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix); + if (Config.Dd7to9) + { + if (dwStage >= MaxTextureStages) + { + return DDERR_INVALIDPARAMS; + } - return hr; - } + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; } - // Update vertices for Direct3D9 (needs to be first) - UpdateVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); + m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr; - // Set fixed function vertex type - if (FAILED((*d3d9Device)->SetFVF(dwVertexTypeDesc))) + HRESULT hr; + + if (!lpSurface) { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc)); - return DDERR_INVALIDPARAMS; + hr = (*d3d9Device)->SetTexture(dwStage, nullptr); } + else + { + lpSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX); + if (!lpDDSrcSurfaceX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface wrapper!"); + return DDERR_INVALIDPARAMS; + } - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + IDirect3DTexture9* pTexture9 = lpDDSrcSurfaceX->GetD3d9Texture(); + if (!pTexture9) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get texture!"); + return DDERR_INVALIDPARAMS; + } - // Draw indexed primitive UP - HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, GetVertexStride(dwVertexTypeDesc)); + if (lpCurrentRenderTargetX && lpCurrentRenderTargetX->IsPalette() && !lpDDSrcSurfaceX->IsPalette()) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: setting non-palette texture on a paletted render target!"); + } - // Handle dwFlags - RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); + hr = (*d3d9Device)->SetTexture(dwStage, pTexture9); + } - if (FAILED(hr)) + if (SUCCEEDED(hr)) { - LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawIndexedPrimitiveUP' call failed: " << (D3DERR)hr); + AttachedTexture[dwStage] = lpSurface; + CurrentTextureSurfaceX[dwStage] = lpDDSrcSurfaceX; } -#ifdef ENABLE_PROFILING - Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); -#endif - return hr; } - if (Config.DdrawUseNativeResolution) + if (lpSurface) { - ScaleVertices(dwVertexTypeDesc, lpVertices, dwVertexCount); + lpSurface->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpSurface); } - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->DrawIndexedPrimitive(dptPrimitiveType, (D3DVERTEXTYPE)dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, dwFlags); - case 3: - return GetProxyInterfaceV3()->DrawIndexedPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, dwFlags); - case 7: - if (DirectXVersion != 7) - { - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); - HRESULT hr = GetProxyInterfaceV7()->DrawIndexedPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, Flags); - - // Handle dwFlags - RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - return hr; - } - else - { - return GetProxyInterfaceV7()->DrawIndexedPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, lpIndices, dwIndexCount, dwFlags); - } - } + return GetProxyInterfaceV7()->SetTexture(dwStage, lpSurface); } -HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitiveStrided(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwVertexCount, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::ApplyStateBlock(DWORD dwBlockHandle) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); - return DDERR_UNSUPPORTED; - } - - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->DrawIndexedPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, dwFlags); - case 7: - if (DirectXVersion != 7) + if (!dwBlockHandle || StateBlockTokens.find(dwBlockHandle) == StateBlockTokens.end()) { - // Handle dwFlags - SetDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); - HRESULT hr = GetProxyInterfaceV7()->DrawIndexedPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, Flags); - - // Handle dwFlags - RestoreDrawStates(dwVertexTypeDesc, dwFlags, DirectXVersion); - - return hr; + return DDERR_INVALIDPARAMS; } - else + + if (IsRecordingState) { - return GetProxyInterfaceV7()->DrawIndexedPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, dwFlags); + return DDERR_GENERIC; } + + return reinterpret_cast(dwBlockHandle)->Apply(); } + + return GetProxyInterfaceV7()->ApplyStateBlock(dwBlockHandle); } -HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType, LPDIRECT3DVERTEXBUFFER7 lpd3dVertexBuffer, DWORD dwStartVertex, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags, DWORD DirectXVersion) +HRESULT m_IDirect3DDeviceX::CaptureStateBlock(DWORD dwBlockHandle) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << - " VertexType = " << Logging::hex(dptPrimitiveType) << - " VertexBuffer = " << lpd3dVertexBuffer << - " StartVertex = " << dwStartVertex << - " NumVertices = " << dwNumVertices << - " Indices = " << lpwIndices << - " IndexCount = " << dwIndexCount << - " Flags = " << Logging::hex(dwFlags) << - " Version = " << DirectXVersion; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpd3dVertexBuffer || !lpwIndices) + if (!dwBlockHandle || StateBlockTokens.find(dwBlockHandle) == StateBlockTokens.end()) { return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + if (IsRecordingState) { - return DDERR_INVALIDOBJECT; + return DDERR_GENERIC; } -#ifdef ENABLE_PROFILING - auto startTime = std::chrono::high_resolution_clock::now(); -#endif + return reinterpret_cast(dwBlockHandle)->Capture(); + } - dwFlags = (dwFlags & D3DDP_FORCE_DWORD); + return GetProxyInterfaceV7()->CaptureStateBlock(dwBlockHandle); +} - m_IDirect3DVertexBufferX* pVertexBufferX = nullptr; - lpd3dVertexBuffer->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pVertexBufferX); - if (!pVertexBufferX) +HRESULT m_IDirect3DDeviceX::DeleteStateBlock(DWORD dwBlockHandle) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!dwBlockHandle || StateBlockTokens.find(dwBlockHandle) == StateBlockTokens.end()) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get vertex buffer wrapper!"); return DDERR_INVALIDPARAMS; } - LPDIRECT3DVERTEXBUFFER9 d3d9VertexBuffer = pVertexBufferX->GetCurrentD9VertexBuffer(); - if (!d3d9VertexBuffer) + if (IsRecordingState) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get d3d9 vertex buffer!"); return DDERR_GENERIC; } - DWORD FVF = pVertexBufferX->GetFVF9(); + reinterpret_cast(dwBlockHandle)->Release(); - // Set fixed function vertex type - if (FAILED((*d3d9Device)->SetFVF(FVF))) + StateBlockTokens.erase(dwBlockHandle); + + return D3D_OK; + } + + return GetProxyInterfaceV7()->DeleteStateBlock(dwBlockHandle); +} + +HRESULT m_IDirect3DDeviceX::CreateStateBlock(D3DSTATEBLOCKTYPE d3dsbtype, LPDWORD lpdwBlockHandle) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpdwBlockHandle) { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(FVF)); return DDERR_INVALIDPARAMS; } + *lpdwBlockHandle = NULL; - // No operation to performed - if (dwIndexCount == 0) + if (IsRecordingState) { - return D3D_OK; + return DDERR_GENERIC; } - LPDIRECT3DINDEXBUFFER9 d3d9IndexBuffer = ddrawParent->GetIndexBuffer(lpwIndices, dwIndexCount); - if (!d3d9IndexBuffer) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get d3d9 index buffer!"); - return DDERR_GENERIC; + return DDERR_INVALIDOBJECT; } - // Set stream source - (*d3d9Device)->SetStreamSource(0, d3d9VertexBuffer, 0, GetVertexStride(FVF)); + HRESULT hr = (*d3d9Device)->CreateStateBlock(d3dsbtype, reinterpret_cast(lpdwBlockHandle)); - // Set Index data - (*d3d9Device)->SetIndices(d3d9IndexBuffer); + if (SUCCEEDED(hr)) + { + StateBlockTokens.insert(*lpdwBlockHandle); + } - // Handle dwFlags - SetDrawStates(FVF, dwFlags, DirectXVersion); + return hr; + } - // Draw primitive - HRESULT hr = (*d3d9Device)->DrawIndexedPrimitive(dptPrimitiveType, dwStartVertex, 0, dwNumVertices, 0, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount)); + return GetProxyInterfaceV7()->CreateStateBlock(d3dsbtype, lpdwBlockHandle); +} - // Handle dwFlags - RestoreDrawStates(FVF, dwFlags, DirectXVersion); +HRESULT m_IDirect3DDeviceX::Load(LPDIRECTDRAWSURFACE7 lpDestTex, LPPOINT lpDestPoint, LPDIRECTDRAWSURFACE7 lpSrcTex, LPRECT lprcSrcRect, DWORD dwFlags) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (FAILED(hr)) + if (Config.Dd7to9) + { + if (!lpDestTex || !lpSrcTex) { - LOG_LIMIT(100, __FUNCTION__ << " Error: 'DrawIndexedPrimitive' call failed: " << (D3DERR)hr); + return DDERR_INVALIDPARAMS; } -#ifdef ENABLE_PROFILING - Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); -#endif + m_IDirectDrawSurfaceX* pDestSurfaceX = nullptr; + lpDestTex->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pDestSurfaceX); + if (!pDestSurfaceX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get surface!"); + return DDERR_GENERIC; + } - return hr; + return pDestSurfaceX->Load(lpDestTex, lpDestPoint, lpSrcTex, lprcSrcRect, dwFlags); } - if (lpd3dVertexBuffer) + if (lpDestTex) { - lpd3dVertexBuffer->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpd3dVertexBuffer); + lpDestTex->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDestTex); } - - switch (ProxyDirectXVersion) + if (lpSrcTex) { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->DrawIndexedPrimitiveVB(dptPrimitiveType, (LPDIRECT3DVERTEXBUFFER)lpd3dVertexBuffer, lpwIndices, dwIndexCount, dwFlags); - case 7: - if (DirectXVersion != 7) - { - D3DVERTEXBUFFERDESC BufferDesc = {}; - if (lpd3dVertexBuffer) - { - lpd3dVertexBuffer->GetVertexBufferDesc(&BufferDesc); - } + lpSrcTex->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpSrcTex); + } - // Handle dwFlags - SetDrawStates(BufferDesc.dwFVF, dwFlags, DirectXVersion); + return GetProxyInterfaceV7()->Load(lpDestTex, lpDestPoint, lpSrcTex, lprcSrcRect, dwFlags); +} - DWORD Flags = dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); - HRESULT hr = GetProxyInterfaceV7()->DrawIndexedPrimitiveVB(dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, Flags); +HRESULT m_IDirect3DDeviceX::LightEnable(DWORD dwLightIndex, BOOL bEnable) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; + } - // Handle dwFlags - RestoreDrawStates(BufferDesc.dwFVF, dwFlags, DirectXVersion); + HRESULT hr = LightD9Enable(dwLightIndex, bEnable); - return hr; - } - else + if (SUCCEEDED(hr)) { - return GetProxyInterfaceV7()->DrawIndexedPrimitiveVB(dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags); +#ifdef ENABLE_DEBUGOVERLAY + if (Config.EnableImgui) + { + DOverlay.LightEnable(dwLightIndex, bEnable); + } +#endif } + + return hr; } + + return GetProxyInterfaceV7()->LightEnable(dwLightIndex, bEnable); } -HRESULT m_IDirect3DDeviceX::ComputeSphereVisibility(LPD3DVECTOR lpCenters, LPD3DVALUE lpRadii, DWORD dwNumSpheres, DWORD dwFlags, LPDWORD lpdwReturnValues) +HRESULT m_IDirect3DDeviceX::GetLightEnable(DWORD dwLightIndex, BOOL* pbEnable) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpCenters || !lpRadii || !dwNumSpheres || !lpdwReturnValues) + if (!pbEnable) { return DDERR_INVALIDPARAMS; } - LOG_LIMIT(100, __FUNCTION__ << " Warning: function not fully implemented"); - - // Sphere visibility is computed by back-transforming the viewing frustum to the model space, using the inverse of the combined world, view, or projection matrices. - // If the combined matrix can't be inverted (if the determinant is 0), the method will fail, returning D3DERR_INVALIDMATRIX. - for (UINT x = 0; x < dwNumSpheres; x++) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) { - // If a sphere is completely visible, the corresponding entry in lpdwReturnValues is 0. - lpdwReturnValues[x] = 0; // Just return all is visible for now + return DDERR_INVALIDOBJECT; } - return D3D_OK; + return (*d3d9Device)->GetLightEnable(dwLightIndex, pbEnable); } - switch (ProxyDirectXVersion) + return GetProxyInterfaceV7()->GetLightEnable(dwLightIndex, pbEnable); +} + +HRESULT m_IDirect3DDeviceX::SetClipPlane(DWORD dwIndex, D3DVALUE* pPlaneEquation) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->ComputeSphereVisibility(lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues); - case 7: - return GetProxyInterfaceV7()->ComputeSphereVisibility(lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues); + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__, true))) + { + return DDERR_INVALIDOBJECT; + } + + return (*d3d9Device)->SetClipPlane(dwIndex, pPlaneEquation); } + + return GetProxyInterfaceV7()->SetClipPlane(dwIndex, pPlaneEquation); } -HRESULT m_IDirect3DDeviceX::ValidateDevice(LPDWORD lpdwPasses) +HRESULT m_IDirect3DDeviceX::GetClipPlane(DWORD dwIndex, D3DVALUE* pPlaneEquation) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpdwPasses) + if (!pPlaneEquation) { return DDERR_INVALIDPARAMS; } @@ -4794,432 +4600,451 @@ HRESULT m_IDirect3DDeviceX::ValidateDevice(LPDWORD lpdwPasses) return DDERR_INVALIDOBJECT; } - DWORD FVF, Size; - IDirect3DVertexBuffer9* vertexBuffer = ddrawParent->GetValidateDeviceVertexBuffer(FVF, Size); + return (*d3d9Device)->SetClipPlane(dwIndex, pPlaneEquation); + } - if (!vertexBuffer) + return GetProxyInterfaceV7()->GetClipPlane(dwIndex, pPlaneEquation); +} + +HRESULT m_IDirect3DDeviceX::GetInfo(DWORD dwDevInfoID, LPVOID pDevInfoStruct, DWORD dwSize) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!pDevInfoStruct || dwSize == 0) { - LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to get vertex buffer!"); return DDERR_GENERIC; } - // Bind the vertex buffer to the device - (*d3d9Device)->SetStreamSource(0, vertexBuffer, 0, Size); - - // Set a simple FVF (Flexible Vertex Format) - (*d3d9Device)->SetFVF(FVF); +#ifdef _DEBUG + // Fill device info structures + switch (dwDevInfoID) + { + case D3DDEVINFOID_TEXTUREMANAGER: + case D3DDEVINFOID_D3DTEXTUREMANAGER: + if (dwSize == sizeof(D3DDEVINFO_TEXTUREMANAGER)) + { + // Simulate a default texture manager structure for a good video card + D3DDEVINFO_TEXTUREMANAGER* pTexManagerInfo = (D3DDEVINFO_TEXTUREMANAGER*)pDevInfoStruct; + pTexManagerInfo->bThrashing = FALSE; + pTexManagerInfo->dwNumEvicts = 0; + pTexManagerInfo->dwNumVidCreates = 0; + pTexManagerInfo->dwNumTexturesUsed = 0; + pTexManagerInfo->dwNumUsedTexInVid = 0; + pTexManagerInfo->dwWorkingSet = 0; + pTexManagerInfo->dwWorkingSetBytes = 0; + pTexManagerInfo->dwTotalManaged = 0; + pTexManagerInfo->dwTotalBytes = 0; + pTexManagerInfo->dwLastPri = 0; + break; + } + return DDERR_GENERIC; - // Call ValidateDevice - HRESULT hr = (*d3d9Device)->ValidateDevice(lpdwPasses); + case D3DDEVINFOID_TEXTURING: + if (dwSize == sizeof(D3DDEVINFO_TEXTURING)) + { + // Simulate a default texturing activity structure for a good video card + D3DDEVINFO_TEXTURING* pTexturingInfo = (D3DDEVINFO_TEXTURING*)pDevInfoStruct; + pTexturingInfo->dwNumLoads = 0; + pTexturingInfo->dwApproxBytesLoaded = 0; + pTexturingInfo->dwNumPreLoads = 0; + pTexturingInfo->dwNumSet = 0; + pTexturingInfo->dwNumCreates = 0; + pTexturingInfo->dwNumDestroys = 0; + pTexturingInfo->dwNumSetPriorities = 0; + pTexturingInfo->dwNumSetLODs = 0; + pTexturingInfo->dwNumLocks = 0; + pTexturingInfo->dwNumGetDCs = 0; + break; + } + return DDERR_GENERIC; - if (FAILED(hr)) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: ValidateDevice() function failed: " << (DDERR)hr); + default: + Logging::LogDebug() << __FUNCTION__ << " Error: Unknown DevInfoID: " << dwDevInfoID; + return DDERR_GENERIC; } +#endif - return hr; + // This method is intended to be used for performance tracking and debugging during product development (on the debug version of DirectX). + // The method can succeed, returning S_FALSE, without retrieving device data. + // This occurs when the retail version of the DirectX runtime is installed on the host system. + return S_FALSE; } - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->ValidateDevice(lpdwPasses); - case 7: - return GetProxyInterfaceV7()->ValidateDevice(lpdwPasses); - } + return GetProxyInterfaceV7()->GetInfo(dwDevInfoID, pDevInfoStruct, dwSize); } -HRESULT m_IDirect3DDeviceX::ApplyStateBlock(DWORD dwBlockHandle) +// ****************************** +// Helper functions +// ****************************** + +void m_IDirect3DDeviceX::InitInterface(DWORD DirectXVersion) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + ScopedDDCriticalSection ThreadLockDD; + + if (ddrawParent) + { + ddrawParent->SetD3DDevice(this); + } + + if (D3DInterface) + { + D3DInterface->SetD3DDevice(this); + } if (Config.Dd7to9) { - if (!dwBlockHandle || StateBlockTokens.find(dwBlockHandle) == StateBlockTokens.end()) + if (ddrawParent) { - return DDERR_INVALIDPARAMS; + d3d9Device = ddrawParent->GetDirectD9Device(); + + if (CurrentRenderTarget) + { + m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr; + + CurrentRenderTarget->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX); + if (lpDDSrcSurfaceX) + { + CurrentRenderTarget->AddRef(); + + lpCurrentRenderTargetX = lpDDSrcSurfaceX; + + ddrawParent->SetRenderTargetSurface(lpCurrentRenderTargetX); + } + } } - if (IsRecordingState) + if (Config.DdrawConvertHomogeneousW) { - return DDERR_GENERIC; + ZeroMemory(&ConvertHomogeneous.ToWorld_ViewMatrix, sizeof(D3DMATRIX)); + ConvertHomogeneous.ToWorld_ViewMatrix._11 = 1.0f; + ConvertHomogeneous.ToWorld_ViewMatrix._22 = 1.0f; + ConvertHomogeneous.ToWorld_ViewMatrix._33 = 1.0f; + ConvertHomogeneous.ToWorld_ViewMatrix._44 = 1.0f; + + ConvertHomogeneous.ToWorld_ProjectionMatrix = ConvertHomogeneous.ToWorld_ViewMatrix; + ConvertHomogeneous.ToWorld_ViewMatrixOriginal = ConvertHomogeneous.ToWorld_ViewMatrix; } - return reinterpret_cast(dwBlockHandle)->Apply(); + AddRef(DirectXVersion); } +} - return GetProxyInterfaceV7()->ApplyStateBlock(dwBlockHandle); +void m_IDirect3DDeviceX::ReleaseInterface() +{ + if (Config.Exiting) + { + return; + } + + ScopedDDCriticalSection ThreadLockDD; + + if (CurrentRenderTarget) + { + lpCurrentRenderTargetX = nullptr; + + CurrentRenderTarget->Release(); + CurrentRenderTarget = nullptr; + } + + if (ddrawParent) + { + ddrawParent->ClearD3DDevice(this); + } + + if (D3DInterface) + { + D3DInterface->ClearD3DDevice(this); + } + + // Don't delete wrapper interface + SaveInterfaceAddress(WrapperInterface, WrapperInterfaceBackup); + SaveInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2); + SaveInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3); + SaveInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7); + + // Clear ExecuteBuffers + for (auto& entry : ExecuteBufferList) + { + entry->ClearD3DDevice(); + } + + ReleaseAllStateBlocks(); } -HRESULT m_IDirect3DDeviceX::CaptureStateBlock(DWORD dwBlockHandle) +HRESULT m_IDirect3DDeviceX::CheckInterface(char *FunctionName, bool CheckD3DDevice) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Check ddrawParent device + if (!ddrawParent) + { + LOG_LIMIT(100, FunctionName << " Error: no ddraw parent!"); + return DDERR_INVALIDOBJECT; + } - if (Config.Dd7to9) + // Check d3d9 device + if (CheckD3DDevice) { - if (!dwBlockHandle || StateBlockTokens.find(dwBlockHandle) == StateBlockTokens.end()) + if (!ddrawParent->CheckD9Device(FunctionName) || !d3d9Device || !*d3d9Device) { - return DDERR_INVALIDPARAMS; + LOG_LIMIT(100, FunctionName << " Error: d3d9 device not setup!"); + return DDERR_INVALIDOBJECT; } - - if (IsRecordingState) + if (bSetDefaults) { - return DDERR_GENERIC; + SetDefaults(); } - - return reinterpret_cast(dwBlockHandle)->Capture(); } - return GetProxyInterfaceV7()->CaptureStateBlock(dwBlockHandle); + return D3D_OK; } -HRESULT m_IDirect3DDeviceX::DeleteStateBlock(DWORD dwBlockHandle) +void* m_IDirect3DDeviceX::GetWrapperInterfaceX(DWORD DirectXVersion) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + switch (DirectXVersion) + { + case 0: + if (WrapperInterface7) return WrapperInterface7; + if (WrapperInterface3) return WrapperInterface3; + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DDEVICE)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DDEVICE2)ProxyInterface, this); + case 3: + return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3DDEVICE3)ProxyInterface, this); + case 7: + return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECT3DDEVICE7)ProxyInterface, this); + } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} - if (Config.Dd7to9) +void m_IDirect3DDeviceX::ClearTextureHandle(D3DTEXTUREHANDLE tHandle) +{ + if (tHandle) { - if (!dwBlockHandle || StateBlockTokens.find(dwBlockHandle) == StateBlockTokens.end()) - { - return DDERR_INVALIDPARAMS; - } + TextureHandleMap.erase(tHandle); - if (IsRecordingState) + // If texture handle is set then clear it + if (rsTextureHandle == tHandle) { - return DDERR_GENERIC; + SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, 0); } + } +} - reinterpret_cast(dwBlockHandle)->Release(); - - StateBlockTokens.erase(dwBlockHandle); +HRESULT m_IDirect3DDeviceX::SetTextureHandle(D3DTEXTUREHANDLE& tHandle, m_IDirect3DTextureX* pTextureX) +{ + if (!tHandle || !pTextureX) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: NULL pointer found! " << pTextureX << " -> " << tHandle); + return DDERR_INVALIDPARAMS; + } - return D3D_OK; + // Ensure that the handle is unique + while (GetTexture(tHandle)) + { + tHandle += 4; } - return GetProxyInterfaceV7()->DeleteStateBlock(dwBlockHandle); + TextureHandleMap[tHandle] = pTextureX; + + return D3D_OK; } -HRESULT m_IDirect3DDeviceX::CreateStateBlock(D3DSTATEBLOCKTYPE d3dsbtype, LPDWORD lpdwBlockHandle) +void m_IDirect3DDeviceX::ClearLight(m_IDirect3DLight* lpLight) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (Config.Dd7to9) + // Find handle associated with Light + auto it = LightIndexMap.begin(); + while (it != LightIndexMap.end()) { - if (!lpdwBlockHandle) - { - return DDERR_INVALIDPARAMS; - } - *lpdwBlockHandle = NULL; - - if (IsRecordingState) + if (it->second == lpLight) { - return DDERR_GENERIC; - } + // Disable light before removing + LightEnable(it->first, FALSE); - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_INVALIDOBJECT; + // Remove entry from map + it = LightIndexMap.erase(it); } - - HRESULT hr = (*d3d9Device)->CreateStateBlock(d3dsbtype, reinterpret_cast(lpdwBlockHandle)); - - if (SUCCEEDED(hr)) + else { - StateBlockTokens.insert(*lpdwBlockHandle); + ++it; } - - return hr; } - - return GetProxyInterfaceV7()->CreateStateBlock(d3dsbtype, lpdwBlockHandle); } -HRESULT m_IDirect3DDeviceX::SetClipStatus(LPD3DCLIPSTATUS lpD3DClipStatus) +HRESULT m_IDirect3DDeviceX::SetLight(m_IDirect3DLight* lpLightInterface, LPD3DLIGHT lpLight) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (Config.Dd7to9) + if (!lpLightInterface || !lpLight || (lpLight->dwSize != sizeof(D3DLIGHT) && lpLight->dwSize != sizeof(D3DLIGHT2))) { - // D3DCLIPSTATUS_EXTENTS2 flag cannot be combined with D3DCLIPSTATUS_EXTENTS3. - if (!lpD3DClipStatus || (lpD3DClipStatus->dwFlags & (D3DCLIPSTATUS_EXTENTS2 | D3DCLIPSTATUS_EXTENTS3)) == (D3DCLIPSTATUS_EXTENTS2 | D3DCLIPSTATUS_EXTENTS3)) - { - return DDERR_INVALIDPARAMS; - } + return DDERR_INVALIDPARAMS; + } - // D3DCLIPSTATUS_EXTENTS3 is Not currently implemented in DirectDraw. - if (lpD3DClipStatus->dwFlags & D3DCLIPSTATUS_EXTENTS3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: only clip status flag is supported. Using unsupported dwFlags combination: " << Logging::hex(lpD3DClipStatus->dwFlags)); - return DDERR_INVALIDPARAMS; - } - else if (lpD3DClipStatus->dwFlags & D3DCLIPSTATUS_EXTENTS2) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Extents 2D flag Not Implemented: " << *lpD3DClipStatus); - D3DClipStatus = *lpD3DClipStatus; - } + D3DLIGHT7 Light7; - // For now just save clip status - if (lpD3DClipStatus->dwFlags & D3DCLIPSTATUS_STATUS) - { - D3DClipStatus = *lpD3DClipStatus; - D3DClipStatus.dwFlags = D3DCLIPSTATUS_STATUS; - D3DClipStatus.dwStatus = 0; - return D3D_OK; - } + // ToDo: the dvAttenuation members are interpreted differently in D3DLIGHT2 than they were for D3DLIGHT. - // ToDo: set clip status from dwStatus + ConvertLight(Light7, *lpLight); - // ToDo: check the D3DRENDERSTATE_EXTENTS flag and use that to enable or disable extents clip planes - // The default setting for this state, FALSE, disables extent updates. Applications that intend to use the - // IDirect3DDevice7::GetClipStatus and IDirect3DDevice7::SetClipStatus methods to manipulate the viewport extents - // can enable extents updates by setting D3DRENDERSTATE_EXTENTS to TRUE. + DWORD dwLightIndex = 0; - // Check for device interface - /*if (FAILED(CheckInterface(__FUNCTION__, true))) + // Check if Light exists in the map + for (auto& entry : LightIndexMap) + { + if (entry.second == lpLightInterface) { - return DDERR_INVALIDOBJECT; + dwLightIndex = entry.first; + break; } + } - // Calculate the center of the bounding box - float centerX = (lpD3DClipStatus->minx + lpD3DClipStatus->maxx) * 0.5f; - float centerY = (lpD3DClipStatus->miny + lpD3DClipStatus->maxy) * 0.5f; - float centerZ = (lpD3DClipStatus->minz + lpD3DClipStatus->maxz) * 0.5f; - - // Calculate the extents (half-width, half-height, and half-depth) of the bounding box - float halfWidth = (lpD3DClipStatus->maxx - lpD3DClipStatus->minx) * 0.5f; - float halfHeight = (lpD3DClipStatus->maxy - lpD3DClipStatus->miny) * 0.5f; - float halfDepth = (lpD3DClipStatus->maxz - lpD3DClipStatus->minz) * 0.5f; - - // Calculate the front clipping plane coefficients - float frontNormalX = -1.0f; // Clipping towards the negative X direction - float frontNormalY = 0.0f; - float frontNormalZ = 0.0f; - float frontDistance = centerX - halfWidth; - - float frontClipPlane[4] = { frontNormalX, frontNormalY, frontNormalZ, frontDistance }; - - // Calculate the back clipping plane coefficients - float backNormalX = 1.0f; // Clipping towards the positive X direction - float backNormalY = 0.0f; - float backNormalZ = 0.0f; - float backDistance = -(centerX + halfWidth); - - float backClipPlane[4] = { backNormalX, backNormalY, backNormalZ, backDistance }; - - // Calculate the top clipping plane coefficients - float topNormalX = 0.0f; - float topNormalY = 1.0f; // Clipping towards the positive Y direction - float topNormalZ = 0.0f; - float topDistance = -(centerY + halfHeight); - - float topClipPlane[4] = { topNormalX, topNormalY, topNormalZ, topDistance }; - - // Calculate the bottom clipping plane coefficients - float bottomNormalX = 0.0f; - float bottomNormalY = -1.0f; // Clipping towards the negative Y direction - float bottomNormalZ = 0.0f; - float bottomDistance = centerY - halfHeight; - - float bottomClipPlane[4] = { bottomNormalX, bottomNormalY, bottomNormalZ, bottomDistance }; - - // Calculate the near clipping plane coefficients - float nearNormalX = 0.0f; - float nearNormalY = 0.0f; - float nearNormalZ = -1.0f; // Clipping towards the negative Z direction - float nearDistance = centerZ - halfDepth; - - float nearClipPlane[4] = { nearNormalX, nearNormalY, nearNormalZ, nearDistance }; - - // Calculate the far clipping plane coefficients - float farNormalX = 0.0f; - float farNormalY = 0.0f; - float farNormalZ = 1.0f; // Clipping towards the positive Z direction - float farDistance = -(centerZ + halfDepth); - - float farClipPlane[4] = { farNormalX, farNormalY, farNormalZ, farDistance }; - - // Set the clip planes - int x = 0; - for (auto clipPlane : { frontClipPlane, backClipPlane, topClipPlane, bottomClipPlane, nearClipPlane, farClipPlane }) + // Create index and add light to the map + if (dwLightIndex == 0) + { + BYTE Start = (BYTE)((DWORD)lpLightInterface & 0xff); + for (BYTE x = Start; x != Start - 1; x++) { - HRESULT hr = (*d3d9Device)->SetClipPlane(x, clipPlane); - if (FAILED(hr)) + bool Flag = true; + for (auto& entry : LightIndexMap) { - LOG_LIMIT(100, __FUNCTION__ << " Error: 'SetClipPlane' call failed: " << (D3DERR)hr << - " call: { " << clipPlane[0] << ", " << clipPlane[1] << ", " << clipPlane[2] << ", " << clipPlane[3] << "}"); - return hr; + if (entry.first == x) + { + Flag = false; + break; + } + } + if (x != 0 && Flag) + { + dwLightIndex = x; + break; } - x++; } - - // To enable a clipping plane, set the corresponding bit in the DWORD value applied to the D3DRS_CLIPPLANEENABLE render state. - SetD9RenderState(D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0 | D3DCLIPPLANE1 | D3DCLIPPLANE2 | D3DCLIPPLANE3 | D3DCLIPPLANE4 | D3DCLIPPLANE5);*/ - - return D3D_OK; } - switch (ProxyDirectXVersion) + if (dwLightIndex == 0) { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->SetClipStatus(lpD3DClipStatus); - case 3: - return GetProxyInterfaceV3()->SetClipStatus(lpD3DClipStatus); - case 7: - return GetProxyInterfaceV7()->SetClipStatus(lpD3DClipStatus); + LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to find an available Light Index"); + return DDERR_INVALIDPARAMS; } -} -HRESULT m_IDirect3DDeviceX::GetClipStatus(LPD3DCLIPSTATUS lpD3DClipStatus) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // Add light to index map + LightIndexMap[dwLightIndex] = lpLightInterface; - if (Config.Dd7to9) + HRESULT hr = SetLight(dwLightIndex, &Light7); + + if (SUCCEEDED(hr)) { - if (!lpD3DClipStatus) + if (((LPD3DLIGHT2)lpLight)->dwSize == sizeof(D3DLIGHT2) && (((LPD3DLIGHT2)lpLight)->dwFlags & D3DLIGHT_ACTIVE) == NULL) { - return DDERR_INVALIDPARAMS; + LightEnable(dwLightIndex, FALSE); + } + else + { + LightEnable(dwLightIndex, TRUE); } - - *lpD3DClipStatus = D3DClipStatus; - - return D3D_OK; } - switch (ProxyDirectXVersion) - { - case 1: - default: - return DDERR_GENERIC; - case 2: - return GetProxyInterfaceV2()->GetClipStatus(lpD3DClipStatus); - case 3: - return GetProxyInterfaceV3()->GetClipStatus(lpD3DClipStatus); - case 7: - return GetProxyInterfaceV7()->GetClipStatus(lpD3DClipStatus); - } + return hr; } -HRESULT m_IDirect3DDeviceX::SetClipPlane(DWORD dwIndex, D3DVALUE* pPlaneEquation) +HRESULT m_IDirect3DDeviceX::GetLightEnable(m_IDirect3DLight* lpLightInterface, BOOL* pbEnable) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + if (!lpLightInterface || !pbEnable) + { + return DDERR_INVALIDPARAMS; + } - if (Config.Dd7to9) + DWORD dwLightIndex = 0; + + // Check if Light exists in the map + for (auto& entry : LightIndexMap) { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + if (entry.second == lpLightInterface) { - return DDERR_INVALIDOBJECT; + dwLightIndex = entry.first; + break; } + } - return (*d3d9Device)->SetClipPlane(dwIndex, pPlaneEquation); + if (dwLightIndex == 0) + { + return DDERR_INVALIDPARAMS; } - return GetProxyInterfaceV7()->SetClipPlane(dwIndex, pPlaneEquation); + return GetLightEnable(dwLightIndex, pbEnable); } -HRESULT m_IDirect3DDeviceX::GetClipPlane(DWORD dwIndex, D3DVALUE* pPlaneEquation) +void m_IDirect3DDeviceX::ClearMaterialHandle(D3DMATERIALHANDLE mHandle) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (Config.Dd7to9) + if (mHandle) { - if (!pPlaneEquation) - { - return DDERR_INVALIDPARAMS; - } + TextureHandleMap.erase(mHandle); - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) + // If material handle is set then clear it + if (lsMaterialHandle == mHandle) { - return DDERR_INVALIDOBJECT; + SetLightState(D3DLIGHTSTATE_MATERIAL, 0); } + } +} - return (*d3d9Device)->SetClipPlane(dwIndex, pPlaneEquation); +HRESULT m_IDirect3DDeviceX::SetMaterialHandle(D3DMATERIALHANDLE& mHandle, m_IDirect3DMaterialX* lpMaterial) +{ + if (!mHandle || !lpMaterial) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: NULL pointer found! " << lpMaterial << " -> " << mHandle); + return DDERR_GENERIC; } - return GetProxyInterfaceV7()->GetClipPlane(dwIndex, pPlaneEquation); + // Ensure that the handle is unique + while (GetMaterial(mHandle)) + { + mHandle += 4; + } + + MaterialHandleMap[mHandle] = lpMaterial; + + return D3D_OK; } -HRESULT m_IDirect3DDeviceX::GetInfo(DWORD dwDevInfoID, LPVOID pDevInfoStruct, DWORD dwSize) +HRESULT m_IDirect3DDeviceX::SetMaterial(LPD3DMATERIAL lpMaterial) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (Config.Dd7to9) + if (!lpMaterial) { - if (!pDevInfoStruct || dwSize == 0) - { - return DDERR_GENERIC; - } + return DDERR_INVALIDPARAMS; + } -#ifdef _DEBUG - // Fill device info structures - switch (dwDevInfoID) - { - case D3DDEVINFOID_TEXTUREMANAGER: - case D3DDEVINFOID_D3DTEXTUREMANAGER: - if (dwSize == sizeof(D3DDEVINFO_TEXTUREMANAGER)) - { - // Simulate a default texture manager structure for a good video card - D3DDEVINFO_TEXTUREMANAGER* pTexManagerInfo = (D3DDEVINFO_TEXTUREMANAGER*)pDevInfoStruct; - pTexManagerInfo->bThrashing = FALSE; - pTexManagerInfo->dwNumEvicts = 0; - pTexManagerInfo->dwNumVidCreates = 0; - pTexManagerInfo->dwNumTexturesUsed = 0; - pTexManagerInfo->dwNumUsedTexInVid = 0; - pTexManagerInfo->dwWorkingSet = 0; - pTexManagerInfo->dwWorkingSetBytes = 0; - pTexManagerInfo->dwTotalManaged = 0; - pTexManagerInfo->dwTotalBytes = 0; - pTexManagerInfo->dwLastPri = 0; - break; - } - return DDERR_GENERIC; + D3DMATERIAL7 Material7; - case D3DDEVINFOID_TEXTURING: - if (dwSize == sizeof(D3DDEVINFO_TEXTURING)) - { - // Simulate a default texturing activity structure for a good video card - D3DDEVINFO_TEXTURING* pTexturingInfo = (D3DDEVINFO_TEXTURING*)pDevInfoStruct; - pTexturingInfo->dwNumLoads = 0; - pTexturingInfo->dwApproxBytesLoaded = 0; - pTexturingInfo->dwNumPreLoads = 0; - pTexturingInfo->dwNumSet = 0; - pTexturingInfo->dwNumCreates = 0; - pTexturingInfo->dwNumDestroys = 0; - pTexturingInfo->dwNumSetPriorities = 0; - pTexturingInfo->dwNumSetLODs = 0; - pTexturingInfo->dwNumLocks = 0; - pTexturingInfo->dwNumGetDCs = 0; - break; - } - return DDERR_GENERIC; + ConvertMaterial(Material7, *lpMaterial); - default: - Logging::LogDebug() << __FUNCTION__ << " Error: Unknown DevInfoID: " << dwDevInfoID; - return DDERR_GENERIC; - } -#endif + HRESULT hr = SetMaterial(&Material7); - // This method is intended to be used for performance tracking and debugging during product development (on the debug version of DirectX). - // The method can succeed, returning S_FALSE, without retrieving device data. - // This occurs when the retail version of the DirectX runtime is installed on the host system. - return S_FALSE; + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to set material: " << (D3DERR)hr); + return hr; } - return GetProxyInterfaceV7()->GetInfo(dwDevInfoID, pDevInfoStruct, dwSize); -} + if (lpMaterial->dwRampSize) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: RampSize Not Implemented: " << lpMaterial->dwRampSize); + } + + if (lpMaterial->hTexture) + { + SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, lpMaterial->hTexture); + } -/************************/ -/*** Helper functions ***/ -/************************/ + return D3D_OK; +} void m_IDirect3DDeviceX::ClearSurface(m_IDirectDrawSurfaceX* lpSurfaceX) { @@ -5255,119 +5080,233 @@ void m_IDirect3DDeviceX::SetDdrawParent(m_IDirectDrawX* ddraw) } } -void m_IDirect3DDeviceX::InitInterface(DWORD DirectXVersion) +void m_IDirect3DDeviceX::AddExecuteBuffer(m_IDirect3DExecuteBuffer* lpExecuteBuffer) { - if (ddrawParent) + if (!lpExecuteBuffer) { - ddrawParent->SetD3DDevice(this); + return; } - if (D3DInterface) + ExecuteBufferList.push_back(lpExecuteBuffer); +} + +void m_IDirect3DDeviceX::ClearExecuteBuffer(m_IDirect3DExecuteBuffer* lpExecuteBuffer) +{ + // Find and remove the buffer from the list + auto it = std::find(ExecuteBufferList.begin(), ExecuteBufferList.end(), lpExecuteBuffer); + if (it != ExecuteBufferList.end()) { - D3DInterface->SetD3DDevice(this); + ExecuteBufferList.erase(it); } +} - if (Config.Dd7to9) +void m_IDirect3DDeviceX::CopyConvertExecuteVertex(BYTE*& DestVertex, DWORD& DestVertexCount, BYTE* SrcVertex, DWORD SrcIndex, DWORD VertexTypeDesc) +{ + // Primitive structures and related defines. Vertex offsets are to types D3DVERTEX, D3DLVERTEX, or D3DTLVERTEX. + if (VertexTypeDesc == D3DFVF_VERTEX) { - if (ddrawParent) - { - d3d9Device = ddrawParent->GetDirectD9Device(); - - if (CurrentRenderTarget) - { - m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr; - - CurrentRenderTarget->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX); - if (lpDDSrcSurfaceX) - { - CurrentRenderTarget->AddRef(); - - lpCurrentRenderTargetX = lpDDSrcSurfaceX; + DestVertexCount++; + *((D3DVERTEX*)DestVertex) = ((D3DVERTEX*)SrcVertex)[SrcIndex]; + DestVertex += sizeof(D3DVERTEX); + return; + } + else if (VertexTypeDesc == D3DFVF_LVERTEX) + { + DestVertexCount++; + *((D3DLVERTEX*)DestVertex) = ((D3DLVERTEX*)SrcVertex)[SrcIndex]; + DestVertex += sizeof(D3DLVERTEX); + return; + } + else if (VertexTypeDesc == D3DFVF_TLVERTEX) + { + DestVertexCount++; + *((D3DTLVERTEX*)DestVertex) = ((D3DTLVERTEX*)SrcVertex)[SrcIndex]; + DestVertex += sizeof(D3DTLVERTEX); + return; + } +} - ddrawParent->SetRenderTargetSurface(lpCurrentRenderTargetX); - } - } - } +HRESULT m_IDirect3DDeviceX::DrawExecutePoint(D3DPOINT* point, WORD pointCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) +{ + // Define vertices and setup vector + std::vector vertices; + vertices.resize(sizeof(D3DTLVERTEX) * pointCount); + BYTE* verticesData = vertices.data(); + DWORD verticesCount = 0; - if (Config.DdrawConvertHomogeneousW) - { - ZeroMemory(&ConvertHomogeneous.ToWorld_ViewMatrix, sizeof(D3DMATRIX)); - ConvertHomogeneous.ToWorld_ViewMatrix._11 = 1.0f; - ConvertHomogeneous.ToWorld_ViewMatrix._22 = 1.0f; - ConvertHomogeneous.ToWorld_ViewMatrix._33 = 1.0f; - ConvertHomogeneous.ToWorld_ViewMatrix._44 = 1.0f; + // Add vertices to vector + for (DWORD i = 0; i < pointCount; i++) + { + if ((DWORD)point[i].wFirst < vertexIndexCount) + { + DWORD count = min(point[i].wCount, vertexIndexCount - point[i].wFirst); - ConvertHomogeneous.ToWorld_ProjectionMatrix = ConvertHomogeneous.ToWorld_ViewMatrix; - ConvertHomogeneous.ToWorld_ViewMatrixOriginal = ConvertHomogeneous.ToWorld_ViewMatrix; + for (DWORD x = 0; x < count; x++) + { + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, point[i].wFirst + x, VertexTypeDesc); + } } - - AddRef(DirectXVersion); } -} -void m_IDirect3DDeviceX::ReleaseInterface() -{ - if (Config.Exiting) + if (verticesCount) { - return; + // Pass the vertex data to the rendering pipeline + DrawPrimitive(D3DPT_POINTLIST, VertexTypeDesc, vertices.data(), verticesCount, 0, 1); } - if (ddrawParent) - { - ddrawParent->ClearD3DDevice(this); - } + return D3D_OK; +} - if (D3DInterface) - { - D3DInterface->ClearD3DDevice(this); - } +HRESULT m_IDirect3DDeviceX::DrawExecuteLine(D3DLINE* line, WORD lineCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) +{ + // Define vertices and setup vector + std::vector vertices; + vertices.resize(sizeof(D3DTLVERTEX) * lineCount * 2); + BYTE* verticesData = vertices.data(); + DWORD verticesCount = 0; - if (CurrentRenderTarget) + for (DWORD i = 0; i < lineCount; i++) { - CurrentRenderTarget->Release(); + if (line[i].v1 < vertexIndexCount && line[i].v2 < vertexIndexCount) + { + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, line[i].v1, VertexTypeDesc); + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, line[i].v2, VertexTypeDesc); + } } - // Don't delete wrapper interface - SaveInterfaceAddress(WrapperInterface, WrapperInterfaceBackup); - SaveInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2); - SaveInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3); - SaveInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7); - - // Clear ExecuteBuffers - for (auto& entry : ExecuteBufferList) + if (verticesCount) { - entry->ClearD3DDevice(); + // Pass the vertex data to the rendering pipeline + DrawPrimitive(D3DPT_LINELIST, VertexTypeDesc, vertices.data(), verticesCount, 0, 1); } - ReleaseAllStateBlocks(); + return D3D_OK; } -HRESULT m_IDirect3DDeviceX::CheckInterface(char *FunctionName, bool CheckD3DDevice) +HRESULT m_IDirect3DDeviceX::DrawExecuteTriangle(D3DTRIANGLE* triangle, WORD triangleCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) { - // Check ddrawParent device - if (!ddrawParent) + // Compute buffer size + DWORD BufferSize; { - LOG_LIMIT(100, FunctionName << " Error: no ddraw parent!"); - return DDERR_INVALIDOBJECT; + bool LastRecord = false; + DWORD Count = 0, MaxCount = 0; + for (DWORD i = 0; i < triangleCount; i++) + { + bool IsStartRecord = (triangle[i].wFlags & 0x1F) < D3DTRIFLAG_STARTFLAT(30); + if (IsStartRecord != LastRecord) + { + MaxCount = max(Count, MaxCount); + Count = (IsStartRecord) ? 3 : 4; + } + else + { + Count += (IsStartRecord) ? 3 : 1; + } + LastRecord = IsStartRecord; + } + BufferSize = sizeof(D3DTLVERTEX) * max(Count, MaxCount); } - // Check d3d9 device - if (CheckD3DDevice) + std::vector vertices; + vertices.resize(BufferSize); + BYTE* verticesData = vertices.data(); + DWORD verticesCount = 0; + + D3DPRIMITIVETYPE PrimitiveType = D3DPT_TRIANGLELIST; + + LONG LastCullMode = D3DTRIFLAG_START; + LONG CullRecordCount = 0; + + for (DWORD i = 0; i < triangleCount; i++) { - if (!ddrawParent->CheckD9Device(FunctionName) || !d3d9Device || !*d3d9Device) + // Flags for this triangle + WORD TriFlags = (triangle[i].wFlags & 0x1F); + + // START loads all three vertices + if (TriFlags < D3DTRIFLAG_STARTFLAT(30)) { - LOG_LIMIT(100, FunctionName << " Error: d3d9 device not setup!"); - return DDERR_INVALIDOBJECT; + if (triangle[i].v1 < vertexIndexCount && triangle[i].v2 < vertexIndexCount && triangle[i].v3 < vertexIndexCount) + { + PrimitiveType = D3DPT_TRIANGLELIST; + + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v1, VertexTypeDesc); + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v2, VertexTypeDesc); + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v3, VertexTypeDesc); + + LastCullMode = D3DTRIFLAG_START; + CullRecordCount = TriFlags; + } } - if (bSetDefaults) + // EVEN and ODD load just v3 with even or odd culling + else if (TriFlags == D3DTRIFLAG_EVEN || TriFlags == D3DTRIFLAG_ODD) { - SetDefaults(); + // Set primative type + if (LastCullMode == D3DTRIFLAG_START) + { + // Even cull modes indicates a triangle fan + if (TriFlags == D3DTRIFLAG_EVEN) + { + PrimitiveType = D3DPT_TRIANGLEFAN; + } + // Odd or mismatching cull modes indicates a triangle strip + else + { + PrimitiveType = D3DPT_TRIANGLESTRIP; + } + } + // The primative type doesn't mismatch past cull mode + else if ((TriFlags == LastCullMode && PrimitiveType == D3DPT_TRIANGLESTRIP) || + (TriFlags != LastCullMode && PrimitiveType == D3DPT_TRIANGLEFAN)) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: vertex cull mode mismatch detected!"); + } + + if (triangle[i].v3 < vertexIndexCount) + { + CopyConvertExecuteVertex(verticesData, verticesCount, vertexBuffer, triangle[i].v3, VertexTypeDesc); + } + + LastCullMode = TriFlags; + CullRecordCount--; + } + + // Check next records + bool AtEndOfList = !(i + 1U < triangleCount); + LONG NextRecord = (i + 1U < triangleCount) ? ((triangle[i + 1].wFlags & 0x1F) < 30 ? D3DTRIFLAG_START : D3DTRIFLAG_EVEN) : 0; + LONG NextNextRecord = (i + 2U < triangleCount) ? ((triangle[i + 2].wFlags & 0x1F) < 30 ? D3DTRIFLAG_START : D3DTRIFLAG_EVEN) : 0; + + // Draw primitaves once at the end of the list + if (verticesCount && // There primatives to draw + (AtEndOfList || // There are no more records, or + (NextRecord == D3DTRIFLAG_START && // Next record is a new START + (LastCullMode != D3DTRIFLAG_START || NextNextRecord != D3DTRIFLAG_START)))) + { + if (CullRecordCount > 0) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: drawing before all records have been culled: " << CullRecordCount); + } + + // Pass the vertex data to the rendering pipeline + DrawPrimitive(PrimitiveType, VertexTypeDesc, vertices.data(), verticesCount, 0, 1); + + // Reset variables for next list + verticesCount = 0; + verticesData = vertices.data(); } } return D3D_OK; } +void m_IDirect3DDeviceX::ClearViewport(m_IDirect3DViewportX* lpViewportX) +{ + if (lpViewportX == lpCurrentViewportX) + { + lpCurrentViewport = nullptr; + lpCurrentViewportX = nullptr; + } +} + void m_IDirect3DDeviceX::SetD3D(m_IDirect3DX* lpD3D) { if (!lpD3D) @@ -5619,9 +5558,6 @@ void m_IDirect3DDeviceX::ReleaseAllStateBlocks() void m_IDirect3DDeviceX::SetDefaults() { - // Reset flags - ConvertHomogeneous.IsTransformViewSet = false; - // Reset defaults flag bSetDefaults = false; @@ -5631,6 +5567,9 @@ void m_IDirect3DDeviceX::SetDefaults() // Reset state block IsRecordingState = false; + // Reset Homogeneous flag + ConvertHomogeneous.IsTransformViewSet = false; + // Clip status D3DClipStatus = {}; @@ -5683,157 +5622,155 @@ void m_IDirect3DDeviceX::SetDefaults() (*d3d9Device)->GetViewport(&DefaultViewport); } -inline void m_IDirect3DDeviceX::SetDrawStates(DWORD dwVertexTypeDesc, DWORD& dwFlags, DWORD DirectXVersion) +void m_IDirect3DDeviceX::SetDrawStates(DWORD dwVertexTypeDesc, DWORD& dwFlags, DWORD DirectXVersion) { + if (lpCurrentRenderTargetX) + { + lpCurrentRenderTargetX->PrepareRenderTarget(); + } + if (ddrawParent) + { + ddrawParent->ReSetRenderTarget(); + } + + // Handle texture wrapping + if (rsTextureWrappingChanged) + { + DWORD RenderState = (rsTextureWrappingU ? D3DWRAP_U : 0) | (rsTextureWrappingV ? D3DWRAP_V : 0); + SetD9RenderState(D3DRS_WRAP0, RenderState); + } + + // Handle anti-aliasing + if (rsAntiAliasChanged) + { + BOOL AntiAliasEnabled = (bool)((D3DANTIALIASMODE)rsAntiAlias == D3DANTIALIAS_SORTDEPENDENT || (D3DANTIALIASMODE)rsAntiAlias == D3DANTIALIAS_SORTINDEPENDENT); + SetD9RenderState(D3DRS_MULTISAMPLEANTIALIAS, AntiAliasEnabled); + rsAntiAliasChanged = false; + } + + // Handle dwFlags if (DirectXVersion < 7) { // dwFlags (D3DDP_WAIT) can be ignored safely - // Handle texture wrapping - if (rsTextureWrappingChanged) - { - DWORD RenderState = (rsTextureWrappingU ? D3DWRAP_U : 0) | (rsTextureWrappingV ? D3DWRAP_V : 0); - SetRenderState(D3DRENDERSTATE_WRAP0, RenderState); - } - - // Handle dwFlags if (dwFlags & D3DDP_DONOTCLIP) { - GetRenderState(D3DRENDERSTATE_CLIPPING, &DrawStates.rsClipping); - SetRenderState(D3DRENDERSTATE_CLIPPING, FALSE); + (*d3d9Device)->GetRenderState(D3DRS_CLIPPING, &DrawStates.rsClipping); + (*d3d9Device)->SetRenderState(D3DRS_CLIPPING, FALSE); } if ((dwFlags & D3DDP_DONOTLIGHT) || !(dwVertexTypeDesc & D3DFVF_NORMAL)) { - GetRenderState(D3DRENDERSTATE_LIGHTING, &DrawStates.rsLighting); - SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE); + (*d3d9Device)->GetRenderState(D3DRS_LIGHTING, &DrawStates.rsLighting); + (*d3d9Device)->SetRenderState(D3DRS_LIGHTING, FALSE); } if (dwFlags & D3DDP_DONOTUPDATEEXTENTS) { - GetRenderState(D3DRENDERSTATE_EXTENTS, &DrawStates.rsExtents); - SetRenderState(D3DRENDERSTATE_EXTENTS, FALSE); + // ToDo: fix Extents see SetRenderState() implementation + //GetRenderState(D3DRENDERSTATE_EXTENTS, &DrawStates.rsExtents); + //SetRenderState(D3DRENDERSTATE_EXTENTS, FALSE); } } - // Handle antialiasing - if (rsAntiAliasChanged) - { - BOOL AntiAliasEnabled = (bool)((D3DANTIALIASMODE)rsAntiAlias == D3DANTIALIAS_SORTDEPENDENT || (D3DANTIALIASMODE)rsAntiAlias == D3DANTIALIAS_SORTINDEPENDENT); - SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, AntiAliasEnabled); - rsAntiAliasChanged = false; - } - if (Config.Dd7to9) + if (Config.DdrawFixByteAlignment > 1) { - if (lpCurrentRenderTargetX) - { - lpCurrentRenderTargetX->PrepareRenderTarget(); - } - if (ddrawParent) - { - ddrawParent->ReSetRenderTarget(); - } - if (Config.DdrawFixByteAlignment > 1) + for (UINT x = 0; x < MaxTextureStages; x++) { - for (UINT x = 0; x < MaxTextureStages; x++) + if (CurrentTextureSurfaceX[x] && CurrentTextureSurfaceX[x]->GetWasBitAlignLocked()) { - if (CurrentTextureSurfaceX[x] && CurrentTextureSurfaceX[x]->GetWasBitAlignLocked()) - { - (*d3d9Device)->GetSamplerState(x, D3DSAMP_MINFILTER, &DrawStates.ssMinFilter[x]); - (*d3d9Device)->GetSamplerState(x, D3DSAMP_MAGFILTER, &DrawStates.ssMagFilter[x]); + (*d3d9Device)->GetSamplerState(x, D3DSAMP_MINFILTER, &DrawStates.ssMinFilter[x]); + (*d3d9Device)->GetSamplerState(x, D3DSAMP_MAGFILTER, &DrawStates.ssMagFilter[x]); - SetD9SamplerState(x, D3DSAMP_MINFILTER, Config.DdrawFixByteAlignment == 2 ? D3DTEXF_POINT : D3DTEXF_LINEAR); - SetD9SamplerState(x, D3DSAMP_MAGFILTER, Config.DdrawFixByteAlignment == 2 ? D3DTEXF_POINT : D3DTEXF_LINEAR); - } + (*d3d9Device)->SetSamplerState(x, D3DSAMP_MINFILTER, Config.DdrawFixByteAlignment == 2 ? D3DTEXF_POINT : D3DTEXF_LINEAR); + (*d3d9Device)->SetSamplerState(x, D3DSAMP_MAGFILTER, Config.DdrawFixByteAlignment == 2 ? D3DTEXF_POINT : D3DTEXF_LINEAR); } } + } + for (UINT x = 0; x < MaxTextureStages; x++) + { + if (ssMipFilter[x] != D3DTEXF_NONE && CurrentTextureSurfaceX[x] && !CurrentTextureSurfaceX[x]->IsMipMapGenerated()) + { + CurrentTextureSurfaceX[x]->GenerateMipMapLevels(); + } + } + if (rsColorKeyEnabled) + { + // Check for color key alpha texture for (UINT x = 0; x < MaxTextureStages; x++) { - if (ssMipFilter[x] != D3DTEXF_NONE && CurrentTextureSurfaceX[x] && !CurrentTextureSurfaceX[x]->IsMipMapGenerated()) + if (CurrentTextureSurfaceX[x] && CurrentTextureSurfaceX[x]->IsColorKeyTexture() && CurrentTextureSurfaceX[x]->GetD3d9DrawTexture()) { - CurrentTextureSurfaceX[x]->GenerateMipMapLevels(); + dwFlags |= D3DDP_DXW_ALPHACOLORKEY; + (*d3d9Device)->SetTexture(x, CurrentTextureSurfaceX[x]->GetD3d9DrawTexture()); } } - if (rsColorKeyEnabled) + if (dwFlags & D3DDP_DXW_ALPHACOLORKEY) { - // Check for color key alpha texture - for (UINT x = 0; x < MaxTextureStages; x++) - { - if (CurrentTextureSurfaceX[x] && CurrentTextureSurfaceX[x]->IsColorKeyTexture() && CurrentTextureSurfaceX[x]->GetD3d9DrawTexture()) - { - dwFlags |= D3DDP_DXW_ALPHACOLORKEY; - (*d3d9Device)->SetTexture(x, CurrentTextureSurfaceX[x]->GetD3d9DrawTexture()); - } - } - if (dwFlags & D3DDP_DXW_ALPHACOLORKEY) - { - (*d3d9Device)->GetRenderState(D3DRS_ALPHATESTENABLE, &DrawStates.rsAlphaTestEnable); - (*d3d9Device)->GetRenderState(D3DRS_ALPHAFUNC, &DrawStates.rsAlphaFunc); - (*d3d9Device)->GetRenderState(D3DRS_ALPHAREF, &DrawStates.rsAlphaRef); + (*d3d9Device)->GetRenderState(D3DRS_ALPHATESTENABLE, &DrawStates.rsAlphaTestEnable); + (*d3d9Device)->GetRenderState(D3DRS_ALPHAFUNC, &DrawStates.rsAlphaFunc); + (*d3d9Device)->GetRenderState(D3DRS_ALPHAREF, &DrawStates.rsAlphaRef); - SetD9RenderState(D3DRS_ALPHATESTENABLE, TRUE); - SetD9RenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); - SetD9RenderState(D3DRS_ALPHAREF, (DWORD)0x01); - } + (*d3d9Device)->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + (*d3d9Device)->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); + (*d3d9Device)->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x01); } - if ((dwFlags & D3DDP_DXW_COLORKEYENABLE) && ddrawParent) + } + if ((dwFlags & D3DDP_DXW_COLORKEYENABLE) && ddrawParent) + { + if (!colorkeyPixelShader || !*colorkeyPixelShader) { - if (!colorkeyPixelShader || !*colorkeyPixelShader) - { - colorkeyPixelShader = ddrawParent->GetColorKeyShader(); - } - if (colorkeyPixelShader && *colorkeyPixelShader) - { - (*d3d9Device)->SetPixelShader(*colorkeyPixelShader); - (*d3d9Device)->SetPixelShaderConstantF(0, DrawStates.lowColorKey, 1); - (*d3d9Device)->SetPixelShaderConstantF(1, DrawStates.highColorKey, 1); - } + colorkeyPixelShader = ddrawParent->GetColorKeyShader(); + } + if (colorkeyPixelShader && *colorkeyPixelShader) + { + (*d3d9Device)->SetPixelShader(*colorkeyPixelShader); + (*d3d9Device)->SetPixelShaderConstantF(0, DrawStates.lowColorKey, 1); + (*d3d9Device)->SetPixelShaderConstantF(1, DrawStates.highColorKey, 1); } } } -inline void m_IDirect3DDeviceX::RestoreDrawStates(DWORD dwVertexTypeDesc, DWORD dwFlags, DWORD DirectXVersion) +void m_IDirect3DDeviceX::RestoreDrawStates(DWORD dwVertexTypeDesc, DWORD dwFlags, DWORD DirectXVersion) { + // Handle dwFlags if (DirectXVersion < 7) { - // Handle dwFlags if (dwFlags & D3DDP_DONOTCLIP) { - SetRenderState(D3DRENDERSTATE_CLIPPING, DrawStates.rsClipping); + (*d3d9Device)->SetRenderState(D3DRS_CLIPPING, DrawStates.rsClipping); } if ((dwFlags & D3DDP_DONOTLIGHT) || !(dwVertexTypeDesc & D3DFVF_NORMAL)) { - SetRenderState(D3DRENDERSTATE_LIGHTING, DrawStates.rsLighting); + (*d3d9Device)->SetRenderState(D3DRS_LIGHTING, DrawStates.rsLighting); } if (dwFlags & D3DDP_DONOTUPDATEEXTENTS) { - SetRenderState(D3DRENDERSTATE_EXTENTS, DrawStates.rsExtents); + // ToDo: fix Extents see SetRenderState() implementation + //SetRenderState(D3DRENDERSTATE_EXTENTS, DrawStates.rsExtents); } } - if (Config.Dd7to9) + if (Config.DdrawFixByteAlignment > 1) { - if (Config.DdrawFixByteAlignment > 1) + for (UINT x = 0; x < MaxTextureStages; x++) { - for (UINT x = 0; x < MaxTextureStages; x++) + if (CurrentTextureSurfaceX[x] && CurrentTextureSurfaceX[x]->GetWasBitAlignLocked()) { - if (CurrentTextureSurfaceX[x] && CurrentTextureSurfaceX[x]->GetWasBitAlignLocked()) - { - SetD9SamplerState(x, D3DSAMP_MINFILTER, DrawStates.ssMinFilter[x]); - SetD9SamplerState(x, D3DSAMP_MAGFILTER, DrawStates.ssMagFilter[x]); - } + (*d3d9Device)->SetSamplerState(x, D3DSAMP_MINFILTER, DrawStates.ssMinFilter[x]); + (*d3d9Device)->SetSamplerState(x, D3DSAMP_MAGFILTER, DrawStates.ssMagFilter[x]); } } - if (dwFlags & D3DDP_DXW_ALPHACOLORKEY) - { - SetD9RenderState(D3DRS_ALPHATESTENABLE, DrawStates.rsAlphaTestEnable); - SetD9RenderState(D3DRS_ALPHAFUNC, DrawStates.rsAlphaFunc); - SetD9RenderState(D3DRS_ALPHAREF, DrawStates.rsAlphaRef); - } - if (dwFlags & D3DDP_DXW_COLORKEYENABLE) - { - (*d3d9Device)->SetPixelShader(nullptr); - } + } + if (dwFlags & D3DDP_DXW_ALPHACOLORKEY) + { + (*d3d9Device)->SetRenderState(D3DRS_ALPHATESTENABLE, DrawStates.rsAlphaTestEnable); + (*d3d9Device)->SetRenderState(D3DRS_ALPHAFUNC, DrawStates.rsAlphaFunc); + (*d3d9Device)->SetRenderState(D3DRS_ALPHAREF, DrawStates.rsAlphaRef); + } + if (dwFlags & D3DDP_DXW_COLORKEYENABLE) + { + (*d3d9Device)->SetPixelShader(nullptr); } } -inline void m_IDirect3DDeviceX::ScaleVertices(DWORD dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount) +void m_IDirect3DDeviceX::ScaleVertices(DWORD dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount) { if (dwVertexTypeDesc == 3) { @@ -5851,7 +5788,7 @@ inline void m_IDirect3DDeviceX::ScaleVertices(DWORD dwVertexTypeDesc, LPVOID& lp } } -inline void m_IDirect3DDeviceX::UpdateVertices(DWORD& dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount) +void m_IDirect3DDeviceX::UpdateVertices(DWORD& dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount) { if (dwVertexTypeDesc == D3DFVF_LVERTEX) { diff --git a/ddraw/IDirect3DDeviceX.h b/ddraw/IDirect3DDeviceX.h index fbb2c8ef..67ef05e2 100644 --- a/ddraw/IDirect3DDeviceX.h +++ b/ddraw/IDirect3DDeviceX.h @@ -1,21 +1,5 @@ #pragma once -#include -#include -#include "External\DirectXMath\Inc\DirectXMath.h" - -struct CONVERTHOMOGENEOUS -{ - bool IsTransformViewSet = false; // Remembers if game sets the view matrix - D3DMATRIX ToWorld_ProjectionMatrix; // Store the projection matrix used to transform the geometry on the gpu - D3DMATRIX ToWorld_ViewMatrix; // Store the view matrix used to transform the geometry on the gpu - D3DMATRIX ToWorld_ViewMatrixOriginal; // Store the original view matrix, so we can restore it - DirectX::XMMATRIX ToWorld_ViewMatrixInverse; // Store the inverse view matrix to transform the geometry on the cpu - std::vector ToWorld_IntermediateGeometry; // Intermediate buffer for the geometry conversion - float ToWorld_GameCameraYaw = 0.0f; - float ToWorld_GameCameraPitch = 0.0f; -}; - class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject { private: @@ -27,16 +11,15 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject ULONG RefCount7 = 0; REFCLSID ClassID = IID_IUnknown; - // Store d3d device version wrappers + // Store version wrappers m_IDirect3DDevice* WrapperInterface = nullptr; m_IDirect3DDevice2* WrapperInterface2 = nullptr; m_IDirect3DDevice3* WrapperInterface3 = nullptr; m_IDirect3DDevice7* WrapperInterface7 = nullptr; - // Convert Device + // Convert to Direct3D9 m_IDirectDrawX *ddrawParent = nullptr; m_IDirect3DX* D3DInterface = nullptr; - m_IDirectDrawSurfaceX* lpCurrentRenderTargetX = nullptr; LPDIRECT3DDEVICE9 *d3d9Device = nullptr; LPDIRECT3DPIXELSHADER9* colorkeyPixelShader = nullptr; LPDIRECT3DVIEWPORT3 lpCurrentViewport = nullptr; @@ -74,15 +57,6 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject std::unordered_map Matrix; } DeviceStates; - inline HRESULT SetD9RenderState(D3DRENDERSTATETYPE dwRenderStateType, DWORD dwRenderState); - inline HRESULT SetD9TextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); - inline HRESULT SetD9SamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); - inline HRESULT SetD9Light(DWORD Index, CONST D3DLIGHT9* pLight); - inline HRESULT LightD9Enable(DWORD Index, BOOL bEnable); - inline HRESULT SetD9Viewport(CONST D3DVIEWPORT9* pViewport); - inline HRESULT SetD9Material(CONST D3DMATERIAL9* pMaterial); - inline HRESULT SetD9Transform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix); - struct { DWORD rsClipping = 0; DWORD rsLighting = 0; @@ -130,34 +104,19 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject // Default settings D3DVIEWPORT9 DefaultViewport = {}; - // SetTexture array + // Render target LPDIRECTDRAWSURFACE7 CurrentRenderTarget = nullptr; + m_IDirectDrawSurfaceX* lpCurrentRenderTargetX = nullptr; + + // SetTexture array m_IDirectDrawSurfaceX* CurrentTextureSurfaceX[MaxTextureStages] = {}; LPDIRECTDRAWSURFACE7 AttachedTexture[MaxTextureStages] = {}; // Texture handle map std::unordered_map TextureHandleMap; - inline m_IDirect3DTextureX* GetTexture(D3DTEXTUREHANDLE TextureHandle) - { - m_IDirect3DTextureX* pTextureX = TextureHandleMap[TextureHandle]; - if (!pTextureX) - { - TextureHandleMap.erase(TextureHandle); - } - return pTextureX; - } // Material handle map std::unordered_map MaterialHandleMap; - inline m_IDirect3DMaterialX* GetMaterial(D3DMATERIALHANDLE MaterialHandle) - { - m_IDirect3DMaterialX* pMaterialX = MaterialHandleMap[MaterialHandle]; - if (!pMaterialX) - { - MaterialHandleMap.erase(MaterialHandle); - } - return pMaterialX; - } // Matrix map struct D3DMATRIXSTRUCT { @@ -165,15 +124,6 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject D3DMATRIX m = {}; }; std::unordered_map MatrixMap; - inline D3DMATRIX* GetMatrix(D3DMATRIXHANDLE MatrixHandle) - { - if (!MatrixMap[MatrixHandle].IsValidMatrix) - { - MatrixMap.erase(MatrixHandle); - return nullptr; - } - return &MatrixMap[MatrixHandle].m; - } // Light index map std::unordered_map LightIndexMap; @@ -190,19 +140,42 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject // Viewport array std::vector AttachedViewports; - inline bool IsViewportAttached(LPDIRECT3DVIEWPORT3 ViewportX) - { - auto it = std::find_if(AttachedViewports.begin(), AttachedViewports.end(), - [=](auto pViewport) -> bool { return pViewport == ViewportX; }); + // Helper functions + HRESULT CheckInterface(char* FunctionName, bool CheckD3DDevice); - if (it != std::end(AttachedViewports)) + // Execute buffer function + void CopyConvertExecuteVertex(BYTE*& DestVertex, DWORD& DestVertexCount, BYTE* SrcVertex, DWORD SrcIndex, DWORD VertexTypeDesc); + HRESULT DrawExecutePoint(D3DPOINT* point, WORD pointCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc); + HRESULT DrawExecuteLine(D3DLINE* line, WORD lineCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc); + HRESULT DrawExecuteTriangle(D3DTRIANGLE* triangle, WORD triangleCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc); + + HRESULT SetD9RenderState(D3DRENDERSTATETYPE dwRenderStateType, DWORD dwRenderState); + HRESULT SetD9TextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); + HRESULT SetD9SamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); + HRESULT SetD9Light(DWORD Index, CONST D3DLIGHT9* pLight); + HRESULT LightD9Enable(DWORD Index, BOOL bEnable); + HRESULT SetD9Viewport(CONST D3DVIEWPORT9* pViewport); + HRESULT SetD9Material(CONST D3DMATERIAL9* pMaterial); + HRESULT SetD9Transform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix); + + HRESULT RestoreStates(); + void SetDefaults(); + void SetDrawStates(DWORD dwVertexTypeDesc, DWORD& dwFlags, DWORD DirectXVersion); + void RestoreDrawStates(DWORD dwVertexTypeDesc, DWORD dwFlags, DWORD DirectXVersion); + void ScaleVertices(DWORD dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount); + void UpdateVertices(DWORD& dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount); + + D3DMATRIX* GetMatrix(D3DMATRIXHANDLE MatrixHandle) + { + if (!MatrixMap[MatrixHandle].IsValidMatrix) { - return true; + MatrixMap.erase(MatrixHandle); + return nullptr; } - return false; + return &MatrixMap[MatrixHandle].m; } - inline bool DeleteAttachedViewport(LPDIRECT3DVIEWPORT3 ViewportX) + bool DeleteAttachedViewport(LPDIRECT3DVIEWPORT3 ViewportX) { auto it = std::find_if(AttachedViewports.begin(), AttachedViewports.end(), [=](auto pViewport) -> bool { return pViewport == ViewportX; }); @@ -215,6 +188,26 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject return false; } + m_IDirect3DTextureX* GetTexture(D3DTEXTUREHANDLE TextureHandle) + { + m_IDirect3DTextureX* pTextureX = TextureHandleMap[TextureHandle]; + if (!pTextureX) + { + TextureHandleMap.erase(TextureHandle); + } + return pTextureX; + } + + m_IDirect3DMaterialX* GetMaterial(D3DMATERIALHANDLE MaterialHandle) + { + m_IDirect3DMaterialX* pMaterialX = MaterialHandleMap[MaterialHandle]; + if (!pMaterialX) + { + MaterialHandleMap.erase(MaterialHandle); + } + return pMaterialX; + } + // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { @@ -235,23 +228,6 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject inline IDirect3DDevice3 *GetProxyInterfaceV3() { return (IDirect3DDevice3 *)ProxyInterface; } inline IDirect3DDevice7 *GetProxyInterfaceV7() { return ProxyInterface; } - // Check interfaces - HRESULT CheckInterface(char *FunctionName, bool CheckD3DDevice); - - // Execute buffer function - inline void CopyConvertExecuteVertex(BYTE*& DestVertex, DWORD& DestVertexCount, BYTE* SrcVertex, DWORD SrcIndex, DWORD VertexTypeDesc); - HRESULT DrawExecutePoint(D3DPOINT* point, WORD pointCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc); - HRESULT DrawExecuteLine(D3DLINE* line, WORD lineCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc); - HRESULT DrawExecuteTriangle(D3DTRIANGLE* triangle, WORD triangleCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc); - - // Helper functions - HRESULT RestoreStates(); - void SetDefaults(); - void SetDrawStates(DWORD dwVertexTypeDesc, DWORD& dwFlags, DWORD DirectXVersion); - void RestoreDrawStates(DWORD dwVertexTypeDesc, DWORD dwFlags, DWORD DirectXVersion); - void ScaleVertices(DWORD dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount); - void UpdateVertices(DWORD& dwVertexTypeDesc, LPVOID& lpVertices, DWORD dwVertexCount); - // Interface initialization functions void InitInterface(DWORD DirectXVersion); void ReleaseInterface(); @@ -259,7 +235,7 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject public: m_IDirect3DDeviceX(IDirect3DDevice7 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal), ClassID(IID_IDirect3DHALDevice) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -325,7 +301,7 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject STDMETHOD(SetTextureStageState)(THIS_ DWORD, D3DTEXTURESTAGESTATETYPE, DWORD); STDMETHOD(GetCaps)(THIS_ LPD3DDEVICEDESC, LPD3DDEVICEDESC); STDMETHOD(GetCaps)(THIS_ LPD3DDEVICEDESC7); - STDMETHOD(GetStats)(THIS_ LPD3DSTATS, DWORD); + STDMETHOD(GetStats)(THIS_ LPD3DSTATS); STDMETHOD(AddViewport)(THIS_ LPDIRECT3DVIEWPORT3); STDMETHOD(DeleteViewport)(THIS_ LPDIRECT3DVIEWPORT3); STDMETHOD(NextViewport)(THIS_ LPDIRECT3DVIEWPORT3, LPDIRECT3DVIEWPORT3*, DWORD, DWORD); @@ -381,17 +357,31 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject ULONG AddRef(DWORD DirectXVersion); ULONG Release(DWORD DirectXVersion); bool IsDeviceInScene() const { return IsInScene; } - inline void SetParent3DSurface(m_IDirectDrawSurfaceX* lpSurfaceX, DWORD DxVersion) { parent3DSurface = { lpSurfaceX, DxVersion }; } + void SetParent3DSurface(m_IDirectDrawSurfaceX* lpSurfaceX, DWORD DxVersion) { parent3DSurface = { lpSurfaceX, DxVersion }; } // ExecuteBuffer void AddExecuteBuffer(m_IDirect3DExecuteBuffer* lpExecuteBuffer); void ClearExecuteBuffer(m_IDirect3DExecuteBuffer* lpExecuteBuffer); // Viewport functions - inline void GetDefaultViewport(D3DVIEWPORT9& Viewport) const { Viewport = DefaultViewport; } - inline bool CheckIfViewportSet(m_IDirect3DViewportX* pViewport) { return (pViewport == lpCurrentViewportX); } + void GetDefaultViewport(D3DVIEWPORT9& Viewport) const { Viewport = DefaultViewport; } + bool CheckIfViewportSet(m_IDirect3DViewportX* pViewport) { return (pViewport == lpCurrentViewportX); } void ClearViewport(m_IDirect3DViewportX* lpViewportX); + bool IsViewportAttached(LPDIRECT3DVIEWPORT3 ViewportX) + { + if (!ViewportX) return false; + + auto it = std::find_if(AttachedViewports.begin(), AttachedViewports.end(), + [=](auto pViewport) -> bool { return pViewport == ViewportX; }); + + if (it != std::end(AttachedViewports)) + { + return true; + } + return false; + } + // Texture handle function void ClearTextureHandle(D3DTEXTUREHANDLE tHandle); HRESULT SetTextureHandle(D3DTEXTUREHANDLE& tHandle, m_IDirect3DTextureX* pTextureX); @@ -399,7 +389,7 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject // Material handle function void ClearMaterialHandle(D3DMATERIALHANDLE mHandle); HRESULT SetMaterialHandle(D3DMATERIALHANDLE& mHandle, m_IDirect3DMaterialX* lpMaterial); - inline bool CheckIfMaterialSet(D3DMATERIALHANDLE mHandle) const { return (mHandle == lsMaterialHandle); } + bool CheckIfMaterialSet(D3DMATERIALHANDLE mHandle) const { return (mHandle == lsMaterialHandle); } // Light index function void ClearLight(m_IDirect3DLight* lpLight); diff --git a/ddraw/IDirect3DExecuteBuffer.cpp b/ddraw/IDirect3DExecuteBuffer.cpp index e31d4c2c..bd238630 100644 --- a/ddraw/IDirect3DExecuteBuffer.cpp +++ b/ddraw/IDirect3DExecuteBuffer.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,47 +16,13 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirect3DExecuteBuffer* WrapperInterfaceBackup = nullptr; } -inline static void SaveInterfaceAddress(m_IDirect3DExecuteBuffer* Interface, m_IDirect3DExecuteBuffer*& InterfaceBackup) -{ - if (Interface) - { - Interface->SetProxy(nullptr, nullptr, nullptr); - if (InterfaceBackup) - { - InterfaceBackup->DeleteMe(); - InterfaceBackup = nullptr; - } - InterfaceBackup = Interface; - } -} - -m_IDirect3DExecuteBuffer* CreateDirect3DExecuteBuffer(IDirect3DExecuteBuffer* aOriginal, m_IDirect3DDeviceX* NewD3DDInterface, LPD3DEXECUTEBUFFERDESC lpDesc) -{ - m_IDirect3DExecuteBuffer* Interface = nullptr; - if (WrapperInterfaceBackup) - { - Interface = WrapperInterfaceBackup; - WrapperInterfaceBackup = nullptr; - Interface->SetProxy(aOriginal, NewD3DDInterface, lpDesc); - } - else - { - if (aOriginal) - { - Interface = new m_IDirect3DExecuteBuffer(aOriginal); - } - else - { - Interface = new m_IDirect3DExecuteBuffer(NewD3DDInterface, lpDesc); - } - } - return Interface; -} +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirect3DExecuteBuffer::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -109,7 +75,7 @@ ULONG m_IDirect3DExecuteBuffer::AddRef() return 0; } - if (!ProxyInterface) + if (Config.Dd7to9) { return InterlockedIncrement(&RefCount); } @@ -126,17 +92,20 @@ ULONG m_IDirect3DExecuteBuffer::Release() return 0; } - LONG ref; - - if (!ProxyInterface) - { - ref = InterlockedDecrement(&RefCount); - } - else + if (Config.Dd7to9) { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + SaveInterfaceAddress(this, WrapperInterfaceBackup); + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { SaveInterfaceAddress(this, WrapperInterfaceBackup); @@ -145,6 +114,10 @@ ULONG m_IDirect3DExecuteBuffer::Release() return ref; } +// ****************************** +// IDirect3DExecuteBuffer functions +// ****************************** + HRESULT m_IDirect3DExecuteBuffer::Initialize(LPDIRECT3DDEVICE lpDirect3DDevice, LPD3DEXECUTEBUFFERDESC lpDesc) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -154,7 +127,7 @@ HRESULT m_IDirect3DExecuteBuffer::Initialize(LPDIRECT3DDEVICE lpDirect3DDevice, return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // The method returns DDERR_ALREADYINITIALIZED because the Direct3DExecuteBuffer object is initialized when it is created. return DDERR_ALREADYINITIALIZED; @@ -177,7 +150,7 @@ HRESULT m_IDirect3DExecuteBuffer::Lock(LPD3DEXECUTEBUFFERDESC lpDesc) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpDesc) { @@ -221,7 +194,7 @@ HRESULT m_IDirect3DExecuteBuffer::Unlock() return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // Check if the buffer is not locked if (!IsLocked) @@ -249,7 +222,7 @@ HRESULT m_IDirect3DExecuteBuffer::SetExecuteData(LPD3DEXECUTEDATA lpExecuteData) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpExecuteData) { @@ -312,7 +285,7 @@ HRESULT m_IDirect3DExecuteBuffer::GetExecuteData(LPD3DEXECUTEDATA lpExecuteData) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpExecuteData) { @@ -341,6 +314,126 @@ HRESULT m_IDirect3DExecuteBuffer::GetExecuteData(LPD3DEXECUTEDATA lpExecuteData) return ProxyInterface->GetExecuteData(lpExecuteData); } +HRESULT m_IDirect3DExecuteBuffer::Validate(LPDWORD lpdwOffset, LPD3DVALIDATECALLBACK lpFunc, LPVOID lpUserArg, DWORD dwReserved) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (!ProxyInterface && !D3DDeviceInterface) + { + return DDERR_INVALIDOBJECT; + } + + if (Config.Dd7to9) + { + if (!lpdwOffset && !lpFunc) + { + return DDERR_INVALIDPARAMS; + } + + ValidateInstructionData(&ExecuteData, lpdwOffset, lpFunc, lpUserArg); + + return D3D_OK; + } + + return ProxyInterface->Validate(lpdwOffset, lpFunc, lpUserArg, dwReserved); +} + +HRESULT m_IDirect3DExecuteBuffer::Optimize(DWORD dwDummy) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (!ProxyInterface && !D3DDeviceInterface) + { + return DDERR_INVALIDOBJECT; + } + + if (Config.Dd7to9) + { + // The method is not currently supported. + return D3D_OK; + } + + return ProxyInterface->Optimize(dwDummy); +} + +// ****************************** +// Helper functions +// ****************************** + +void m_IDirect3DExecuteBuffer::InitInterface(LPD3DEXECUTEBUFFERDESC lpDesc) +{ + ScopedDDCriticalSection ThreadLockDD; + + if (D3DDeviceInterface) + { + D3DDeviceInterface->AddExecuteBuffer(this); + } + + IsLocked = false; + IsDataValidated = false; + ExecuteData = {}; + ExecuteData.dwSize = sizeof(D3DEXECUTEDATA); + Desc = {}; + Desc.dwSize = sizeof(D3DEXECUTEBUFFERDESC); + MemoryData.clear(); + + if (lpDesc) + { + Desc = *lpDesc; + Desc.dwFlags &= (D3DDEB_BUFSIZE | D3DDEB_CAPS | D3DDEB_LPDATA); + if (!(Desc.dwFlags & D3DDEB_CAPS)) + { + Desc.dwFlags |= D3DDEB_CAPS; + Desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY; + } + Desc.dwCaps &= D3DDEBCAPS_MEM; + if (!(Desc.dwFlags & D3DDEB_LPDATA) || !Desc.lpData) + { + Desc.dwFlags |= D3DDEB_LPDATA; + MemoryData.resize(Desc.dwBufferSize, 0); + Desc.lpData = MemoryData.data(); + } + } +} + +void m_IDirect3DExecuteBuffer::ReleaseInterface() +{ + if (Config.Exiting) + { + return; + } + + ScopedDDCriticalSection ThreadLockDD; + + if (D3DDeviceInterface) + { + D3DDeviceInterface->ClearExecuteBuffer(this); + } +} + +m_IDirect3DExecuteBuffer* m_IDirect3DExecuteBuffer::CreateDirect3DExecuteBuffer(IDirect3DExecuteBuffer* aOriginal, m_IDirect3DDeviceX* NewD3DDInterface, LPD3DEXECUTEBUFFERDESC lpDesc) +{ + m_IDirect3DExecuteBuffer* Interface = nullptr; + if (WrapperInterfaceBackup) + { + Interface = WrapperInterfaceBackup; + WrapperInterfaceBackup = nullptr; + Interface->SetProxy(aOriginal, NewD3DDInterface, lpDesc); + } + else + { + if (aOriginal) + { + Interface = new m_IDirect3DExecuteBuffer(aOriginal); + } + else + { + Interface = new m_IDirect3DExecuteBuffer(NewD3DDInterface, lpDesc); + } + } + return Interface; +} + HRESULT m_IDirect3DExecuteBuffer::GetBuffer(LPVOID* lplpData, D3DEXECUTEDATA& CurrentExecuteData, LPD3DSTATUS* lplpStatus) { if (!lplpData || !lplpStatus) @@ -551,96 +644,3 @@ HRESULT m_IDirect3DExecuteBuffer::ValidateInstructionData(LPD3DEXECUTEDATA lpExe return DD_OK; } - -HRESULT m_IDirect3DExecuteBuffer::Validate(LPDWORD lpdwOffset, LPD3DVALIDATECALLBACK lpFunc, LPVOID lpUserArg, DWORD dwReserved) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (!ProxyInterface && !D3DDeviceInterface) - { - return DDERR_INVALIDOBJECT; - } - - if (!ProxyInterface) - { - if (!lpdwOffset && !lpFunc) - { - return DDERR_INVALIDPARAMS; - } - - ValidateInstructionData(&ExecuteData, lpdwOffset, lpFunc, lpUserArg); - - return D3D_OK; - } - - return ProxyInterface->Validate(lpdwOffset, lpFunc, lpUserArg, dwReserved); -} - -HRESULT m_IDirect3DExecuteBuffer::Optimize(DWORD dwDummy) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - if (!ProxyInterface && !D3DDeviceInterface) - { - return DDERR_INVALIDOBJECT; - } - - if (!ProxyInterface) - { - // The method is not currently supported. - return D3D_OK; - } - - return ProxyInterface->Optimize(dwDummy); -} - -/************************/ -/*** Helper functions ***/ -/************************/ - -void m_IDirect3DExecuteBuffer::InitInterface(LPD3DEXECUTEBUFFERDESC lpDesc) -{ - if (D3DDeviceInterface) - { - D3DDeviceInterface->AddExecuteBuffer(this); - } - - IsLocked = false; - IsDataValidated = false; - ExecuteData = {}; - ExecuteData.dwSize = sizeof(D3DEXECUTEDATA); - Desc = {}; - Desc.dwSize = sizeof(D3DEXECUTEBUFFERDESC); - MemoryData.clear(); - - if (lpDesc) - { - Desc = *lpDesc; - Desc.dwFlags &= (D3DDEB_BUFSIZE | D3DDEB_CAPS | D3DDEB_LPDATA); - if (!(Desc.dwFlags & D3DDEB_CAPS)) - { - Desc.dwFlags |= D3DDEB_CAPS; - Desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY; - } - Desc.dwCaps &= D3DDEBCAPS_MEM; - if (!(Desc.dwFlags & D3DDEB_LPDATA) || !Desc.lpData) - { - Desc.dwFlags |= D3DDEB_LPDATA; - MemoryData.resize(Desc.dwBufferSize, 0); - Desc.lpData = MemoryData.data(); - } - } -} - -void m_IDirect3DExecuteBuffer::ReleaseInterface() -{ - if (Config.Exiting) - { - return; - } - - if (D3DDeviceInterface) - { - D3DDeviceInterface->ClearExecuteBuffer(this); - } -} diff --git a/ddraw/IDirect3DExecuteBuffer.h b/ddraw/IDirect3DExecuteBuffer.h index 0a3aedc0..7c907d81 100644 --- a/ddraw/IDirect3DExecuteBuffer.h +++ b/ddraw/IDirect3DExecuteBuffer.h @@ -1,7 +1,5 @@ #pragma once -m_IDirect3DExecuteBuffer* CreateDirect3DExecuteBuffer(IDirect3DExecuteBuffer* aOriginal, m_IDirect3DDeviceX* NewD3DDInterface, LPD3DEXECUTEBUFFERDESC lpDesc); - class m_IDirect3DExecuteBuffer : public IDirect3DExecuteBuffer, public AddressLookupTableDdrawObject { private: @@ -89,6 +87,7 @@ class m_IDirect3DExecuteBuffer : public IDirect3DExecuteBuffer, public AddressLo STDMETHOD(Optimize)(THIS_ DWORD); // Helper functions - inline void ClearD3DDevice() { D3DDeviceInterface = nullptr; } + void ClearD3DDevice() { D3DDeviceInterface = nullptr; } HRESULT GetBuffer(LPVOID* lplpData, D3DEXECUTEDATA& CurrentExecuteData, LPD3DSTATUS* lplpStatus); + static m_IDirect3DExecuteBuffer* CreateDirect3DExecuteBuffer(IDirect3DExecuteBuffer* aOriginal, m_IDirect3DDeviceX* NewD3DDInterface, LPD3DEXECUTEBUFFERDESC lpDesc); }; diff --git a/ddraw/IDirect3DLight.cpp b/ddraw/IDirect3DLight.cpp index 91c4ef36..48cd3b28 100644 --- a/ddraw/IDirect3DLight.cpp +++ b/ddraw/IDirect3DLight.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,47 +16,13 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirect3DLight* WrapperInterfaceBackup = nullptr; } -inline static void SaveInterfaceAddress(m_IDirect3DLight* Interface, m_IDirect3DLight*& InterfaceBackup) -{ - if (Interface) - { - Interface->SetProxy(nullptr, nullptr); - if (InterfaceBackup) - { - InterfaceBackup->DeleteMe(); - InterfaceBackup = nullptr; - } - InterfaceBackup = Interface; - } -} - -m_IDirect3DLight* CreateDirect3DLight(IDirect3DLight* aOriginal, m_IDirect3DX* NewD3DInterface) -{ - m_IDirect3DLight* Interface = nullptr; - if (WrapperInterfaceBackup) - { - Interface = WrapperInterfaceBackup; - WrapperInterfaceBackup = nullptr; - Interface->SetProxy(aOriginal, NewD3DInterface); - } - else - { - if (aOriginal) - { - Interface = new m_IDirect3DLight(aOriginal); - } - else - { - Interface = new m_IDirect3DLight(NewD3DInterface); - } - } - return Interface; -} +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirect3DLight::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -109,7 +75,7 @@ ULONG m_IDirect3DLight::AddRef() return 0; } - if (!ProxyInterface) + if (Config.Dd7to9) { return InterlockedIncrement(&RefCount); } @@ -126,17 +92,20 @@ ULONG m_IDirect3DLight::Release() return 0; } - LONG ref; - - if (!ProxyInterface) - { - ref = InterlockedDecrement(&RefCount); - } - else + if (Config.Dd7to9) { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + SaveInterfaceAddress(this, WrapperInterfaceBackup); + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { SaveInterfaceAddress(this, WrapperInterfaceBackup); @@ -145,6 +114,10 @@ ULONG m_IDirect3DLight::Release() return ref; } +// ****************************** +// IDirect3DLight functions +// ****************************** + HRESULT m_IDirect3DLight::Initialize(LPDIRECT3D lpDirect3D) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -154,7 +127,7 @@ HRESULT m_IDirect3DLight::Initialize(LPDIRECT3D lpDirect3D) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // The method returns DDERR_ALREADYINITIALIZED because the Direct3DLight object is initialized when it is created. return DDERR_ALREADYINITIALIZED; @@ -177,7 +150,7 @@ HRESULT m_IDirect3DLight::SetLight(LPD3DLIGHT lpLight) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // Although this method's declaration specifies the lpLight parameter as being the address of a D3DLIGHT structure, that structure is not normally used. // Rather, the D3DLIGHT2 structure is recommended to achieve the best lighting effects. @@ -188,15 +161,9 @@ HRESULT m_IDirect3DLight::SetLight(LPD3DLIGHT lpLight) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - - // If current viewport is inuse then deactivate the light + // If current light is in use then update device BOOL Enable = FALSE; - if (SUCCEEDED((*D3DDeviceInterface)->GetLightEnable(this, &Enable)) && Enable) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && SUCCEEDED((*D3DDeviceInterface)->GetLightEnable(this, &Enable)) && Enable) { D3DLIGHT2 Light2 = {}; memcpy(&Light2, lpLight, lpLight->dwSize); @@ -230,7 +197,7 @@ HRESULT m_IDirect3DLight::GetLight(LPD3DLIGHT lpLight) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // Although this method's declaration specifies the lpLight parameter as being the address of a D3DLIGHT structure, that structure is not normally used. // Rather, the D3DLIGHT2 structure is recommended to achieve the best lighting effects. @@ -241,12 +208,6 @@ HRESULT m_IDirect3DLight::GetLight(LPD3DLIGHT lpLight) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - if (!LightSet) { LOG_LIMIT(100, __FUNCTION__ << " Warning: light has not yet been set."); @@ -269,7 +230,7 @@ HRESULT m_IDirect3DLight::GetLight(LPD3DLIGHT lpLight) // Check for active BOOL Enable = FALSE; - if (SUCCEEDED((*D3DDeviceInterface)->GetLightEnable(this, &Enable)) && Enable) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && SUCCEEDED((*D3DDeviceInterface)->GetLightEnable(this, &Enable)) && Enable) { ((LPD3DLIGHT2)lpLight)->dwFlags |= D3DLIGHT_ACTIVE; } @@ -285,9 +246,43 @@ HRESULT m_IDirect3DLight::GetLight(LPD3DLIGHT lpLight) return ProxyInterface->GetLight(lpLight); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** + +void m_IDirect3DLight::InitInterface() +{ + ScopedDDCriticalSection ThreadLockDD; + + if (D3DInterface) + { + D3DInterface->AddLight(this); + } + + LightSet = false; +} + +void m_IDirect3DLight::ReleaseInterface() +{ + if (Config.Exiting) + { + return; + } + + ScopedDDCriticalSection ThreadLockDD; + + if (D3DInterface) + { + D3DInterface->ClearLight(this); + } + + if (D3DDeviceInterface && *D3DDeviceInterface) + { + (*D3DDeviceInterface)->ClearLight(this); + } + + ClearD3D(); +} HRESULT m_IDirect3DLight::CheckInterface(char* FunctionName) { @@ -304,7 +299,6 @@ HRESULT m_IDirect3DLight::CheckInterface(char* FunctionName) D3DDeviceInterface = D3DInterface->GetD3DDevice(); if (!D3DDeviceInterface || !*D3DDeviceInterface) { - LOG_LIMIT(100, FunctionName << " Error: could not get the D3DDevice!"); return DDERR_INVALIDOBJECT; } } @@ -312,32 +306,36 @@ HRESULT m_IDirect3DLight::CheckInterface(char* FunctionName) return D3D_OK; } -void m_IDirect3DLight::InitInterface() +m_IDirect3DDeviceX* m_IDirect3DLight::GetD3DDevice() { - if (D3DInterface) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__))) { - D3DInterface->AddLight(this); + return nullptr; } - LightSet = false; + return *D3DDeviceInterface; } -void m_IDirect3DLight::ReleaseInterface() +m_IDirect3DLight* m_IDirect3DLight::CreateDirect3DLight(IDirect3DLight* aOriginal, m_IDirect3DX* NewD3DInterface) { - if (Config.Exiting) - { - return; - } - - if (D3DInterface) + m_IDirect3DLight* Interface = nullptr; + if (WrapperInterfaceBackup) { - D3DInterface->ClearLight(this); + Interface = WrapperInterfaceBackup; + WrapperInterfaceBackup = nullptr; + Interface->SetProxy(aOriginal, NewD3DInterface); } - - if (D3DDeviceInterface && *D3DDeviceInterface) + else { - (*D3DDeviceInterface)->ClearLight(this); + if (aOriginal) + { + Interface = new m_IDirect3DLight(aOriginal); + } + else + { + Interface = new m_IDirect3DLight(NewD3DInterface); + } } - - ClearD3D(); + return Interface; } diff --git a/ddraw/IDirect3DLight.h b/ddraw/IDirect3DLight.h index b70c37dd..17fdbd9a 100644 --- a/ddraw/IDirect3DLight.h +++ b/ddraw/IDirect3DLight.h @@ -1,7 +1,5 @@ #pragma once -m_IDirect3DLight* CreateDirect3DLight(IDirect3DLight* aOriginal, m_IDirect3DX* NewD3DInterface); - class m_IDirect3DLight : public IDirect3DLight, public AddressLookupTableDdrawObject { private: @@ -83,5 +81,7 @@ class m_IDirect3DLight : public IDirect3DLight, public AddressLookupTableDdrawOb STDMETHOD(GetLight)(THIS_ LPD3DLIGHT); // Helper function - inline void ClearD3D() { D3DInterface = nullptr; D3DDeviceInterface = nullptr; } + m_IDirect3DDeviceX* GetD3DDevice(); + void ClearD3D() { D3DInterface = nullptr; D3DDeviceInterface = nullptr; } + static m_IDirect3DLight* CreateDirect3DLight(IDirect3DLight* aOriginal, m_IDirect3DX* NewD3DInterface); }; diff --git a/ddraw/IDirect3DMaterialX.cpp b/ddraw/IDirect3DMaterialX.cpp index 629a39c1..066379ba 100644 --- a/ddraw/IDirect3DMaterialX.cpp +++ b/ddraw/IDirect3DMaterialX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,13 +16,16 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirect3DMaterial* WrapperInterfaceBackup = nullptr; m_IDirect3DMaterial2* WrapperInterfaceBackup2 = nullptr; m_IDirect3DMaterial3* WrapperInterfaceBackup3 = nullptr; } +// ****************************** +// IUnknown functions +// ****************************** + HRESULT m_IDirect3DMaterialX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << riid; @@ -44,13 +47,7 @@ HRESULT m_IDirect3DMaterialX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, D return D3D_OK; } - if (DirectXVersion != 1 && DirectXVersion != 2 && DirectXVersion != 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirect3D7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; if (riid == GetWrapperType(DxVersion) || riid == IID_IUnknown) { @@ -64,31 +61,11 @@ HRESULT m_IDirect3DMaterialX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, D return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } -void *m_IDirect3DMaterialX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface3) return WrapperInterface3; - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DMATERIAL)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DMATERIAL2)ProxyInterface, this); - case 3: - return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3DMATERIAL3)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirect3DMaterialX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - if (!ProxyInterface) + if (Config.Dd7to9) { switch (DirectXVersion) { @@ -111,10 +88,10 @@ ULONG m_IDirect3DMaterialX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - ULONG ref; - - if (!ProxyInterface) + if (Config.Dd7to9) { + ULONG ref; + switch (DirectXVersion) { case 1: @@ -136,25 +113,29 @@ ULONG m_IDirect3DMaterialX::Release(DWORD DirectXVersion) { delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } +// ****************************** +// IDirect3DMaterial functions +// ****************************** + HRESULT m_IDirect3DMaterialX::Initialize(LPDIRECT3D lplpD3D) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // The method returns DDERR_ALREADYINITIALIZED because the IDirect3DMaterial object is initialized when it is created. return DDERR_ALREADYINITIALIZED; @@ -172,7 +153,7 @@ HRESULT m_IDirect3DMaterialX::SetMaterial(LPD3DMATERIAL lpMat) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpMat || lpMat->dwSize != sizeof(D3DMATERIAL)) { @@ -180,14 +161,8 @@ HRESULT m_IDirect3DMaterialX::SetMaterial(LPD3DMATERIAL lpMat) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - // If current material is set then use new material - if (mHandle && (*D3DDeviceInterface)->CheckIfMaterialSet(mHandle)) + if (mHandle && SUCCEEDED(CheckInterface(__FUNCTION__)) && (*D3DDeviceInterface)->CheckIfMaterialSet(mHandle)) { if (FAILED((*D3DDeviceInterface)->SetMaterial(lpMat))) { @@ -217,7 +192,7 @@ HRESULT m_IDirect3DMaterialX::GetMaterial(LPD3DMATERIAL lpMat) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpMat || lpMat->dwSize != sizeof(D3DMATERIAL)) { @@ -247,7 +222,7 @@ HRESULT m_IDirect3DMaterialX::GetHandle(LPDIRECT3DDEVICE3 lpDirect3DDevice, LPD3 { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpDirect3DDevice || !lpHandle) { @@ -258,6 +233,7 @@ HRESULT m_IDirect3DMaterialX::GetHandle(LPDIRECT3DDEVICE3 lpDirect3DDevice, LPD3 // Check for device interface if (FAILED(CheckInterface(__FUNCTION__))) { + LOG_LIMIT(100, __FUNCTION__ << " Error: D3DDevice does not exist!"); return DDERR_GENERIC; } @@ -310,7 +286,7 @@ HRESULT m_IDirect3DMaterialX::Reserve() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // Former stub method. This method was never implemented and is not supported in any interface. return D3D_OK; @@ -323,7 +299,7 @@ HRESULT m_IDirect3DMaterialX::Unreserve() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // Former stub method. This method was never implemented and is not supported in any interface. return D3D_OK; @@ -332,41 +308,20 @@ HRESULT m_IDirect3DMaterialX::Unreserve() return GetProxyInterfaceV1()->Unreserve(); } -/************************/ -/*** Helper functions ***/ -/************************/ - -HRESULT m_IDirect3DMaterialX::CheckInterface(char* FunctionName) -{ - // Check D3DInterface device - if (!D3DInterface) - { - LOG_LIMIT(100, FunctionName << " Error: no D3D parent!"); - return DDERR_INVALIDOBJECT; - } - - // Check d3d9 device - if (!D3DDeviceInterface || !*D3DDeviceInterface) - { - D3DDeviceInterface = D3DInterface->GetD3DDevice(); - if (!D3DDeviceInterface || !*D3DDeviceInterface) - { - LOG_LIMIT(100, FunctionName << " Error: could not get the D3DDevice!"); - return DDERR_INVALIDOBJECT; - } - } - - return D3D_OK; -} +// ****************************** +// Helper functions +// ****************************** void m_IDirect3DMaterialX::InitInterface(DWORD DirectXVersion) { + ScopedDDCriticalSection ThreadLockDD; + if (D3DInterface) { D3DInterface->AddMaterial(this); } - if (!ProxyInterface) + if (Config.Dd7to9) { Material.dwSize = sizeof(D3DMATERIAL); @@ -381,6 +336,8 @@ void m_IDirect3DMaterialX::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (D3DInterface) { D3DInterface->ClearMaterial(this); @@ -396,3 +353,57 @@ void m_IDirect3DMaterialX::ReleaseInterface() (*D3DDeviceInterface)->ClearMaterialHandle(mHandle); } } + +HRESULT m_IDirect3DMaterialX::CheckInterface(char* FunctionName) +{ + // Check D3DInterface device + if (!D3DInterface) + { + LOG_LIMIT(100, FunctionName << " Error: no D3D parent!"); + return DDERR_INVALIDOBJECT; + } + + // Check d3d9 device + if (!D3DDeviceInterface || !*D3DDeviceInterface) + { + D3DDeviceInterface = D3DInterface->GetD3DDevice(); + if (!D3DDeviceInterface || !*D3DDeviceInterface) + { + LOG_LIMIT(100, FunctionName << " Error: could not get the D3DDevice!"); + return DDERR_INVALIDOBJECT; + } + } + + return D3D_OK; +} + +void* m_IDirect3DMaterialX::GetWrapperInterfaceX(DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 0: + if (WrapperInterface3) return WrapperInterface3; + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DMATERIAL)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DMATERIAL2)ProxyInterface, this); + case 3: + return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3DMATERIAL3)ProxyInterface, this); + } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} + +m_IDirect3DDeviceX* m_IDirect3DMaterialX::GetD3DDevice() +{ + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__))) + { + return nullptr; + } + + return *D3DDeviceInterface; +} diff --git a/ddraw/IDirect3DMaterialX.h b/ddraw/IDirect3DMaterialX.h index c520a32e..64b07e01 100644 --- a/ddraw/IDirect3DMaterialX.h +++ b/ddraw/IDirect3DMaterialX.h @@ -9,7 +9,12 @@ class m_IDirect3DMaterialX : public IUnknown, public AddressLookupTableDdrawObje ULONG RefCount2 = 0; ULONG RefCount3 = 0; - // Convert Material + // Store version wrappers + m_IDirect3DMaterial* WrapperInterface = nullptr; + m_IDirect3DMaterial2* WrapperInterface2 = nullptr; + m_IDirect3DMaterial3* WrapperInterface3 = nullptr; + + // Convert to Direct3D9 m_IDirect3DX* D3DInterface = nullptr; m_IDirect3DDeviceX** D3DDeviceInterface = nullptr; D3DMATERIAL Material = {}; // Defaults to all null @@ -18,11 +23,6 @@ class m_IDirect3DMaterialX : public IUnknown, public AddressLookupTableDdrawObje // Helper functions HRESULT CheckInterface(char* FunctionName); - // Store d3d material version wrappers - m_IDirect3DMaterial *WrapperInterface = nullptr; - m_IDirect3DMaterial2 *WrapperInterface2 = nullptr; - m_IDirect3DMaterial3 *WrapperInterface3 = nullptr; - // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { @@ -47,7 +47,7 @@ class m_IDirect3DMaterialX : public IUnknown, public AddressLookupTableDdrawObje public: m_IDirect3DMaterialX(IDirect3DMaterial3 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -102,7 +102,8 @@ class m_IDirect3DMaterialX : public IUnknown, public AddressLookupTableDdrawObje // Helper function HRESULT QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion); void *GetWrapperInterfaceX(DWORD DirectXVersion); - inline void ClearD3D() { D3DInterface = nullptr; D3DDeviceInterface = nullptr; } + m_IDirect3DDeviceX* GetD3DDevice(); + void ClearD3D() { D3DInterface = nullptr; D3DDeviceInterface = nullptr; } ULONG AddRef(DWORD DirectXVersion); ULONG Release(DWORD DirectXVersion); }; diff --git a/ddraw/IDirect3DTextureX.cpp b/ddraw/IDirect3DTextureX.cpp index dfdb6ace..fab9c336 100644 --- a/ddraw/IDirect3DTextureX.cpp +++ b/ddraw/IDirect3DTextureX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,12 +16,15 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirect3DTexture* WrapperInterfaceBackup = nullptr; m_IDirect3DTexture2* WrapperInterfaceBackup2 = nullptr; } +// ****************************** +// IUnknown functions +// ****************************** + HRESULT m_IDirect3DTextureX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << riid; @@ -43,26 +46,13 @@ HRESULT m_IDirect3DTextureX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DW return D3D_OK; } - if (DirectXVersion != 1 && DirectXVersion != 2) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirect3D7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; if (riid == GetWrapperType(DxVersion) || riid == IID_IUnknown) { *ppvObj = GetWrapperInterfaceX(DxVersion); - if (parent3DSurface.Interface) - { - parent3DSurface.Interface->AddRef(parent3DSurface.DxVersion); // 3DTextures share reference count with surface - } - else - { - AddRef(DxVersion); - } + AddRef(DxVersion); return D3D_OK; } @@ -70,35 +60,18 @@ HRESULT m_IDirect3DTextureX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DW return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } -void *m_IDirect3DTextureX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DTEXTURE)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DTEXTURE2)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirect3DTextureX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - // 3DTextures share reference count with surface - if (parent3DSurface.Interface) + if (Config.Dd7to9) { - return parent3DSurface.Interface->AddRef(parent3DSurface.DxVersion); - } + // 3DTextures share reference count with surface + if (parent3DSurface.Interface) + { + return parent3DSurface.Interface->AddRef(parent3DSurface.DxVersion); + } - if (!ProxyInterface) - { switch (DirectXVersion) { case 1: @@ -118,16 +91,16 @@ ULONG m_IDirect3DTextureX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - // 3DTextures share reference count with surface - if (parent3DSurface.Interface) + if (Config.Dd7to9) { - return parent3DSurface.Interface->Release(parent3DSurface.DxVersion); - } + // 3DTextures share reference count with surface + if (parent3DSurface.Interface) + { + return parent3DSurface.Interface->Release(parent3DSurface.DxVersion); + } - ULONG ref; + ULONG ref; - if (!ProxyInterface) - { switch (DirectXVersion) { case 1: @@ -145,25 +118,29 @@ ULONG m_IDirect3DTextureX::Release(DWORD DirectXVersion) { delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } +// ****************************** +// IDirect3DTexture functions +// ****************************** + HRESULT m_IDirect3DTextureX::Initialize(LPDIRECT3DDEVICE lpDirect3DDevice, LPDIRECTDRAWSURFACE lplpDDSurface) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // The method returns DDERR_ALREADYINITIALIZED because the IDirect3DTexture object is initialized when it is created. return DDERR_ALREADYINITIALIZED; @@ -185,7 +162,7 @@ HRESULT m_IDirect3DTextureX::GetHandle(LPDIRECT3DDEVICE2 lpDirect3DDevice2, LPD3 { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpDirect3DDevice2 || !lpHandle) { @@ -242,24 +219,11 @@ HRESULT m_IDirect3DTextureX::GetHandle(LPDIRECT3DDEVICE2 lpDirect3DDevice2, LPD3 } } -HRESULT m_IDirect3DTextureX::SetHandle(DWORD dwHandle) -{ - if (!dwHandle) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: NULL pointer found!"); - return DDERR_GENERIC; - } - - tHandle = dwHandle; - - return D3D_OK; -} - HRESULT m_IDirect3DTextureX::PaletteChanged(DWORD dwStart, DWORD dwCount) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // This method informs the driver that the palette has changed on a texture surface. // Only affects the legacy ramp device. For all other devices, this method takes no action and returns D3D_OK. @@ -281,19 +245,13 @@ HRESULT m_IDirect3DTextureX::Load(LPDIRECT3DTEXTURE2 lpD3DTexture2) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpD3DTexture2) { return DDERR_INVALIDPARAMS; } - if (!D3DDeviceInterface || !*D3DDeviceInterface) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: D3DDevice does not exist!"); - return DDERR_GENERIC; - } - if (!parent3DSurface.Interface) { LOG_LIMIT(100, __FUNCTION__ << " Error: surface is not attached!"); @@ -338,7 +296,7 @@ HRESULT m_IDirect3DTextureX::Load(LPDIRECT3DTEXTURE2 lpD3DTexture2) } POINT Point = {}; - return (*D3DDeviceInterface)->Load(pDestSurface7, &Point, pSrcSurface7, nullptr, 0); + return parent3DSurface.Interface->Load(pDestSurface7, &Point, pSrcSurface7, nullptr, 0); } if (lpD3DTexture2) @@ -361,7 +319,7 @@ HRESULT m_IDirect3DTextureX::Unload() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // Textures are loaded as managed in Direct3D9, so there is no need to manualy unload the texture return D3D_OK; @@ -374,9 +332,14 @@ HRESULT m_IDirect3DTextureX::Unload() /*** Helper functions ***/ /************************/ -void m_IDirect3DTextureX::InitInterface() +void m_IDirect3DTextureX::InitInterface(DWORD DirectXVersion) { - // Blank for now + ScopedDDCriticalSection ThreadLockDD; + + if (Config.Dd7to9) + { + AddRef(DirectXVersion); + } } void m_IDirect3DTextureX::ReleaseInterface() @@ -386,6 +349,8 @@ void m_IDirect3DTextureX::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + // Don't delete wrapper interface SaveInterfaceAddress(WrapperInterface, WrapperInterfaceBackup); SaveInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2); @@ -395,3 +360,33 @@ void m_IDirect3DTextureX::ReleaseInterface() (*D3DDeviceInterface)->ClearTextureHandle(tHandle); } } + +void* m_IDirect3DTextureX::GetWrapperInterfaceX(DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 0: + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DTEXTURE)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DTEXTURE2)ProxyInterface, this); + } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} + +HRESULT m_IDirect3DTextureX::SetHandle(DWORD dwHandle) +{ + if (!dwHandle) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: NULL pointer found!"); + return DDERR_GENERIC; + } + + tHandle = dwHandle; + + return D3D_OK; +} diff --git a/ddraw/IDirect3DTextureX.h b/ddraw/IDirect3DTextureX.h index 7dc11b89..ecc8809d 100644 --- a/ddraw/IDirect3DTextureX.h +++ b/ddraw/IDirect3DTextureX.h @@ -8,7 +8,11 @@ class m_IDirect3DTextureX : public IUnknown, public AddressLookupTableDdrawObjec ULONG RefCount1 = 0; ULONG RefCount2 = 0; - // Convert Texture + // Store version wrappers + m_IDirect3DTexture* WrapperInterface = nullptr; + m_IDirect3DTexture2* WrapperInterface2 = nullptr; + + // Convert to Direct3D9 m_IDirect3DDeviceX **D3DDeviceInterface = nullptr; DWORD tHandle = 0; struct { @@ -16,10 +20,6 @@ class m_IDirect3DTextureX : public IUnknown, public AddressLookupTableDdrawObjec DWORD DxVersion = 0; } parent3DSurface; - // Store d3d texture version wrappers - m_IDirect3DTexture *WrapperInterface = nullptr; - m_IDirect3DTexture2 *WrapperInterface2 = nullptr; - // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { @@ -35,13 +35,13 @@ class m_IDirect3DTextureX : public IUnknown, public AddressLookupTableDdrawObjec inline IDirect3DTexture2 *GetProxyInterfaceV2() { return ProxyInterface; } // Interface initialization functions - void InitInterface(); + void InitInterface(DWORD DirectXVersion); void ReleaseInterface(); public: m_IDirect3DTextureX(IDirect3DTexture2 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -56,7 +56,7 @@ class m_IDirect3DTextureX : public IUnknown, public AddressLookupTableDdrawObjec Logging::Log() << __FUNCTION__ << " (" << this << ") Warning: created from non-dd7to9 interface!"; } - InitInterface(); + InitInterface(DirectXVersion); } m_IDirect3DTextureX(m_IDirect3DDeviceX **D3DDInterface, DWORD DirectXVersion, m_IDirectDrawSurfaceX *lpSurface, DWORD DXSurfaceVersion) : D3DDeviceInterface(D3DDInterface) { @@ -67,7 +67,7 @@ class m_IDirect3DTextureX : public IUnknown, public AddressLookupTableDdrawObjec parent3DSurface.Interface = lpSurface; parent3DSurface.DxVersion = DXSurfaceVersion; - InitInterface(); + InitInterface(DirectXVersion); } ~m_IDirect3DTextureX() { @@ -96,9 +96,9 @@ class m_IDirect3DTextureX : public IUnknown, public AddressLookupTableDdrawObjec // Handle functions HRESULT m_IDirect3DTextureX::SetHandle(DWORD dwHandle); - inline void SetD3DDevice(m_IDirect3DDeviceX** D3DDevice) { D3DDeviceInterface = D3DDevice; } - inline void ClearD3DDevice() { D3DDeviceInterface = nullptr; } + void SetD3DDevice(m_IDirect3DDeviceX** D3DDevice) { D3DDeviceInterface = D3DDevice; } + void ClearD3DDevice() { D3DDeviceInterface = nullptr; } // Surface functions - m_IDirectDrawSurfaceX *GetSurface() { return parent3DSurface.Interface; } + m_IDirectDrawSurfaceX *GetSurface() const { return parent3DSurface.Interface; } }; diff --git a/ddraw/IDirect3DTypes.cpp b/ddraw/IDirect3DTypes.cpp index 350507e1..913d75f3 100644 --- a/ddraw/IDirect3DTypes.cpp +++ b/ddraw/IDirect3DTypes.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/IDirect3DTypes.h b/ddraw/IDirect3DTypes.h index 8fafc66d..c3dbf554 100644 --- a/ddraw/IDirect3DTypes.h +++ b/ddraw/IDirect3DTypes.h @@ -9,6 +9,8 @@ constexpr UINT MaxSamplerStates = 14; // Devices can have up to 14 sampler state constexpr UINT MaxTextureStages = 8; // Devices can have up to eight set textures. constexpr UINT MAX_LIGHTS = 8; // Devices can have up to eight lights. +#define D3DSTATE D3DSTATE7 + #define D3DDP_FORCE_DWORD 0x0000001Fl #define D3DDP_DXW_COLORKEYENABLE 0x00000020l #define D3DDP_DXW_ALPHACOLORKEY 0x00000040l @@ -107,6 +109,18 @@ typedef enum _D3DSURFACETYPE { D3DTYPE_DEPTHSTENCIL = 4 } D3DSURFACETYPE; +struct CONVERTHOMOGENEOUS +{ + bool IsTransformViewSet = false; // Remembers if game sets the view matrix + D3DMATRIX ToWorld_ProjectionMatrix; // Store the projection matrix used to transform the geometry on the gpu + D3DMATRIX ToWorld_ViewMatrix; // Store the view matrix used to transform the geometry on the gpu + D3DMATRIX ToWorld_ViewMatrixOriginal; // Store the original view matrix, so we can restore it + DirectX::XMMATRIX ToWorld_ViewMatrixInverse; // Store the inverse view matrix to transform the geometry on the cpu + std::vector ToWorld_IntermediateGeometry; // Intermediate buffer for the geometry conversion + float ToWorld_GameCameraYaw = 0.0f; + float ToWorld_GameCameraPitch = 0.0f; +}; + void ConvertLight(D3DLIGHT7& Light7, const D3DLIGHT& Light); void ConvertMaterial(D3DMATERIAL& Material, const D3DMATERIAL7& Material7); void ConvertMaterial(D3DMATERIAL7& Material7, const D3DMATERIAL& Material); diff --git a/ddraw/IDirect3DVertexBufferX.cpp b/ddraw/IDirect3DVertexBufferX.cpp index 17bdf2b1..7a1466c0 100644 --- a/ddraw/IDirect3DVertexBufferX.cpp +++ b/ddraw/IDirect3DVertexBufferX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,12 +16,15 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirect3DVertexBuffer* WrapperInterfaceBackup = nullptr; m_IDirect3DVertexBuffer7* WrapperInterfaceBackup7 = nullptr; } +// ****************************** +// IUnknown functions +// ****************************** + HRESULT m_IDirect3DVertexBufferX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << riid; @@ -43,13 +46,7 @@ HRESULT m_IDirect3DVertexBufferX::QueryInterface(REFIID riid, LPVOID FAR * ppvOb return D3D_OK; } - if (DirectXVersion != 1 && DirectXVersion != 7) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirect3D7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; if (riid == GetWrapperType(DxVersion) || riid == IID_IUnknown) { @@ -63,23 +60,6 @@ HRESULT m_IDirect3DVertexBufferX::QueryInterface(REFIID riid, LPVOID FAR * ppvOb return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } -void *m_IDirect3DVertexBufferX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface7) return WrapperInterface7; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DVERTEXBUFFER)ProxyInterface, this); - case 7: - return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECT3DVERTEXBUFFER7)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirect3DVertexBufferX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; @@ -105,10 +85,10 @@ ULONG m_IDirect3DVertexBufferX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - ULONG ref; - if (Config.Dd7to9) { + ULONG ref; + switch (DirectXVersion) { case 1: @@ -126,20 +106,24 @@ ULONG m_IDirect3DVertexBufferX::Release(DWORD DirectXVersion) { delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } +// ****************************** +// IDirect3DVertexBuffer v1 functions +// ****************************** + HRESULT m_IDirect3DVertexBufferX::Lock(DWORD dwFlags, LPVOID* lplpData, LPDWORD lpdwSize) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -262,7 +246,7 @@ HRESULT m_IDirect3DVertexBufferX::ProcessVertices(DWORD dwVertexOp, DWORD dwDest if (Config.Dd7to9) { // Always include the D3DVOP_TRANSFORM flag in the dwVertexOp parameter. If you do not, the method fails, returning DDERR_INVALIDPARAMS. - if (!lpSrcBuffer || !(dwVertexOp & D3DVOP_TRANSFORM)) + if (!lpSrcBuffer || !lpD3DDevice || !(dwVertexOp & D3DVOP_TRANSFORM)) { return DDERR_INVALIDPARAMS; } @@ -273,6 +257,20 @@ HRESULT m_IDirect3DVertexBufferX::ProcessVertices(DWORD dwVertexOp, DWORD dwDest return DDERR_GENERIC; } + if (lpD3DDevice) + { + m_IDirect3DDeviceX* pDirect3DDeviceX = nullptr; + lpD3DDevice->QueryInterface(IID_GetInterfaceX, (LPVOID*)&pDirect3DDeviceX); + if (pDirect3DDeviceX) + { + m_IDirect3DDeviceX** D3DDeviceInterface = D3DInterface->GetD3DDevice(); + if (D3DDeviceInterface && *D3DDeviceInterface != pDirect3DDeviceX) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: Direct3D Device wrapper does not match! " << *D3DDeviceInterface << "->" << pDirect3DDeviceX); + } + } + } + // Handle dwVertexOp // D3DVOP_TRANSFORM is inherently handled by ProcessVertices() as it performs vertex transformations based on the current world, view, and projection matrices. if (dwVertexOp & D3DVOP_CLIP) @@ -514,6 +512,10 @@ HRESULT m_IDirect3DVertexBufferX::Optimize(LPDIRECT3DDEVICE7 lpD3DDevice, DWORD return ProxyInterface->Optimize(lpD3DDevice, dwFlags); } +// ****************************** +// IDirect3DVertexBuffer v7 functions +// ****************************** + HRESULT m_IDirect3DVertexBufferX::ProcessVerticesStrided(DWORD dwVertexOp, DWORD dwDestIndex, DWORD dwCount, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwSrcIndex, LPDIRECT3DDEVICE7 lpD3DDevice, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -546,6 +548,8 @@ HRESULT m_IDirect3DVertexBufferX::ProcessVerticesStrided(DWORD dwVertexOp, DWORD void m_IDirect3DVertexBufferX::InitInterface(DWORD DirectXVersion) { + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->AddVertexBuffer(this); @@ -574,6 +578,8 @@ void m_IDirect3DVertexBufferX::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->ClearVertexBuffer(this); @@ -624,6 +630,23 @@ HRESULT m_IDirect3DVertexBufferX::CheckInterface(char* FunctionName, bool CheckD return D3D_OK; } +void* m_IDirect3DVertexBufferX::GetWrapperInterfaceX(DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 0: + if (WrapperInterface7) return WrapperInterface7; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DVERTEXBUFFER)ProxyInterface, this); + case 7: + return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECT3DVERTEXBUFFER7)ProxyInterface, this); + } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} + HRESULT m_IDirect3DVertexBufferX::CreateD3D9VertexBuffer() { // Release existing buffer diff --git a/ddraw/IDirect3DVertexBufferX.h b/ddraw/IDirect3DVertexBufferX.h index fea63019..a6882f70 100644 --- a/ddraw/IDirect3DVertexBufferX.h +++ b/ddraw/IDirect3DVertexBufferX.h @@ -7,9 +7,16 @@ class m_IDirect3DVertexBufferX : public IDirect3DVertexBuffer7, public AddressLo DWORD ProxyDirectXVersion; ULONG RefCount1 = 0; ULONG RefCount7 = 0; + + // Store version wrappers + m_IDirect3DVertexBuffer* WrapperInterface = nullptr; + m_IDirect3DVertexBuffer7* WrapperInterface7 = nullptr; + + // Convert to Direct3D9 m_IDirectDrawX* ddrawParent = nullptr; m_IDirect3DX* D3DInterface = nullptr; LPDIRECT3DDEVICE9* d3d9Device = nullptr; + LPDIRECT3DVERTEXBUFFER9 d3d9VertexBuffer = nullptr; // Vertex buffer desc D3DVERTEXBUFFERDESC VBDesc = {}; @@ -20,12 +27,12 @@ class m_IDirect3DVertexBufferX : public IDirect3DVertexBuffer7, public AddressLo void* LastLockAddr = nullptr; DWORD LastLockFlags = 0; - // Store d3d interface - LPDIRECT3DVERTEXBUFFER9 d3d9VertexBuffer = nullptr; + // Direct3D9 interface functions + HRESULT CreateD3D9VertexBuffer(); + void ReleaseD3D9VertexBuffer(); - // Store version wrappers - m_IDirect3DVertexBuffer *WrapperInterface = nullptr; - m_IDirect3DVertexBuffer7 *WrapperInterface7 = nullptr; + // Check interfaces + HRESULT CheckInterface(char* FunctionName, bool CheckD3DDevice, bool CheckD3DVertexBuffer); // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) @@ -41,13 +48,6 @@ class m_IDirect3DVertexBufferX : public IDirect3DVertexBuffer7, public AddressLo inline IDirect3DVertexBuffer *GetProxyInterfaceV1() { return (IDirect3DVertexBuffer *)ProxyInterface; } inline IDirect3DVertexBuffer7 *GetProxyInterfaceV7() { return ProxyInterface; } - // Check interfaces - HRESULT CheckInterface(char* FunctionName, bool CheckD3DDevice, bool CheckD3DVertexBuffer); - - // Direct3D9 interface functions - HRESULT CreateD3D9VertexBuffer(); - void ReleaseD3D9VertexBuffer(); - // Interface initialization functions void InitInterface(DWORD DirectXVersion); void ReleaseInterface(); @@ -55,7 +55,7 @@ class m_IDirect3DVertexBufferX : public IDirect3DVertexBuffer7, public AddressLo public: m_IDirect3DVertexBufferX(IDirect3DVertexBuffer7 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -122,8 +122,8 @@ class m_IDirect3DVertexBufferX : public IDirect3DVertexBuffer7, public AddressLo void ClearDdraw() { ddrawParent = nullptr; d3d9Device = nullptr; } // Direct3D9 interfaces - inline const LPDIRECT3DVERTEXBUFFER9 GetCurrentD9VertexBuffer() const { return d3d9VertexBuffer; }; - inline void ClearD3D() { D3DInterface = nullptr; } + const LPDIRECT3DVERTEXBUFFER9 GetCurrentD9VertexBuffer() const { return d3d9VertexBuffer; }; + void ClearD3D() { D3DInterface = nullptr; } void ReleaseD9Buffer(bool BackupData, bool ResetBuffer); DWORD GetFVF9() const { return d3d9VBDesc.FVF; }; diff --git a/ddraw/IDirect3DViewportX.cpp b/ddraw/IDirect3DViewportX.cpp index 4ec15dfa..35ee6390 100644 --- a/ddraw/IDirect3DViewportX.cpp +++ b/ddraw/IDirect3DViewportX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,13 +16,16 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirect3DViewport* WrapperInterfaceBackup = nullptr; m_IDirect3DViewport2* WrapperInterfaceBackup2 = nullptr; m_IDirect3DViewport3* WrapperInterfaceBackup3 = nullptr; } +// ****************************** +// IUnknown functions +// ****************************** + HRESULT m_IDirect3DViewportX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << riid; @@ -44,13 +47,7 @@ HRESULT m_IDirect3DViewportX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, D return D3D_OK; } - if (DirectXVersion != 1 && DirectXVersion != 2 && DirectXVersion != 3) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirect3D7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; if (riid == GetWrapperType(DxVersion) || riid == IID_IUnknown) { @@ -64,31 +61,11 @@ HRESULT m_IDirect3DViewportX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, D return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } -void *m_IDirect3DViewportX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface3) return WrapperInterface3; - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DVIEWPORT)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DVIEWPORT2)ProxyInterface, this); - case 3: - return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3DVIEWPORT3)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirect3DViewportX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - if (!ProxyInterface) + if (Config.Dd7to9) { switch (DirectXVersion) { @@ -111,10 +88,10 @@ ULONG m_IDirect3DViewportX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - ULONG ref; - - if (!ProxyInterface) + if (Config.Dd7to9) { + ULONG ref; + switch (DirectXVersion) { case 1: @@ -140,25 +117,29 @@ ULONG m_IDirect3DViewportX::Release(DWORD DirectXVersion) } delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } +// ****************************** +// IDirect3DViewport v1 functions +// ****************************** + HRESULT m_IDirect3DViewportX::Initialize(LPDIRECT3D lpDirect3D) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // The method returns DDERR_ALREADYINITIALIZED because the IDirect3DViewport object is initialized when it is created. return DDERR_ALREADYINITIALIZED; @@ -176,7 +157,7 @@ HRESULT m_IDirect3DViewportX::GetViewport(LPD3DVIEWPORT lpData) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpData || lpData->dwSize != sizeof(D3DVIEWPORT)) { @@ -184,12 +165,6 @@ HRESULT m_IDirect3DViewportX::GetViewport(LPD3DVIEWPORT lpData) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - HRESULT hr = D3D_OK; if (IsViewPortSet) @@ -204,7 +179,10 @@ HRESULT m_IDirect3DViewportX::GetViewport(LPD3DVIEWPORT lpData) { D3DVIEWPORT7 Viewport7 = {}; - (*D3DDeviceInterface)->GetDefaultViewport(*(D3DVIEWPORT9*)&Viewport7); + if (SUCCEEDED(CheckInterface(__FUNCTION__))) + { + (*D3DDeviceInterface)->GetDefaultViewport(*(D3DVIEWPORT9*)&Viewport7); + } ConvertViewport(*lpData, Viewport7); } @@ -219,7 +197,7 @@ HRESULT m_IDirect3DViewportX::SetViewport(LPD3DVIEWPORT lpData) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpData || lpData->dwSize != sizeof(D3DVIEWPORT)) { @@ -227,12 +205,6 @@ HRESULT m_IDirect3DViewportX::SetViewport(LPD3DVIEWPORT lpData) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - if (lpData->dvScaleX != 0 || lpData->dvScaleY != 0 || lpData->dvMaxX != 0 || lpData->dvMaxY != 0) { LOG_LIMIT(100, __FUNCTION__ << " Warning: 'Scale homogeneous' Not Implemented: " << @@ -244,7 +216,7 @@ HRESULT m_IDirect3DViewportX::SetViewport(LPD3DVIEWPORT lpData) vData = *lpData; // If current viewport is set then use new viewport - if ((*D3DDeviceInterface)->CheckIfViewportSet(this)) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && (*D3DDeviceInterface)->CheckIfViewportSet(this)) { SetCurrentViewportActive(true, false, false); } @@ -267,7 +239,7 @@ HRESULT m_IDirect3DViewportX::TransformVertices(DWORD dwVertexCount, LPD3DTRANSF { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); return DDERR_UNSUPPORTED; @@ -280,7 +252,7 @@ HRESULT m_IDirect3DViewportX::LightElements(DWORD dwElementCount, LPD3DLIGHTDATA { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); return DDERR_UNSUPPORTED; @@ -293,19 +265,13 @@ HRESULT m_IDirect3DViewportX::SetBackground(D3DMATERIALHANDLE hMat) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - MaterialBackground.IsSet = TRUE; MaterialBackground.hMat = hMat; // If current viewport is set then use new viewport - if ((*D3DDeviceInterface)->CheckIfViewportSet(this)) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && (*D3DDeviceInterface)->CheckIfViewportSet(this)) { SetCurrentViewportActive(false, true, false); } @@ -320,7 +286,7 @@ HRESULT m_IDirect3DViewportX::GetBackground(LPD3DMATERIALHANDLE lphMat, LPBOOL l { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lphMat || !lpValid) { @@ -340,7 +306,7 @@ HRESULT m_IDirect3DViewportX::SetBackgroundDepth(LPDIRECTDRAWSURFACE lpDDSurface { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // Sets the background-depth field for the viewport. // The depth-buffer is filled with the specified depth field when the IDirect3DViewport3::Clear method is called @@ -361,7 +327,7 @@ HRESULT m_IDirect3DViewportX::GetBackgroundDepth(LPDIRECTDRAWSURFACE * lplpDDSur { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); return DDERR_UNSUPPORTED; @@ -381,9 +347,17 @@ HRESULT m_IDirect3DViewportX::Clear(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFl { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { - return Clear2(dwCount, lpRects, dwFlags, 0x00000000, 1.0f, 0); + // The requested operation could not be completed because the viewport has not yet been associated with a device. + if (!IsViewportAssiciated()) + { + return D3DERR_VIEWPORTHASNODEVICE; + } + + // ToDo: check on zbuffer and return error if does not exist: D3DERR_ZBUFFER_NOTPRESENT + + return (*D3DDeviceInterface)->Clear(dwCount, lpRects, dwFlags, 0x00000000, 1.0f, 0); } return ProxyInterface->Clear(dwCount, lpRects, dwFlags); @@ -393,7 +367,7 @@ HRESULT m_IDirect3DViewportX::AddLight(LPDIRECT3DLIGHT lpDirect3DLight) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // This method will fail, returning DDERR_INVALIDPARAMS, if you attempt to add a light that has already been assigned to the viewport. if (!lpDirect3DLight || IsLightAttached(lpDirect3DLight)) @@ -401,14 +375,8 @@ HRESULT m_IDirect3DViewportX::AddLight(LPDIRECT3DLIGHT lpDirect3DLight) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - // If current viewport is set then use new light - if ((*D3DDeviceInterface)->CheckIfViewportSet(this)) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && (*D3DDeviceInterface)->CheckIfViewportSet(this)) { D3DLIGHT2 Light2 = {}; Light2.dwSize = sizeof(D3DLIGHT2); @@ -425,6 +393,16 @@ HRESULT m_IDirect3DViewportX::AddLight(LPDIRECT3DLIGHT lpDirect3DLight) } } + // Check if assigning a light associated with current device used by the viewport + { + m_IDirect3DDeviceX* pLight3DDevice = ((m_IDirect3DLight*)lpDirect3DLight)->GetD3DDevice(); + m_IDirect3DDeviceX* pViewPort3DDevice = (D3DDeviceInterface ? *D3DDeviceInterface : nullptr); + if (pLight3DDevice != pViewPort3DDevice) + { + LOG_LIMIT(100, __FUNCTION__ << " (" << pViewPort3DDevice << ") Warning: Light's Direct3D device doesn't match Viewport's device: " << pLight3DDevice); + } + } + AttachedLights.push_back(lpDirect3DLight); lpDirect3DLight->AddRef(); @@ -444,19 +422,13 @@ HRESULT m_IDirect3DViewportX::DeleteLight(LPDIRECT3DLIGHT lpDirect3DLight) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpDirect3DLight) { return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - bool ret = DeleteAttachedLight(lpDirect3DLight); if (!ret) @@ -467,7 +439,7 @@ HRESULT m_IDirect3DViewportX::DeleteLight(LPDIRECT3DLIGHT lpDirect3DLight) lpDirect3DLight->Release(); // If current viewport is then deactivate the light - if ((*D3DDeviceInterface)->CheckIfViewportSet(this)) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && (*D3DDeviceInterface)->CheckIfViewportSet(this)) { D3DLIGHT2 Light2 = {}; Light2.dwSize = sizeof(D3DLIGHT2); @@ -497,7 +469,7 @@ HRESULT m_IDirect3DViewportX::NextLight(LPDIRECT3DLIGHT lpDirect3DLight, LPDIREC { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lplpDirect3DLight || (dwFlags == D3DNEXT_NEXT && !lpDirect3DLight)) { @@ -556,11 +528,15 @@ HRESULT m_IDirect3DViewportX::NextLight(LPDIRECT3DLIGHT lpDirect3DLight, LPDIREC return hr; } +// ****************************** +// IDirect3DViewport v2 functions +// ****************************** + HRESULT m_IDirect3DViewportX::GetViewport2(LPD3DVIEWPORT2 lpData) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpData || lpData->dwSize != sizeof(D3DVIEWPORT2)) { @@ -580,15 +556,12 @@ HRESULT m_IDirect3DViewportX::GetViewport2(LPD3DVIEWPORT2 lpData) } else { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - D3DVIEWPORT7 Viewport7 = {}; - (*D3DDeviceInterface)->GetDefaultViewport(*(D3DVIEWPORT9*)&Viewport7); + if (SUCCEEDED(CheckInterface(__FUNCTION__))) + { + (*D3DDeviceInterface)->GetDefaultViewport(*(D3DVIEWPORT9*)&Viewport7); + } ConvertViewport(*lpData, Viewport7); } @@ -603,7 +576,7 @@ HRESULT m_IDirect3DViewportX::SetViewport2(LPD3DVIEWPORT2 lpData) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpData || lpData->dwSize != sizeof(D3DVIEWPORT2)) { @@ -611,12 +584,6 @@ HRESULT m_IDirect3DViewportX::SetViewport2(LPD3DVIEWPORT2 lpData) return DDERR_INVALIDPARAMS; } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return DDERR_GENERIC; - } - if (lpData->dvClipWidth != 0 || lpData->dvClipHeight != 0 || lpData->dvClipX != 0 || lpData->dvClipY != 0) { LOG_LIMIT(100, __FUNCTION__ << " Warning: 'clip volume' Not Implemented: " << @@ -628,7 +595,7 @@ HRESULT m_IDirect3DViewportX::SetViewport2(LPD3DVIEWPORT2 lpData) vData2 = *lpData; // If current viewport is set then use new viewport - if ((*D3DDeviceInterface)->CheckIfViewportSet(this)) + if (SUCCEEDED(CheckInterface(__FUNCTION__)) && (*D3DDeviceInterface)->CheckIfViewportSet(this)) { SetCurrentViewportActive(true, false, false); } @@ -647,63 +614,15 @@ HRESULT m_IDirect3DViewportX::SetViewport2(LPD3DVIEWPORT2 lpData) return ProxyInterface->SetViewport2(lpData); } -void m_IDirect3DViewportX::SetCurrentViewportActive(bool SetViewPortData, bool SetBackgroundData, bool SetLightData) -{ - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) - { - return; - } - - if (SetViewPortData && (IsViewPortSet || IsViewPort2Set)) - { - D3DVIEWPORT7 Viewport7 = {}; - if (IsViewPort2Set) - { - ConvertViewport(Viewport7, vData2); - } - else - { - ConvertViewport(Viewport7, vData); - } - if (FAILED((*D3DDeviceInterface)->SetViewport(&Viewport7))) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: failed to set viewport data!"); - } - } - - if (SetBackgroundData && MaterialBackground.IsSet) - { - if (FAILED((*D3DDeviceInterface)->SetLightState(D3DLIGHTSTATE_MATERIAL, MaterialBackground.hMat))) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: failed to set material background!"); - } - } - - if (SetLightData) - { - for (auto& entry : AttachedLights) - { - D3DLIGHT2 Light2 = {}; - Light2.dwSize = sizeof(D3DLIGHT2); - if (FAILED(entry->GetLight((LPD3DLIGHT)&Light2))) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: could not get light!"); - } - Light2.dwFlags |= D3DLIGHT_ACTIVE; - if (FAILED((*D3DDeviceInterface)->SetLight((m_IDirect3DLight*)entry, (LPD3DLIGHT)&Light2))) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: could not set light!"); - } - } - } -} +// ****************************** +// IDirect3DViewport v3 functions +// ****************************** HRESULT m_IDirect3DViewportX::SetBackgroundDepth2(LPDIRECTDRAWSURFACE4 lpDDS) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // Sets the background-depth field for the viewport. // The depth-buffer is filled with the specified depth field when the IDirect3DViewport3::Clear or @@ -724,7 +643,7 @@ HRESULT m_IDirect3DViewportX::GetBackgroundDepth2(LPDIRECTDRAWSURFACE4* lplpDDS, { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { LOG_LIMIT(100, __FUNCTION__ << " Error: Not Implemented"); return DDERR_UNSUPPORTED; @@ -744,23 +663,65 @@ HRESULT m_IDirect3DViewportX::Clear2(DWORD dwCount, LPD3DRECT lpRects, DWORD dwF { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__))) + // The requested operation could not be completed because the viewport has not yet been associated with a device. + if (!IsViewportAssiciated()) { - return DDERR_GENERIC; + return D3DERR_VIEWPORTHASNODEVICE; } + // ToDo: check on zbuffer and stencil buffer and return error if does not exist: D3DERR_ZBUFFER_NOTPRESENT and D3DERR_STENCILBUFFER_NOTPRESENT + return (*D3DDeviceInterface)->Clear(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); } return ProxyInterface->Clear2(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** + +void m_IDirect3DViewportX::InitInterface(DWORD DirectXVersion) +{ + ScopedDDCriticalSection ThreadLockDD; + + if (D3DInterface) + { + D3DInterface->AddViewport(this); + } + + if (Config.Dd7to9) + { + AddRef(DirectXVersion); + } +} + +void m_IDirect3DViewportX::ReleaseInterface() +{ + if (Config.Exiting) + { + return; + } + + ScopedDDCriticalSection ThreadLockDD; + + if (D3DInterface) + { + D3DInterface->ClearViewport(this); + } + + // Don't delete wrapper interface + SaveInterfaceAddress(WrapperInterface, WrapperInterfaceBackup); + SaveInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2); + SaveInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3); + + if (D3DDeviceInterface && *D3DDeviceInterface) + { + (*D3DDeviceInterface)->ClearViewport(this); + } +} HRESULT m_IDirect3DViewportX::CheckInterface(char* FunctionName) { @@ -777,7 +738,6 @@ HRESULT m_IDirect3DViewportX::CheckInterface(char* FunctionName) D3DDeviceInterface = D3DInterface->GetD3DDevice(); if (!D3DDeviceInterface || !*D3DDeviceInterface) { - LOG_LIMIT(100, FunctionName << " Error: could not get the D3DDevice!"); return DDERR_INVALIDOBJECT; } } @@ -785,38 +745,85 @@ HRESULT m_IDirect3DViewportX::CheckInterface(char* FunctionName) return D3D_OK; } -void m_IDirect3DViewportX::InitInterface(DWORD DirectXVersion) +void* m_IDirect3DViewportX::GetWrapperInterfaceX(DWORD DirectXVersion) { - if (D3DInterface) + switch (DirectXVersion) { - D3DInterface->AddViewport(this); + case 0: + if (WrapperInterface3) return WrapperInterface3; + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3DVIEWPORT)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3DVIEWPORT2)ProxyInterface, this); + case 3: + return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3DVIEWPORT3)ProxyInterface, this); } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} - if (!ProxyInterface) +m_IDirect3DDeviceX* m_IDirect3DViewportX::GetD3DDevice() +{ + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__))) { - AddRef(DirectXVersion); + return nullptr; } + + return *D3DDeviceInterface; } -void m_IDirect3DViewportX::ReleaseInterface() +void m_IDirect3DViewportX::SetCurrentViewportActive(bool SetViewPortData, bool SetBackgroundData, bool SetLightData) { - if (Config.Exiting) + // Check for device interface + if (FAILED(CheckInterface(__FUNCTION__))) { return; } - if (D3DInterface) + if (SetViewPortData && (IsViewPortSet || IsViewPort2Set)) { - D3DInterface->ClearViewport(this); + D3DVIEWPORT7 Viewport7 = {}; + if (IsViewPort2Set) + { + ConvertViewport(Viewport7, vData2); + } + else + { + ConvertViewport(Viewport7, vData); + } + if (FAILED((*D3DDeviceInterface)->SetViewport(&Viewport7))) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: failed to set viewport data!"); + } } - // Don't delete wrapper interface - SaveInterfaceAddress(WrapperInterface, WrapperInterfaceBackup); - SaveInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2); - SaveInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3); + if (SetBackgroundData && MaterialBackground.IsSet) + { + if (FAILED((*D3DDeviceInterface)->SetLightState(D3DLIGHTSTATE_MATERIAL, MaterialBackground.hMat))) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: failed to set material background!"); + } + } - if (D3DDeviceInterface && *D3DDeviceInterface) + if (SetLightData) { - (*D3DDeviceInterface)->ClearViewport(this); + for (auto& entry : AttachedLights) + { + D3DLIGHT2 Light2 = {}; + Light2.dwSize = sizeof(D3DLIGHT2); + if (FAILED(entry->GetLight((LPD3DLIGHT)&Light2))) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: could not get light!"); + } + Light2.dwFlags |= D3DLIGHT_ACTIVE; + if (FAILED((*D3DDeviceInterface)->SetLight((m_IDirect3DLight*)entry, (LPD3DLIGHT)&Light2))) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: could not set light!"); + } + } } } diff --git a/ddraw/IDirect3DViewportX.h b/ddraw/IDirect3DViewportX.h index 04e8b714..ffb45366 100644 --- a/ddraw/IDirect3DViewportX.h +++ b/ddraw/IDirect3DViewportX.h @@ -9,15 +9,31 @@ class m_IDirect3DViewportX : public IUnknown, public AddressLookupTableDdrawObje ULONG RefCount2 = 0; ULONG RefCount3 = 0; + // Store version wrappers + m_IDirect3DViewport* WrapperInterface = nullptr; + m_IDirect3DViewport2* WrapperInterface2 = nullptr; + m_IDirect3DViewport3* WrapperInterface3 = nullptr; + + // Convert to Direct3D9 + m_IDirect3DX* D3DInterface = nullptr; + m_IDirect3DDeviceX** D3DDeviceInterface = nullptr; bool IsViewPortSet = false; D3DVIEWPORT vData = {}; bool IsViewPort2Set = false; D3DVIEWPORT2 vData2 = {}; + struct MATERIALBACKGROUND { + BOOL IsSet = FALSE; + D3DMATERIALHANDLE hMat = NULL; + } MaterialBackground; + // Light array std::vector AttachedLights; - inline bool IsLightAttached(LPDIRECT3DLIGHT LightX) + // Helper functions + HRESULT CheckInterface(char* FunctionName); + + bool IsLightAttached(LPDIRECT3DLIGHT LightX) { auto it = std::find_if(AttachedLights.begin(), AttachedLights.end(), [=](auto pLight) -> bool { return pLight == LightX; }); @@ -29,7 +45,7 @@ class m_IDirect3DViewportX : public IUnknown, public AddressLookupTableDdrawObje return false; } - inline bool DeleteAttachedLight(LPDIRECT3DLIGHT LightX) + bool DeleteAttachedLight(LPDIRECT3DLIGHT LightX) { auto it = std::find_if(AttachedLights.begin(), AttachedLights.end(), [=](auto pLight) -> bool { return pLight == LightX; }); @@ -42,22 +58,12 @@ class m_IDirect3DViewportX : public IUnknown, public AddressLookupTableDdrawObje return false; } - struct MATERIALBACKGROUND { - BOOL IsSet = FALSE; - D3DMATERIALHANDLE hMat = NULL; - } MaterialBackground; - - // Device interface pointers - m_IDirect3DX* D3DInterface = nullptr; - m_IDirect3DDeviceX** D3DDeviceInterface = nullptr; - - // Store version wrappers - m_IDirect3DViewport *WrapperInterface = nullptr; - m_IDirect3DViewport2 *WrapperInterface2 = nullptr; - m_IDirect3DViewport3 *WrapperInterface3 = nullptr; - - // Helper functions - HRESULT CheckInterface(char* FunctionName); + bool IsViewportAssiciated() { + return SUCCEEDED(CheckInterface(__FUNCTION__)) && ((*D3DDeviceInterface)->CheckIfViewportSet(this) || + (*D3DDeviceInterface)->IsViewportAttached((LPDIRECT3DVIEWPORT3)WrapperInterface) || + (*D3DDeviceInterface)->IsViewportAttached((LPDIRECT3DVIEWPORT3)WrapperInterface2) || + (*D3DDeviceInterface)->IsViewportAttached((LPDIRECT3DVIEWPORT3)WrapperInterface3)); + } // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) @@ -83,7 +89,7 @@ class m_IDirect3DViewportX : public IUnknown, public AddressLookupTableDdrawObje public: m_IDirect3DViewportX(IDirect3DViewport3 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -155,7 +161,8 @@ class m_IDirect3DViewportX : public IUnknown, public AddressLookupTableDdrawObje HRESULT QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion); void *GetWrapperInterfaceX(DWORD DirectXVersion); void SetCurrentViewportActive(bool SetViewPortData, bool SetBackgroundData, bool SetLightData); - inline void ClearD3D() { D3DInterface = nullptr; D3DDeviceInterface = nullptr; } + m_IDirect3DDeviceX* GetD3DDevice(); + void ClearD3D() { D3DInterface = nullptr; D3DDeviceInterface = nullptr; } ULONG AddRef(DWORD DirectXVersion); ULONG Release(DWORD DirectXVersion); }; diff --git a/ddraw/IDirect3DX.cpp b/ddraw/IDirect3DX.cpp index 945d3774..c85e07a4 100644 --- a/ddraw/IDirect3DX.cpp +++ b/ddraw/IDirect3DX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -17,20 +17,23 @@ #include "ddraw.h" #include "Utils\Utils.h" -bool GetD3DPath = true; -char D3DImPath[MAX_PATH] = { '\0' }; -char D3DIm700Path[MAX_PATH] = { '\0' }; -HMODULE hD3DIm = nullptr; -HMODULE hD3DIm700 = nullptr; - -// Cached wrapper interface namespace { + bool GetD3DPath = true; + char D3DImPath[MAX_PATH] = { '\0' }; + char D3DIm700Path[MAX_PATH] = { '\0' }; + HMODULE hD3DIm = nullptr; + HMODULE hD3DIm700 = nullptr; + m_IDirect3D* WrapperInterfaceBackup = nullptr; m_IDirect3D2* WrapperInterfaceBackup2 = nullptr; m_IDirect3D3* WrapperInterfaceBackup3 = nullptr; m_IDirect3D7* WrapperInterfaceBackup7 = nullptr; } +// ****************************** +// IUnknown functions +// ****************************** + HRESULT m_IDirect3DX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") " << riid; @@ -66,69 +69,37 @@ HRESULT m_IDirect3DX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD Dir } } - if (DirectXVersion != 1 && DirectXVersion != 2 && DirectXVersion != 3 && DirectXVersion != 7) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirect3D7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; - if ((ddrawParent && ((riid == IID_IDirect3D7 && ddrawParent->IsCreatedEx()) || (riid == GetWrapperType(DxVersion) && riid != IID_IDirect3D7 && !ddrawParent->IsCreatedEx()))) || - (!ddrawParent && (riid == GetWrapperType(DxVersion) || riid == IID_IUnknown))) + if ((riid == GetWrapperType(DxVersion) && (riid != IID_IDirect3D7 || DirectXVersion == 7)) || riid == IID_IUnknown) { - *ppvObj = GetWrapperInterfaceX(DxVersion); - - if (ddrawParent) - { - ddrawParent->AddRef(DDrawVersion); // Direct3D shares reference count with DirectDraw - } - else + if (riid != IID_IUnknown && ddrawParent && ((ddrawParent->IsCreatedEx() && riid != IID_IDirect3D7) || (!ddrawParent->IsCreatedEx() && riid == IID_IDirect3D7))) { - AddRef(DxVersion); + return E_NOINTERFACE; } + *ppvObj = GetWrapperInterfaceX(DxVersion); + + AddRef(DxVersion); + return D3D_OK; } return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } -void *m_IDirect3DX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface7) return WrapperInterface7; - if (WrapperInterface3) return WrapperInterface3; - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3D)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3D2)ProxyInterface, this); - case 3: - return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3D3)ProxyInterface, this); - case 7: - return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECT3D7)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirect3DX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Direct3D shares reference count with DirectDraw - if (ddrawParent) - { - return ddrawParent->AddRef(DDrawVersion); - } - if (Config.Dd7to9) { + // Direct3D shares reference count with DirectDraw + if (ddrawParent) + { + return ddrawParent->AddRef(DDrawVersion); + } + switch (DirectXVersion) { case 1: @@ -152,16 +123,16 @@ ULONG m_IDirect3DX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Direct3D shares reference count with DirectDraw - if (ddrawParent) + if (Config.Dd7to9) { - return ddrawParent->Release(DDrawVersion); - } + // Direct3D shares reference count with DirectDraw + if (ddrawParent) + { + return ddrawParent->Release(DDrawVersion); + } - ULONG ref; + ULONG ref; - if (Config.Dd7to9) - { switch (DirectXVersion) { case 1: @@ -186,25 +157,29 @@ ULONG m_IDirect3DX::Release(DWORD DirectXVersion) { delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } +// ****************************** +// IDirect3D v1 functions +// ****************************** + HRESULT m_IDirect3DX::Initialize(REFCLSID rclsid) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion != 1) + if (Config.Dd7to9) { // The method returns DDERR_ALREADYINITIALIZED because the IDirect3D object is initialized when it is created. return DDERR_ALREADYINITIALIZED; @@ -217,6 +192,11 @@ HRESULT m_IDirect3DX::EnumDevices(LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + if (Config.Dd7to9) + { + return EnumDevices7((LPD3DENUMDEVICESCALLBACK7)lpEnumDevicesCallback, lpUserArg, DirectXVersion); + } + switch (ProxyDirectXVersion) { case 1: @@ -226,190 +206,37 @@ HRESULT m_IDirect3DX::EnumDevices(LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback case 3: return GetProxyInterfaceV3()->EnumDevices(lpEnumDevicesCallback, lpUserArg); case 7: - { - if (!lpEnumDevicesCallback) - { - return DDERR_INVALIDPARAMS; - } - - struct EnumDevicesStruct7 - { - LPVOID lpContext; - LPD3DENUMDEVICESCALLBACK lpCallback; - DWORD DirectXVersion; - - static HRESULT CALLBACK ConvertCallback(LPSTR lpDeviceDescription, LPSTR lpDeviceName, LPD3DDEVICEDESC7 lpDeviceDesc, LPVOID lpContext) - { - EnumDevicesStruct7* self = (EnumDevicesStruct7*)lpContext; - - D3DDEVICEDESC D3DDRVDevDesc = {}, D3DSWDevDesc = {}; - D3DDRVDevDesc.dwSize = sizeof(D3DDEVICEDESC); - D3DSWDevDesc.dwSize = sizeof(D3DDEVICEDESC); - ConvertDeviceDesc(D3DDRVDevDesc, *lpDeviceDesc); - ConvertDeviceDesc(D3DSWDevDesc, *lpDeviceDesc); - - D3DDRVDevDesc.dwSize = (self->DirectXVersion == 1) ? D3DDEVICEDESC1_SIZE : - (self->DirectXVersion == 2) ? D3DDEVICEDESC5_SIZE : - (self->DirectXVersion == 3) ? D3DDEVICEDESC6_SIZE : sizeof(D3DDEVICEDESC); - D3DSWDevDesc.dwSize = D3DDRVDevDesc.dwSize; - - return self->lpCallback(&lpDeviceDesc->deviceGUID, lpDeviceDescription, lpDeviceName, &D3DDRVDevDesc, &D3DSWDevDesc, self->lpContext); - } - } CallbackContext7 = {}; - CallbackContext7.lpContext = lpUserArg; - CallbackContext7.lpCallback = lpEnumDevicesCallback; - CallbackContext7.DirectXVersion = DirectXVersion; - - return EnumDevices7(EnumDevicesStruct7::ConvertCallback, &CallbackContext7, 7); - } - case 9: - return EnumDevices7((LPD3DENUMDEVICESCALLBACK7)lpEnumDevicesCallback, lpUserArg, DirectXVersion); default: return DDERR_GENERIC; } } -void m_IDirect3DX::GetCap9Cache() -{ - // Check for device - if (ddrawParent) - { - // Get d3d9Object - IDirect3D9* d3d9Object = ddrawParent->GetDirectD9Object(); - if (d3d9Object) - { - UINT AdapterCount = d3d9Object->GetAdapterCount(); - if (AdapterCount) - { - Cap9Cache.clear(); - - // Loop through all adapters - for (UINT i = 0; i < AdapterCount; i++) - { - // Get Device Caps - DUALCAP9 DCaps9; - if (SUCCEEDED(d3d9Object->GetDeviceCaps(i, D3DDEVTYPE_REF, &DCaps9.REF)) && SUCCEEDED(d3d9Object->GetDeviceCaps(i, D3DDEVTYPE_HAL, &DCaps9.HAL))) - { - Cap9Cache.push_back(DCaps9); - } - } - } - } - } -} - -HRESULT m_IDirect3DX::EnumDevices7(LPD3DENUMDEVICESCALLBACK7 lpEnumDevicesCallback7, LPVOID lpUserArg, DWORD DirectXVersion) +HRESULT m_IDirect3DX::CreateLight(LPDIRECT3DLIGHT* lplpDirect3DLight, LPUNKNOWN pUnkOuter) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (Config.Dd7to9) { - if (!lpEnumDevicesCallback7) + if (!lplpDirect3DLight) { return DDERR_INVALIDPARAMS; } + *lplpDirect3DLight = nullptr; - // Conversion callback - LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback = (LPD3DENUMDEVICESCALLBACK)lpEnumDevicesCallback7; - - // Update Cap9 cache - GetCap9Cache(); - - // Check cache - if (Cap9Cache.empty()) + // Check for device + if (!ddrawParent) { - LOG_LIMIT(100, __FUNCTION__ << " Error: could not get Cap9 cache!"); + LOG_LIMIT(100, __FUNCTION__ << " Error: no ddraw parent!"); return DDERR_INVALIDOBJECT; } - DWORD DevSize = (DirectXVersion == 1) ? D3DDEVICEDESC1_SIZE : - (DirectXVersion == 2) ? D3DDEVICEDESC5_SIZE : - (DirectXVersion == 3) ? D3DDEVICEDESC6_SIZE : sizeof(D3DDEVICEDESC); - - // Loop through all adapters - for (auto& entry : Cap9Cache) - { - for (int x = 0; x < 3; x++) - { - // Get Device Caps - D3DCAPS9 Caps9 = (x == 0) ? entry.REF : entry.HAL; - D3DDEVTYPE Type = (x == 0) ? D3DDEVTYPE_REF : (x == 1) ? D3DDEVTYPE_HAL : (D3DDEVTYPE)(D3DDEVTYPE_HAL + 0x10); - - // Convert device desc - D3DDEVICEDESC7 DeviceDesc7; - Caps9.DeviceType = Type; - ConvertDeviceDesc(DeviceDesc7, Caps9); - - GUID deviceGUID = DeviceDesc7.deviceGUID; - LPSTR lpDescription = nullptr, lpName = nullptr; - - // For conversion - D3DDEVICEDESC D3DDRVDevDesc = {}, D3DSWDevDesc = {}; - D3DDRVDevDesc.dwSize = sizeof(D3DDEVICEDESC); - D3DSWDevDesc.dwSize = sizeof(D3DDEVICEDESC); - - char Desc[MAX_PATH] = {}; - char Name[MAX_PATH] = {}; - - switch ((DWORD)Type) - { - case D3DDEVTYPE_REF: - lpName = "RGB Emulation"; - lpDescription = "Microsoft Direct3D RGB Software Emulation"; - break; - case D3DDEVTYPE_HAL: - lpName = "Direct3D HAL"; - lpDescription = "Microsoft Direct3D Hardware acceleration through Direct3D HAL"; - break; - default: - case D3DDEVTYPE_HAL + 0x10: - lpName = "Direct3D T&L HAL"; - lpDescription = "Microsoft Direct3D Hardware Transform and Lighting acceleration capable device"; - break; - } - - strcpy_s(Desc, lpDescription); - strcpy_s(Name, lpName); - - if (DirectXVersion < 7) - { - // Get D3DSWDevDesc data (D3DDEVTYPE_REF) - ConvertDeviceDesc(D3DSWDevDesc, DeviceDesc7); - - // Get D3DDRVDevDesc data (D3DDEVTYPE_HAL) - Caps9 = entry.HAL; - Caps9.DeviceType = D3DDEVTYPE_HAL; - ConvertDeviceDesc(DeviceDesc7, Caps9); - ConvertDeviceDesc(D3DDRVDevDesc, DeviceDesc7); - - D3DDRVDevDesc.dwSize = DevSize; - D3DSWDevDesc.dwSize = DevSize; + m_IDirect3DLight* Interface = m_IDirect3DLight::CreateDirect3DLight(nullptr, this); - if (lpEnumDevicesCallback(&deviceGUID, Desc, Name, &D3DDRVDevDesc, &D3DSWDevDesc, lpUserArg) == DDENUMRET_CANCEL) - { - return D3D_OK; - } - } - else if (DirectXVersion == 7) - { - if (lpEnumDevicesCallback7(Desc, Name, &DeviceDesc7, lpUserArg) == DDENUMRET_CANCEL) - { - return D3D_OK; - } - } - } - } + *lplpDirect3DLight = (LPDIRECT3DLIGHT)Interface; return D3D_OK; } - return GetProxyInterfaceV7()->EnumDevices(lpEnumDevicesCallback7, lpUserArg); -} - -HRESULT m_IDirect3DX::CreateLight(LPDIRECT3DLIGHT * lplpDirect3DLight, LPUNKNOWN pUnkOuter) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - HRESULT hr = DDERR_GENERIC; switch (ProxyDirectXVersion) @@ -424,13 +251,33 @@ HRESULT m_IDirect3DX::CreateLight(LPDIRECT3DLIGHT * lplpDirect3DLight, LPUNKNOWN hr = GetProxyInterfaceV3()->CreateLight(lplpDirect3DLight, pUnkOuter); break; case 7: - case 9: + default: + if (lplpDirect3DLight) + { + *lplpDirect3DLight = nullptr; + } + return DDERR_GENERIC; + } + + if (SUCCEEDED(hr) && lplpDirect3DLight) { - if (!lplpDirect3DLight) + *lplpDirect3DLight = m_IDirect3DLight::CreateDirect3DLight(*lplpDirect3DLight, nullptr); + } + + return hr; +} + +HRESULT m_IDirect3DX::CreateMaterial(LPDIRECT3DMATERIAL3* lplpDirect3DMaterial, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lplpDirect3DMaterial) { return DDERR_INVALIDPARAMS; } - *lplpDirect3DLight = nullptr; + *lplpDirect3DMaterial = nullptr; // Check for device if (!ddrawParent) @@ -439,71 +286,56 @@ HRESULT m_IDirect3DX::CreateLight(LPDIRECT3DLIGHT * lplpDirect3DLight, LPUNKNOWN return DDERR_INVALIDOBJECT; } - m_IDirect3DLight* Interface = CreateDirect3DLight(nullptr, this); + m_IDirect3DMaterialX* Interface = new m_IDirect3DMaterialX(this, DirectXVersion); - *lplpDirect3DLight = (LPDIRECT3DLIGHT)Interface; + *lplpDirect3DMaterial = (LPDIRECT3DMATERIAL3)Interface->GetWrapperInterfaceX(DirectXVersion); return D3D_OK; } + + HRESULT hr = DDERR_GENERIC; + + switch (ProxyDirectXVersion) + { + case 1: + hr = GetProxyInterfaceV1()->CreateMaterial((LPDIRECT3DMATERIAL*)lplpDirect3DMaterial, pUnkOuter); + break; + case 2: + hr = GetProxyInterfaceV2()->CreateMaterial((LPDIRECT3DMATERIAL2*)lplpDirect3DMaterial, pUnkOuter); + break; + case 3: + hr = GetProxyInterfaceV3()->CreateMaterial(lplpDirect3DMaterial, pUnkOuter); + break; + case 7: default: + if (lplpDirect3DMaterial) + { + *lplpDirect3DMaterial = nullptr; + } return DDERR_GENERIC; } - if (SUCCEEDED(hr) && lplpDirect3DLight) + if (SUCCEEDED(hr) && lplpDirect3DMaterial) { - *lplpDirect3DLight = CreateDirect3DLight(*lplpDirect3DLight, nullptr); - } + m_IDirect3DMaterialX* Interface = new m_IDirect3DMaterialX((IDirect3DMaterial3*)*lplpDirect3DMaterial, DirectXVersion); - return hr; -} - -void m_IDirect3DX::AddLight(m_IDirect3DLight* lpLight) -{ - if (!lpLight) - { - return; + *lplpDirect3DMaterial = (LPDIRECT3DMATERIAL3)Interface->GetWrapperInterfaceX(DirectXVersion); } - LightList.push_back(lpLight); -} - -void m_IDirect3DX::ClearLight(m_IDirect3DLight* lpLight) -{ - // Find and remove the light from the list - auto it = std::find(LightList.begin(), LightList.end(), lpLight); - if (it != LightList.end()) - { - LightList.erase(it); - } + return hr; } -HRESULT m_IDirect3DX::CreateMaterial(LPDIRECT3DMATERIAL3 * lplpDirect3DMaterial, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) +HRESULT m_IDirect3DX::CreateViewport(LPDIRECT3DVIEWPORT3* lplpD3DViewport, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - DirectXVersion = (DirectXVersion < 3) ? DirectXVersion : 3; - - HRESULT hr = DDERR_GENERIC; - - switch (ProxyDirectXVersion) - { - case 1: - hr = GetProxyInterfaceV1()->CreateMaterial((LPDIRECT3DMATERIAL*)lplpDirect3DMaterial, pUnkOuter); - break; - case 2: - hr = GetProxyInterfaceV2()->CreateMaterial((LPDIRECT3DMATERIAL2*)lplpDirect3DMaterial, pUnkOuter); - break; - case 3: - hr = GetProxyInterfaceV3()->CreateMaterial(lplpDirect3DMaterial, pUnkOuter); - break; - case 7: - case 9: + if (Config.Dd7to9) { - if (!lplpDirect3DMaterial) + if (!lplpD3DViewport) { return DDERR_INVALIDPARAMS; } - *lplpDirect3DMaterial = nullptr; + *lplpD3DViewport = nullptr; // Check for device if (!ddrawParent) @@ -512,51 +344,12 @@ HRESULT m_IDirect3DX::CreateMaterial(LPDIRECT3DMATERIAL3 * lplpDirect3DMaterial, return DDERR_INVALIDOBJECT; } - m_IDirect3DMaterialX *Interface = new m_IDirect3DMaterialX(this, DirectXVersion); + m_IDirect3DViewportX* Interface = new m_IDirect3DViewportX(this, DirectXVersion); - *lplpDirect3DMaterial = (LPDIRECT3DMATERIAL3)Interface->GetWrapperInterfaceX(DirectXVersion); + *lplpD3DViewport = (LPDIRECT3DVIEWPORT3)Interface->GetWrapperInterfaceX(DirectXVersion); return D3D_OK; } - default: - return DDERR_GENERIC; - } - - if (SUCCEEDED(hr) && lplpDirect3DMaterial) - { - m_IDirect3DMaterialX *Interface = new m_IDirect3DMaterialX((IDirect3DMaterial3*)*lplpDirect3DMaterial, DirectXVersion); - - *lplpDirect3DMaterial = (LPDIRECT3DMATERIAL3)Interface->GetWrapperInterfaceX(DirectXVersion); - } - - return hr; -} - -void m_IDirect3DX::AddMaterial(m_IDirect3DMaterialX* lpMaterialX) -{ - if (!lpMaterialX) - { - return; - } - - MaterialList.push_back(lpMaterialX); -} - -void m_IDirect3DX::ClearMaterial(m_IDirect3DMaterialX* lpMaterialX) -{ - // Find and remove the material from the list - auto it = std::find(MaterialList.begin(), MaterialList.end(), lpMaterialX); - if (it != MaterialList.end()) - { - MaterialList.erase(it); - } -} - -HRESULT m_IDirect3DX::CreateViewport(LPDIRECT3DVIEWPORT3 * lplpD3DViewport, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - - DirectXVersion = (DirectXVersion < 3) ? DirectXVersion : 3; HRESULT hr = DDERR_GENERIC; @@ -572,34 +365,17 @@ HRESULT m_IDirect3DX::CreateViewport(LPDIRECT3DVIEWPORT3 * lplpD3DViewport, LPUN hr = GetProxyInterfaceV3()->CreateViewport(lplpD3DViewport, pUnkOuter); break; case 7: - case 9: - { - if (!lplpD3DViewport) - { - return DDERR_INVALIDPARAMS; - } - *lplpD3DViewport = nullptr; - - // Check for device - if (!ddrawParent) + default: + if (lplpD3DViewport) { - LOG_LIMIT(100, __FUNCTION__ << " Error: no ddraw parent!"); - return DDERR_INVALIDOBJECT; + *lplpD3DViewport = nullptr; } - - m_IDirect3DViewportX *Interface = new m_IDirect3DViewportX(this, DirectXVersion); - - *lplpD3DViewport = (LPDIRECT3DVIEWPORT3)Interface->GetWrapperInterfaceX(DirectXVersion); - - return D3D_OK; - } - default: return DDERR_GENERIC; } if (SUCCEEDED(hr) && lplpD3DViewport) { - m_IDirect3DViewportX *Interface = new m_IDirect3DViewportX((IDirect3DViewport3*)*lplpD3DViewport, DirectXVersion); + m_IDirect3DViewportX* Interface = new m_IDirect3DViewportX((IDirect3DViewport3*)*lplpD3DViewport, DirectXVersion); *lplpD3DViewport = (LPDIRECT3DVIEWPORT3)Interface->GetWrapperInterfaceX(DirectXVersion); } @@ -607,40 +383,11 @@ HRESULT m_IDirect3DX::CreateViewport(LPDIRECT3DVIEWPORT3 * lplpD3DViewport, LPUN return hr; } -void m_IDirect3DX::AddViewport(m_IDirect3DViewportX* lpViewportX) -{ - if (!lpViewportX) - { - return; - } - - ViewportList.push_back(lpViewportX); -} - -void m_IDirect3DX::ClearViewport(m_IDirect3DViewportX* lpViewportX) -{ - // Find and remove the viewport from the list - auto it = std::find(ViewportList.begin(), ViewportList.end(), lpViewportX); - if (it != ViewportList.end()) - { - ViewportList.erase(it); - } -} - HRESULT m_IDirect3DX::FindDevice(LPD3DFINDDEVICESEARCH lpD3DFDS, LPD3DFINDDEVICERESULT lpD3DFDR) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - switch (ProxyDirectXVersion) - { - case 1: - return GetProxyInterfaceV1()->FindDevice(lpD3DFDS, lpD3DFDR); - case 2: - return GetProxyInterfaceV2()->FindDevice(lpD3DFDS, lpD3DFDR); - case 3: - return GetProxyInterfaceV3()->FindDevice(lpD3DFDS, lpD3DFDR); - case 7: - case 9: + if (Config.Dd7to9) { if (!lpD3DFDS || !lpD3DFDR) { @@ -700,18 +447,29 @@ HRESULT m_IDirect3DX::FindDevice(LPD3DFINDDEVICESEARCH lpD3DFDS, LPD3DFINDDEVICE return DDERR_NOTFOUND; } + + switch (ProxyDirectXVersion) + { + case 1: + return GetProxyInterfaceV1()->FindDevice(lpD3DFDS, lpD3DFDR); + case 2: + return GetProxyInterfaceV2()->FindDevice(lpD3DFDS, lpD3DFDR); + case 3: + return GetProxyInterfaceV3()->FindDevice(lpD3DFDS, lpD3DFDR); + case 7: default: return DDERR_GENERIC; } } -HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS, LPDIRECT3DDEVICE7 * lplpD3DDevice, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) +// ****************************** +// IDirect3D v2 functions +// ****************************** + +HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS, LPDIRECT3DDEVICE7* lplpD3DDevice, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - REFCLSID riid = (rclsid == IID_IDirect3DRampDevice) ? IID_IDirect3DRGBDevice : (ProxyDirectXVersion != 7) ? rclsid : - (rclsid == IID_IDirect3DTnLHalDevice || rclsid == IID_IDirect3DHALDevice || rclsid == IID_IDirect3DMMXDevice || rclsid == IID_IDirect3DRGBDevice) ? rclsid : IID_IDirect3DRGBDevice; - if (Config.Dd7to9) { if (!lplpD3DDevice || !lpDDS) @@ -728,7 +486,7 @@ HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS, } // Get surfaceX - m_IDirectDrawSurfaceX *DdrawSurface3D = nullptr; + m_IDirectDrawSurfaceX* DdrawSurface3D = nullptr; lpDDS->QueryInterface(IID_GetInterfaceX, (LPVOID*)&DdrawSurface3D); // Check for Direct3D surface @@ -745,7 +503,7 @@ HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS, return DDERR_GENERIC; } - m_IDirect3DDeviceX* p_IDirect3DDeviceX = new m_IDirect3DDeviceX(ddrawParent, this, lpDDS, riid, DirectXVersion); + m_IDirect3DDeviceX* p_IDirect3DDeviceX = new m_IDirect3DDeviceX(ddrawParent, this, lpDDS, rclsid, DirectXVersion); *lplpD3DDevice = (LPDIRECT3DDEVICE7)p_IDirect3DDeviceX->GetWrapperInterfaceX(DirectXVersion); @@ -763,17 +521,24 @@ HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS, return D3D_OK; } + REFCLSID riid = (rclsid == IID_IDirect3DRampDevice) ? IID_IDirect3DRGBDevice : (ProxyDirectXVersion != 7) ? rclsid : + (rclsid == IID_IDirect3DTnLHalDevice || rclsid == IID_IDirect3DHALDevice || rclsid == IID_IDirect3DMMXDevice || rclsid == IID_IDirect3DRGBDevice) ? rclsid : IID_IDirect3DRGBDevice; + + HRESULT hr = DDERR_GENERIC; + if (lpDDS) { lpDDS->QueryInterface(IID_GetRealInterface, (LPVOID*)&lpDDS); } - HRESULT hr = DDERR_GENERIC; - switch (ProxyDirectXVersion) { case 1: default: + if (lplpD3DDevice) + { + *lplpD3DDevice = nullptr; + } return DDERR_GENERIC; case 2: hr = GetProxyInterfaceV2()->CreateDevice(riid, (LPDIRECTDRAWSURFACE)lpDDS, (LPDIRECT3DDEVICE2*)lplpD3DDevice); @@ -788,75 +553,23 @@ HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS, if (SUCCEEDED(hr) && lplpD3DDevice) { - m_IDirect3DDeviceX *Interface = new m_IDirect3DDeviceX((m_IDirect3DDevice7*)*lplpD3DDevice, DirectXVersion); + m_IDirect3DDeviceX* Interface = new m_IDirect3DDeviceX((m_IDirect3DDevice7*)*lplpD3DDevice, DirectXVersion); *lplpD3DDevice = (LPDIRECT3DDEVICE7)Interface->GetWrapperInterfaceX(DirectXVersion); - - if (Config.ConvertToDirect3D7 && ddrawParent) - { - Interface->SetDdrawParent(ddrawParent); - } } return hr; } -void m_IDirect3DX::SetD3DDevice(m_IDirect3DDeviceX* lpD3DDevice) -{ - if (!lpD3DDevice) - { - return; - } - - if (D3DDeviceInterface && D3DDeviceInterface != lpD3DDevice) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: Direct3D Device has already been created!"); - } - - D3DDeviceInterface = lpD3DDevice; -} - -void m_IDirect3DX::ClearD3DDevice(m_IDirect3DDeviceX* lpD3DDevice) -{ - if (lpD3DDevice != D3DDeviceInterface) - { - Logging::Log() << __FUNCTION__ << " Warning: released Direct3DDevice interface does not match cached one!"; - } - - if (D3DDeviceInterface && Direct3DDeviceEx.RefCount) - { - for (UINT x = 0; x < Direct3DDeviceEx.RefCount; x++) - { - if (!Release(Direct3DDeviceEx.DxVersion)) break; - } - } - - Direct3DDeviceEx = {}; - - D3DDeviceInterface = nullptr; -} +// ****************************** +// IDirect3D v3 functions +// ****************************** HRESULT m_IDirect3DX::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lpVBDesc, LPDIRECT3DVERTEXBUFFER7* lplpD3DVertexBuffer, DWORD dwFlags, LPUNKNOWN pUnkOuter, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - DirectXVersion = (DirectXVersion < 7) ? 1 : 7; - - HRESULT hr = DDERR_GENERIC; - - switch (ProxyDirectXVersion) - { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - hr = GetProxyInterfaceV3()->CreateVertexBuffer(lpVBDesc, (LPDIRECT3DVERTEXBUFFER*)lplpD3DVertexBuffer, dwFlags, pUnkOuter); - break; - case 7: - hr = GetProxyInterfaceV7()->CreateVertexBuffer(lpVBDesc, lplpD3DVertexBuffer, dwFlags); - break; - case 9: + if (Config.Dd7to9) { if (!lplpD3DVertexBuffer || !lpVBDesc) { @@ -884,7 +597,7 @@ HRESULT m_IDirect3DX::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lpVBDesc, LPDIREC return DDERR_INVALIDOBJECT; } - m_IDirect3DVertexBufferX *Interface = new m_IDirect3DVertexBufferX(ddrawParent, this, lpVBDesc, DirectXVersion); + m_IDirect3DVertexBufferX* Interface = new m_IDirect3DVertexBufferX(ddrawParent, this, lpVBDesc, DirectXVersion); if (DirectXVersion > 3) { @@ -906,11 +619,30 @@ HRESULT m_IDirect3DX::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lpVBDesc, LPDIREC return D3D_OK; } + + HRESULT hr = DDERR_GENERIC; + + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + if (lplpD3DVertexBuffer) + { + *lplpD3DVertexBuffer = nullptr; + } + return DDERR_GENERIC; + case 3: + hr = GetProxyInterfaceV3()->CreateVertexBuffer(lpVBDesc, (LPDIRECT3DVERTEXBUFFER*)lplpD3DVertexBuffer, dwFlags, pUnkOuter); + break; + case 7: + hr = GetProxyInterfaceV7()->CreateVertexBuffer(lpVBDesc, lplpD3DVertexBuffer, dwFlags); + break; } if (SUCCEEDED(hr) && lplpD3DVertexBuffer) { - m_IDirect3DVertexBufferX *Interface = new m_IDirect3DVertexBufferX((m_IDirect3DVertexBuffer7*)*lplpD3DVertexBuffer, DirectXVersion); + m_IDirect3DVertexBufferX* Interface = new m_IDirect3DVertexBufferX((m_IDirect3DVertexBuffer7*)*lplpD3DVertexBuffer, DirectXVersion); *lplpD3DVertexBuffer = (LPDIRECT3DVERTEXBUFFER7)Interface->GetWrapperInterfaceX(DirectXVersion); } @@ -918,48 +650,12 @@ HRESULT m_IDirect3DX::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lpVBDesc, LPDIREC return hr; } -void m_IDirect3DX::AddVertexBuffer(m_IDirect3DVertexBufferX* lpVertexBufferX) -{ - if (!lpVertexBufferX) - { - return; - } - - VertexBufferList.push_back({ lpVertexBufferX, 0, 0 }); -} - -void m_IDirect3DX::ClearVertexBuffer(m_IDirect3DVertexBufferX* lpVertexBufferX) -{ - // Find and remove the buffer from the list - auto it = std::find_if(VertexBufferList.begin(), VertexBufferList.end(), - [lpVertexBufferX](auto entry) { - return entry.Interface == lpVertexBufferX; - }); - if (it != VertexBufferList.end()) - { - if (it->RefCount == 1) - { - Release(it->DxVersion); - } - VertexBufferList.erase(it); - } -} - HRESULT m_IDirect3DX::EnumZBufferFormats(REFCLSID riidDevice, LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallback, LPVOID lpContext) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - switch (ProxyDirectXVersion) + if (Config.Dd7to9) { - case 1: - case 2: - default: - return DDERR_GENERIC; - case 3: - return GetProxyInterfaceV3()->EnumZBufferFormats(riidDevice, lpEnumCallback, lpContext); - case 7: - return GetProxyInterfaceV7()->EnumZBufferFormats(riidDevice, lpEnumCallback, lpContext); - case 9: if (!lpEnumCallback) { return DDERR_INVALIDPARAMS; @@ -973,7 +669,7 @@ HRESULT m_IDirect3DX::EnumZBufferFormats(REFCLSID riidDevice, LPD3DENUMPIXELFORM } // Get d3d9Object - IDirect3D9 *d3d9Object = ddrawParent->GetDirectD9Object(); + IDirect3D9* d3d9Object = ddrawParent->GetDirectD9Object(); if (riidDevice == IID_IDirect3DRGBDevice || riidDevice == IID_IDirect3DMMXDevice || riidDevice == IID_IDirect3DRefDevice || riidDevice == IID_IDirect3DHALDevice || riidDevice == IID_IDirect3DTnLHalDevice) @@ -1042,11 +738,29 @@ HRESULT m_IDirect3DX::EnumZBufferFormats(REFCLSID riidDevice, LPD3DENUMPIXELFORM return DDERR_NOZBUFFERHW; } } -} -HRESULT m_IDirect3DX::EvictManagedTextures() -{ - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + switch (ProxyDirectXVersion) + { + case 1: + case 2: + default: + return DDERR_GENERIC; + case 3: + return GetProxyInterfaceV3()->EnumZBufferFormats(riidDevice, lpEnumCallback, lpContext); + case 7: + return GetProxyInterfaceV7()->EnumZBufferFormats(riidDevice, lpEnumCallback, lpContext); + } +} + +HRESULT m_IDirect3DX::EvictManagedTextures() +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + // Textures are loaded as managed in Direct3D9, so there is no need to manualy evict the texture + return D3D_OK; + } switch (ProxyDirectXVersion) { @@ -1058,18 +772,129 @@ HRESULT m_IDirect3DX::EvictManagedTextures() return GetProxyInterfaceV3()->EvictManagedTextures(); case 7: return GetProxyInterfaceV7()->EvictManagedTextures(); - case 9: - // Textures are loaded as managed in Direct3D9, so there is no need to manualy evict the texture + } +} + +// ****************************** +// IDirect3D v7 functions +// ****************************** + +HRESULT m_IDirect3DX::EnumDevices7(LPD3DENUMDEVICESCALLBACK7 lpEnumDevicesCallback7, LPVOID lpUserArg, DWORD DirectXVersion) +{ + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + + if (Config.Dd7to9) + { + if (!lpEnumDevicesCallback7) + { + return DDERR_INVALIDPARAMS; + } + + // Conversion callback + LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback = (LPD3DENUMDEVICESCALLBACK)lpEnumDevicesCallback7; + + // Update Cap9 cache + GetCap9Cache(); + + // Check cache + if (Cap9Cache.empty()) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: could not get Cap9 cache!"); + return DDERR_INVALIDOBJECT; + } + + DWORD DevSize = (DirectXVersion == 1) ? D3DDEVICEDESC1_SIZE : + (DirectXVersion == 2) ? D3DDEVICEDESC5_SIZE : + (DirectXVersion == 3) ? D3DDEVICEDESC6_SIZE : sizeof(D3DDEVICEDESC); + + // Loop through all adapters + for (auto& entry : Cap9Cache) + { + for (int x = 0; x < 3; x++) + { + // Get Device Caps + D3DCAPS9 Caps9 = (x == 0) ? entry.REF : entry.HAL; + D3DDEVTYPE Type = (x == 0) ? D3DDEVTYPE_REF : (x == 1) ? D3DDEVTYPE_HAL : (D3DDEVTYPE)(D3DDEVTYPE_HAL + 0x10); + + // Convert device desc + D3DDEVICEDESC7 DeviceDesc7; + Caps9.DeviceType = Type; + ConvertDeviceDesc(DeviceDesc7, Caps9); + + GUID deviceGUID = DeviceDesc7.deviceGUID; + LPSTR lpDescription = nullptr, lpName = nullptr; + + // For conversion + D3DDEVICEDESC D3DDRVDevDesc = {}, D3DSWDevDesc = {}; + D3DDRVDevDesc.dwSize = sizeof(D3DDEVICEDESC); + D3DSWDevDesc.dwSize = sizeof(D3DDEVICEDESC); + + char Desc[MAX_PATH] = {}; + char Name[MAX_PATH] = {}; + + switch ((DWORD)Type) + { + case D3DDEVTYPE_REF: + lpName = "RGB Emulation"; + lpDescription = "Microsoft Direct3D RGB Software Emulation"; + break; + case D3DDEVTYPE_HAL: + lpName = "Direct3D HAL"; + lpDescription = "Microsoft Direct3D Hardware acceleration through Direct3D HAL"; + break; + default: + case D3DDEVTYPE_HAL + 0x10: + lpName = "Direct3D T&L HAL"; + lpDescription = "Microsoft Direct3D Hardware Transform and Lighting acceleration capable device"; + break; + } + + strcpy_s(Desc, lpDescription); + strcpy_s(Name, lpName); + + if (DirectXVersion < 7) + { + // Get D3DSWDevDesc data (D3DDEVTYPE_REF) + ConvertDeviceDesc(D3DSWDevDesc, DeviceDesc7); + + // Get D3DDRVDevDesc data (D3DDEVTYPE_HAL) + Caps9 = entry.HAL; + Caps9.DeviceType = D3DDEVTYPE_HAL; + ConvertDeviceDesc(DeviceDesc7, Caps9); + ConvertDeviceDesc(D3DDRVDevDesc, DeviceDesc7); + + D3DDRVDevDesc.dwSize = DevSize; + D3DSWDevDesc.dwSize = DevSize; + + if (lpEnumDevicesCallback(&deviceGUID, Desc, Name, &D3DDRVDevDesc, &D3DSWDevDesc, lpUserArg) == DDENUMRET_CANCEL) + { + return D3D_OK; + } + } + else if (DirectXVersion == 7) + { + if (lpEnumDevicesCallback7(Desc, Name, &DeviceDesc7, lpUserArg) == DDENUMRET_CANCEL) + { + return D3D_OK; + } + } + } + } + return D3D_OK; } + + return GetProxyInterfaceV7()->EnumDevices(lpEnumDevicesCallback7, lpUserArg); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** -void m_IDirect3DX::InitInterface() +void m_IDirect3DX::InitInterface(DWORD DirectXVersion) { + ScopedDDCriticalSection ThreadLockDD; + if (D3DDeviceInterface) { D3DDeviceInterface->SetD3D(this); @@ -1082,6 +907,8 @@ void m_IDirect3DX::InitInterface() return; } + AddRef(DirectXVersion); + // Get Cap9 cache GetCap9Cache(); } @@ -1093,6 +920,8 @@ void m_IDirect3DX::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (D3DDeviceInterface) { D3DDeviceInterface->ClearD3D(this); @@ -1129,6 +958,185 @@ void m_IDirect3DX::ReleaseInterface() } } +void* m_IDirect3DX::GetWrapperInterfaceX(DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 0: + if (WrapperInterface7) return WrapperInterface7; + if (WrapperInterface3) return WrapperInterface3; + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECT3D)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECT3D2)ProxyInterface, this); + case 3: + return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECT3D3)ProxyInterface, this); + case 7: + return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECT3D7)ProxyInterface, this); + } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} + +void m_IDirect3DX::GetCap9Cache() +{ + // Check for device + if (ddrawParent) + { + // Get d3d9Object + IDirect3D9* d3d9Object = ddrawParent->GetDirectD9Object(); + if (d3d9Object) + { + UINT AdapterCount = d3d9Object->GetAdapterCount(); + if (AdapterCount) + { + Cap9Cache.clear(); + + // Loop through all adapters + for (UINT i = 0; i < AdapterCount; i++) + { + // Get Device Caps + DUALCAP9 DCaps9; + if (SUCCEEDED(d3d9Object->GetDeviceCaps(i, D3DDEVTYPE_REF, &DCaps9.REF)) && SUCCEEDED(d3d9Object->GetDeviceCaps(i, D3DDEVTYPE_HAL, &DCaps9.HAL))) + { + Cap9Cache.push_back(DCaps9); + } + } + } + } + } +} + +void m_IDirect3DX::AddLight(m_IDirect3DLight* lpLight) +{ + if (!lpLight) + { + return; + } + + LightList.push_back(lpLight); +} + +void m_IDirect3DX::ClearLight(m_IDirect3DLight* lpLight) +{ + // Find and remove the light from the list + auto it = std::find(LightList.begin(), LightList.end(), lpLight); + if (it != LightList.end()) + { + LightList.erase(it); + } +} + +void m_IDirect3DX::AddMaterial(m_IDirect3DMaterialX* lpMaterialX) +{ + if (!lpMaterialX) + { + return; + } + + MaterialList.push_back(lpMaterialX); +} + +void m_IDirect3DX::ClearMaterial(m_IDirect3DMaterialX* lpMaterialX) +{ + // Find and remove the material from the list + auto it = std::find(MaterialList.begin(), MaterialList.end(), lpMaterialX); + if (it != MaterialList.end()) + { + MaterialList.erase(it); + } +} + +void m_IDirect3DX::AddViewport(m_IDirect3DViewportX* lpViewportX) +{ + if (!lpViewportX) + { + return; + } + + ViewportList.push_back(lpViewportX); +} + +void m_IDirect3DX::ClearViewport(m_IDirect3DViewportX* lpViewportX) +{ + // Find and remove the viewport from the list + auto it = std::find(ViewportList.begin(), ViewportList.end(), lpViewportX); + if (it != ViewportList.end()) + { + ViewportList.erase(it); + } +} + +void m_IDirect3DX::SetD3DDevice(m_IDirect3DDeviceX* lpD3DDevice) +{ + if (!lpD3DDevice) + { + return; + } + + if (D3DDeviceInterface && D3DDeviceInterface != lpD3DDevice) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: Direct3D Device has already been created!"); + } + + D3DDeviceInterface = lpD3DDevice; +} + +void m_IDirect3DX::ClearD3DDevice(m_IDirect3DDeviceX* lpD3DDevice) +{ + if (lpD3DDevice != D3DDeviceInterface) + { + Logging::Log() << __FUNCTION__ << " Warning: released Direct3DDevice interface does not match cached one!"; + } + + m_IDirect3DDeviceX* pD3DDevice = D3DDeviceInterface; + D3DDeviceInterface = nullptr; + + DWORD RefCount = Direct3DDeviceEx.RefCount; + DWORD DxVersion = Direct3DDeviceEx.DxVersion; + Direct3DDeviceEx = {}; // Clear before releasing + + if (pD3DDevice && RefCount) + { + for (UINT x = 0; x < RefCount; x++) + { + Release(DxVersion); + } + } +} + +void m_IDirect3DX::AddVertexBuffer(m_IDirect3DVertexBufferX* lpVertexBufferX) +{ + if (!lpVertexBufferX) + { + return; + } + + VertexBufferList.push_back({ lpVertexBufferX, 0, 0 }); +} + +void m_IDirect3DX::ClearVertexBuffer(m_IDirect3DVertexBufferX* lpVertexBufferX) +{ + // Find and remove the buffer from the list + auto it = std::find_if(VertexBufferList.begin(), VertexBufferList.end(), + [lpVertexBufferX](auto entry) { + return entry.Interface == lpVertexBufferX; + }); + if (it != VertexBufferList.end()) + { + DWORD RefCount = it->RefCount; + DWORD DxVersion = it->DxVersion; + VertexBufferList.erase(it); // Erase from list before releasing + if (RefCount == 1) + { + Release(DxVersion); + } + } +} + void m_IDirect3DX::ResolutionHack() { if (Config.DdrawResolutionHack) diff --git a/ddraw/IDirect3DX.h b/ddraw/IDirect3DX.h index e8eb7029..5602064e 100644 --- a/ddraw/IDirect3DX.h +++ b/ddraw/IDirect3DX.h @@ -9,15 +9,17 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject ULONG RefCount2 = 0; ULONG RefCount3 = 0; ULONG RefCount7 = 0; - m_IDirectDrawX *ddrawParent = nullptr; - DWORD DDrawVersion = 0; - // Store d3d version wrappers + // Store version wrappers m_IDirect3D *WrapperInterface = nullptr; m_IDirect3D2 *WrapperInterface2 = nullptr; m_IDirect3D3 *WrapperInterface3 = nullptr; m_IDirect3D7 *WrapperInterface7 = nullptr; + // Convert to Direct3D9 + m_IDirectDrawX* ddrawParent = nullptr; + DWORD DDrawVersion = 0; + // Device interface pointers struct { m_IDirect3DDeviceX* Interface = nullptr; @@ -50,6 +52,10 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject // Viewport array std::vector ViewportList; + // Helper functions + void GetCap9Cache(); + void ResolutionHack(); + // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { @@ -70,18 +76,14 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject inline IDirect3D3 *GetProxyInterfaceV3() { return (IDirect3D3 *)ProxyInterface; } inline IDirect3D7 *GetProxyInterfaceV7() { return ProxyInterface; } - // Helper functions - void GetCap9Cache(); - void ResolutionHack(); - // Interface initialization functions - void InitInterface(); + void InitInterface(DWORD DirectXVersion); void ReleaseInterface(); public: m_IDirect3DX(IDirect3D7 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -96,7 +98,7 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject Logging::Log() << __FUNCTION__ << " (" << this << ") Warning: created from non-dd7to9 interface!"; } - InitInterface(); + InitInterface(DirectXVersion); } m_IDirect3DX(m_IDirectDrawX *lpDdraw, DWORD DirectXVersion, DWORD DXDrawVersion) : ddrawParent(lpDdraw), DDrawVersion(DXDrawVersion) { @@ -104,7 +106,7 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject LOG_LIMIT(3, "Creating interface " << __FUNCTION__ << " (" << this << ")" << " converting interface from v" << DirectXVersion << " to v" << ProxyDirectXVersion); - InitInterface(); + InitInterface(DirectXVersion); } ~m_IDirect3DX() { @@ -134,7 +136,7 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject // Helper functions HRESULT QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion); void* GetWrapperInterfaceX(DWORD DirectXVersion); - inline m_IDirect3DDeviceX** GetD3DDevice() { return &D3DDeviceInterface; } + m_IDirect3DDeviceX** GetD3DDevice() { return &D3DDeviceInterface; } void SetD3DDevice(m_IDirect3DDeviceX* lpD3DDevice); void ClearD3DDevice(m_IDirect3DDeviceX* lpD3DDevice); void AddLight(m_IDirect3DLight* lpLight); @@ -149,6 +151,6 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject ULONG Release(DWORD DirectXVersion); // Functions handling the ddraw parent interface - inline void SetDdrawParent(m_IDirectDrawX* ddraw) { ddrawParent = ddraw; GetCap9Cache(); } - inline void ClearDdraw() { ddrawParent = nullptr; } + void SetDdrawParent(m_IDirectDrawX* ddraw) { ddrawParent = ddraw; GetCap9Cache(); } + void ClearDdraw() { ddrawParent = nullptr; } }; diff --git a/ddraw/IDirectDrawClipper.cpp b/ddraw/IDirectDrawClipper.cpp index 894125ca..45698565 100644 --- a/ddraw/IDirectDrawClipper.cpp +++ b/ddraw/IDirectDrawClipper.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -18,47 +18,13 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirectDrawClipper* WrapperInterfaceBackup = nullptr; } -inline static void SaveInterfaceAddress(m_IDirectDrawClipper* Interface, m_IDirectDrawClipper*& InterfaceBackup) -{ - if (Interface) - { - Interface->SetProxy(nullptr, nullptr, 0); - if (InterfaceBackup) - { - InterfaceBackup->DeleteMe(); - InterfaceBackup = nullptr; - } - InterfaceBackup = Interface; - } -} - -m_IDirectDrawClipper* CreateDirectDrawClipper(IDirectDrawClipper* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags) -{ - m_IDirectDrawClipper* Interface = nullptr; - if (WrapperInterfaceBackup) - { - Interface = WrapperInterfaceBackup; - WrapperInterfaceBackup = nullptr; - Interface->SetProxy(aOriginal, NewParent, dwFlags); - } - else - { - if (aOriginal) - { - Interface = new m_IDirectDrawClipper(aOriginal); - } - else - { - Interface = new m_IDirectDrawClipper(NewParent, dwFlags); - } - } - return Interface; -} +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawClipper::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -97,7 +63,7 @@ ULONG m_IDirectDrawClipper::AddRef() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { return InterlockedIncrement(&RefCount); } @@ -109,17 +75,20 @@ ULONG m_IDirectDrawClipper::Release() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - ULONG ref; - - if (!ProxyInterface) - { - ref = InterlockedDecrement(&RefCount); - } - else + if (Config.Dd7to9) { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + SaveInterfaceAddress(this, WrapperInterfaceBackup); + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { SaveInterfaceAddress(this, WrapperInterfaceBackup); @@ -128,11 +97,15 @@ ULONG m_IDirectDrawClipper::Release() return ref; } +// ****************************** +// IDirectDrawClipper functions +// ****************************** + HRESULT m_IDirectDrawClipper::GetClipList(LPRECT lpRect, LPRGNDATA lpClipList, LPDWORD lpdwSize) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpdwSize) { @@ -232,7 +205,7 @@ HRESULT m_IDirectDrawClipper::GetHWnd(HWND FAR * lphWnd) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lphWnd) { @@ -256,7 +229,7 @@ HRESULT m_IDirectDrawClipper::Initialize(LPDIRECTDRAW lpDD, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // Returns D3D_OK if successful, otherwise it returns an error. return D3D_OK; @@ -274,7 +247,7 @@ HRESULT m_IDirectDrawClipper::IsClipListChanged(BOOL FAR * lpbChanged) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpbChanged) { @@ -302,7 +275,7 @@ HRESULT m_IDirectDrawClipper::SetClipList(LPRGNDATA lpClipList, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { // You cannot set the clip list if a window handle is already associated with the DirectDrawClipper object. if (cliphWnd) @@ -338,7 +311,7 @@ HRESULT m_IDirectDrawClipper::SetHWnd(DWORD dwFlags, HWND hWnd) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { cliphWnd = hWnd; @@ -350,12 +323,14 @@ HRESULT m_IDirectDrawClipper::SetHWnd(DWORD dwFlags, HWND hWnd) return ProxyInterface->SetHWnd(dwFlags, hWnd); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** void m_IDirectDrawClipper::InitInterface(DWORD dwFlags) { + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->AddClipper(this); @@ -375,10 +350,35 @@ void m_IDirectDrawClipper::ReleaseInterface() return; } - ClearBaseClipper(this); + ScopedDDCriticalSection ThreadLockDD; + + m_IDirectDrawX::ClearBaseClipper(this); if (ddrawParent) { ddrawParent->ClearClipper(this); } } + +m_IDirectDrawClipper* m_IDirectDrawClipper::CreateDirectDrawClipper(IDirectDrawClipper* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags) +{ + m_IDirectDrawClipper* Interface = nullptr; + if (WrapperInterfaceBackup) + { + Interface = WrapperInterfaceBackup; + WrapperInterfaceBackup = nullptr; + Interface->SetProxy(aOriginal, NewParent, dwFlags); + } + else + { + if (aOriginal) + { + Interface = new m_IDirectDrawClipper(aOriginal); + } + else + { + Interface = new m_IDirectDrawClipper(NewParent, dwFlags); + } + } + return Interface; +} diff --git a/ddraw/IDirectDrawClipper.h b/ddraw/IDirectDrawClipper.h index 9649024a..e13449be 100644 --- a/ddraw/IDirectDrawClipper.h +++ b/ddraw/IDirectDrawClipper.h @@ -1,22 +1,20 @@ #pragma once -m_IDirectDrawClipper* CreateDirectDrawClipper(IDirectDrawClipper* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags); - class m_IDirectDrawClipper : public IDirectDrawClipper, public AddressLookupTableDdrawObject { private: IDirectDrawClipper *ProxyInterface = nullptr; - REFIID WrapperID = IID_IDirectDrawClipper; ULONG RefCount = 1; + REFIID WrapperID = IID_IDirectDrawClipper; + + // Convert to Direct3D9 + m_IDirectDrawX* ddrawParent = nullptr; DWORD clipperCaps = 0; // Clipper flags HWND cliphWnd = nullptr; std::vector ClipList; bool IsClipListSet = false; bool IsClipListChangedFlag = false; - // Convert to Direct3D9 - m_IDirectDrawX* ddrawParent = nullptr; - // Interface initialization functions void InitInterface(DWORD dwFlags); void ReleaseInterface(); @@ -87,4 +85,5 @@ class m_IDirectDrawClipper : public IDirectDrawClipper, public AddressLookupTabl // Functions handling the ddraw parent interface void SetDdrawParent(m_IDirectDrawX* ddraw) { ddrawParent = ddraw; } void ClearDdraw() { ddrawParent = nullptr; } + static m_IDirectDrawClipper* CreateDirectDrawClipper(IDirectDrawClipper* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags); }; diff --git a/ddraw/IDirectDrawColorControl.cpp b/ddraw/IDirectDrawColorControl.cpp index 50836738..b9a4cb3b 100644 --- a/ddraw/IDirectDrawColorControl.cpp +++ b/ddraw/IDirectDrawColorControl.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,47 +16,13 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirectDrawColorControl* WrapperInterfaceBackup = nullptr; } -inline static void SaveInterfaceAddress(m_IDirectDrawColorControl* Interface, m_IDirectDrawColorControl*& InterfaceBackup) -{ - if (Interface) - { - Interface->SetProxy(nullptr, nullptr); - if (InterfaceBackup) - { - InterfaceBackup->DeleteMe(); - InterfaceBackup = nullptr; - } - InterfaceBackup = Interface; - } -} - -m_IDirectDrawColorControl* CreateDirectDrawColorControl(IDirectDrawColorControl* aOriginal, m_IDirectDrawX* NewParent) -{ - m_IDirectDrawColorControl* Interface = nullptr; - if (WrapperInterfaceBackup) - { - Interface = WrapperInterfaceBackup; - WrapperInterfaceBackup = nullptr; - Interface->SetProxy(aOriginal, NewParent); - } - else - { - if (aOriginal) - { - Interface = new m_IDirectDrawColorControl(aOriginal); - } - else - { - Interface = new m_IDirectDrawColorControl(NewParent); - } - } - return Interface; -} +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawColorControl::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -109,7 +75,7 @@ ULONG m_IDirectDrawColorControl::AddRef() return 0; } - if (!ProxyInterface) + if (Config.Dd7to9) { return InterlockedIncrement(&RefCount); } @@ -126,17 +92,20 @@ ULONG m_IDirectDrawColorControl::Release() return 0; } - ULONG ref; - - if (!ProxyInterface) + if (Config.Dd7to9) { - ref = InterlockedDecrement(&RefCount); - } - else - { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + SaveInterfaceAddress(this, WrapperInterfaceBackup); + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { SaveInterfaceAddress(this, WrapperInterfaceBackup); @@ -145,6 +114,10 @@ ULONG m_IDirectDrawColorControl::Release() return ref; } +// ****************************** +// IDirectDrawColorControl functions +// ****************************** + HRESULT m_IDirectDrawColorControl::GetColorControls(LPDDCOLORCONTROL lpColorControl) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -154,7 +127,7 @@ HRESULT m_IDirectDrawColorControl::GetColorControls(LPDDCOLORCONTROL lpColorCont return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpColorControl) { @@ -178,7 +151,7 @@ HRESULT m_IDirectDrawColorControl::SetColorControls(LPDDCOLORCONTROL lpColorCont return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpColorControl) { @@ -190,17 +163,15 @@ HRESULT m_IDirectDrawColorControl::SetColorControls(LPDDCOLORCONTROL lpColorCont // Present new color setting if (ddrawParent) { - ddrawParent->SetVsync(); + ScopedDDCriticalSection ThreadLockDD; - SetCriticalSection(); + ddrawParent->SetVsync(); m_IDirectDrawSurfaceX *lpDDSrcSurfaceX = ddrawParent->GetPrimarySurface(); if (lpDDSrcSurfaceX) { lpDDSrcSurfaceX->PresentSurface(false); } - - ReleaseCriticalSection(); } return DD_OK; @@ -209,12 +180,14 @@ HRESULT m_IDirectDrawColorControl::SetColorControls(LPDDCOLORCONTROL lpColorCont return ProxyInterface->SetColorControls(lpColorControl); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** void m_IDirectDrawColorControl::InitInterface() { + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->SetColorControl(this); @@ -239,8 +212,33 @@ void m_IDirectDrawColorControl::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->ClearColorControl(this); } } + +m_IDirectDrawColorControl* m_IDirectDrawColorControl::CreateDirectDrawColorControl(IDirectDrawColorControl* aOriginal, m_IDirectDrawX* NewParent) +{ + m_IDirectDrawColorControl* Interface = nullptr; + if (WrapperInterfaceBackup) + { + Interface = WrapperInterfaceBackup; + WrapperInterfaceBackup = nullptr; + Interface->SetProxy(aOriginal, NewParent); + } + else + { + if (aOriginal) + { + Interface = new m_IDirectDrawColorControl(aOriginal); + } + else + { + Interface = new m_IDirectDrawColorControl(NewParent); + } + } + return Interface; +} diff --git a/ddraw/IDirectDrawColorControl.h b/ddraw/IDirectDrawColorControl.h index a42fbcba..d4f13a03 100644 --- a/ddraw/IDirectDrawColorControl.h +++ b/ddraw/IDirectDrawColorControl.h @@ -1,13 +1,11 @@ #pragma once -m_IDirectDrawColorControl* CreateDirectDrawColorControl(IDirectDrawColorControl* aOriginal, m_IDirectDrawX* NewParent); - class m_IDirectDrawColorControl : public IDirectDrawColorControl, public AddressLookupTableDdrawObject { private: IDirectDrawColorControl *ProxyInterface = nullptr; - REFIID WrapperID = IID_IDirectDrawColorControl; ULONG RefCount = 1; + REFIID WrapperID = IID_IDirectDrawColorControl; // Convert to Direct3D9 m_IDirectDrawX *ddrawParent = nullptr; @@ -78,4 +76,6 @@ class m_IDirectDrawColorControl : public IDirectDrawColorControl, public Address // Functions handling the ddraw parent interface void ClearDdraw() { ddrawParent = nullptr; } + static m_IDirectDrawColorControl* CreateDirectDrawColorControl(IDirectDrawColorControl* aOriginal, m_IDirectDrawX* NewParent); + }; diff --git a/ddraw/IDirectDrawFactory.cpp b/ddraw/IDirectDrawFactory.cpp index d1914e5c..f2aac27d 100644 --- a/ddraw/IDirectDrawFactory.cpp +++ b/ddraw/IDirectDrawFactory.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,9 +16,9 @@ #include "ddraw.h" -/************************/ -/*** IUnknown methods ***/ -/************************/ +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawFactory::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -52,17 +52,20 @@ ULONG m_IDirectDrawFactory::Release() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - ULONG ref; - - if (!ProxyInterface) - { - ref = InterlockedDecrement(&RefCount); - } - else + if (Config.Dd7to9) { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + delete this; + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { delete this; @@ -71,15 +74,15 @@ ULONG m_IDirectDrawFactory::Release() return ref; } -/**********************************/ -/*** IDirectDrawFactory methods ***/ -/**********************************/ +// ****************************** +// IDirectDrawFactory functions +// ****************************** HRESULT m_IDirectDrawFactory::CreateDirectDraw(GUID * pGUID, HWND hWnd, DWORD dwCoopLevelFlags, DWORD dwReserved, IUnknown * pUnkOuter, IDirectDraw * * ppDirectDraw) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { HRESULT hr = dd_DirectDrawCreate(pGUID, ppDirectDraw, pUnkOuter); @@ -116,7 +119,7 @@ HRESULT m_IDirectDrawFactory::DirectDrawEnumerateA(LPDDENUMCALLBACKA lpCallback, { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { return dd_DirectDrawEnumerateA(lpCallback, lpContext); } @@ -128,7 +131,7 @@ HRESULT m_IDirectDrawFactory::DirectDrawEnumerateW(LPDDENUMCALLBACKW lpCallback, { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!ProxyInterface) + if (Config.Dd7to9) { return dd_DirectDrawEnumerateW(lpCallback, lpContext); } diff --git a/ddraw/IDirectDrawFactory.h b/ddraw/IDirectDrawFactory.h index bab323eb..e9347c29 100644 --- a/ddraw/IDirectDrawFactory.h +++ b/ddraw/IDirectDrawFactory.h @@ -4,8 +4,8 @@ class m_IDirectDrawFactory : public IDirectDrawFactory { private: IDirectDrawFactory *ProxyInterface = nullptr; - REFIID WrapperID = IID_IDirectDrawFactory; ULONG RefCount = 1; + REFIID WrapperID = IID_IDirectDrawFactory; public: m_IDirectDrawFactory(IDirectDrawFactory *aOriginal) : ProxyInterface(aOriginal) diff --git a/ddraw/IDirectDrawGammaControl.cpp b/ddraw/IDirectDrawGammaControl.cpp index 88e7c377..01f5706b 100644 --- a/ddraw/IDirectDrawGammaControl.cpp +++ b/ddraw/IDirectDrawGammaControl.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -16,47 +16,13 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirectDrawGammaControl* WrapperInterfaceBackup = nullptr; } -inline static void SaveInterfaceAddress(m_IDirectDrawGammaControl* Interface, m_IDirectDrawGammaControl*& InterfaceBackup) -{ - if (Interface) - { - Interface->SetProxy(nullptr, nullptr); - if (InterfaceBackup) - { - InterfaceBackup->DeleteMe(); - InterfaceBackup = nullptr; - } - InterfaceBackup = Interface; - } -} - -m_IDirectDrawGammaControl* CreateDirectDrawGammaControl(IDirectDrawGammaControl* aOriginal, m_IDirectDrawX* NewParent) -{ - m_IDirectDrawGammaControl* Interface = nullptr; - if (WrapperInterfaceBackup) - { - Interface = WrapperInterfaceBackup; - WrapperInterfaceBackup = nullptr; - Interface->SetProxy(aOriginal, NewParent); - } - else - { - if (aOriginal) - { - Interface = new m_IDirectDrawGammaControl(aOriginal); - } - else - { - Interface = new m_IDirectDrawGammaControl(NewParent); - } - } - return Interface; -} +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawGammaControl::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -109,7 +75,7 @@ ULONG m_IDirectDrawGammaControl::AddRef() return 0; } - if (!ProxyInterface) + if (Config.Dd7to9) { return InterlockedIncrement(&RefCount); } @@ -126,17 +92,20 @@ ULONG m_IDirectDrawGammaControl::Release() return 0; } - ULONG ref; - - if (!ProxyInterface) - { - ref = InterlockedDecrement(&RefCount); - } - else + if (Config.Dd7to9) { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + SaveInterfaceAddress(this, WrapperInterfaceBackup); + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { SaveInterfaceAddress(this, WrapperInterfaceBackup); @@ -145,6 +114,10 @@ ULONG m_IDirectDrawGammaControl::Release() return ref; } +// ****************************** +// IDirectDrawGammaControl functions +// ****************************** + HRESULT m_IDirectDrawGammaControl::GetGammaRamp(DWORD dwFlags, LPDDGAMMARAMP lpRampData) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -154,7 +127,7 @@ HRESULT m_IDirectDrawGammaControl::GetGammaRamp(DWORD dwFlags, LPDDGAMMARAMP lpR return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!(dwFlags == D3DSGR_NO_CALIBRATION || dwFlags == DDSGR_CALIBRATE) || !lpRampData) { @@ -181,7 +154,7 @@ HRESULT m_IDirectDrawGammaControl::SetGammaRamp(DWORD dwFlags, LPDDGAMMARAMP lpR return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!(dwFlags == D3DSGR_NO_CALIBRATION || dwFlags == DDSGR_CALIBRATE) || !lpRampData) { @@ -199,12 +172,14 @@ HRESULT m_IDirectDrawGammaControl::SetGammaRamp(DWORD dwFlags, LPDDGAMMARAMP lpR return ProxyInterface->SetGammaRamp(dwFlags, lpRampData); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** void m_IDirectDrawGammaControl::InitInterface() { + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->SetGammaControl(this); @@ -218,8 +193,33 @@ void m_IDirectDrawGammaControl::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->ClearGammaControl(this); } } + +m_IDirectDrawGammaControl* m_IDirectDrawGammaControl::CreateDirectDrawGammaControl(IDirectDrawGammaControl* aOriginal, m_IDirectDrawX* NewParent) +{ + m_IDirectDrawGammaControl* Interface = nullptr; + if (WrapperInterfaceBackup) + { + Interface = WrapperInterfaceBackup; + WrapperInterfaceBackup = nullptr; + Interface->SetProxy(aOriginal, NewParent); + } + else + { + if (aOriginal) + { + Interface = new m_IDirectDrawGammaControl(aOriginal); + } + else + { + Interface = new m_IDirectDrawGammaControl(NewParent); + } + } + return Interface; +} diff --git a/ddraw/IDirectDrawGammaControl.h b/ddraw/IDirectDrawGammaControl.h index 8e00d270..ddb411ea 100644 --- a/ddraw/IDirectDrawGammaControl.h +++ b/ddraw/IDirectDrawGammaControl.h @@ -1,13 +1,11 @@ #pragma once -m_IDirectDrawGammaControl* CreateDirectDrawGammaControl(IDirectDrawGammaControl* aOriginal, m_IDirectDrawX* NewParent); - class m_IDirectDrawGammaControl : public IDirectDrawGammaControl, public AddressLookupTableDdrawObject { private: IDirectDrawGammaControl *ProxyInterface = nullptr; - REFIID WrapperID = IID_IDirectDrawGammaControl; ULONG RefCount = 1; + REFIID WrapperID = IID_IDirectDrawGammaControl; // Convert to Direct3D9 m_IDirectDrawX *ddrawParent = nullptr; @@ -78,4 +76,5 @@ class m_IDirectDrawGammaControl : public IDirectDrawGammaControl, public Address // Functions handling the ddraw parent interface void SetDdrawParent(m_IDirectDrawX *ddraw) { ddrawParent = ddraw; } void ClearDdraw() { ddrawParent = nullptr; } + static m_IDirectDrawGammaControl* CreateDirectDrawGammaControl(IDirectDrawGammaControl* aOriginal, m_IDirectDrawX* NewParent); }; diff --git a/ddraw/IDirectDrawPalette.cpp b/ddraw/IDirectDrawPalette.cpp index 1e58b125..04b19a80 100644 --- a/ddraw/IDirectDrawPalette.cpp +++ b/ddraw/IDirectDrawPalette.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -18,47 +18,13 @@ #include "ddraw.h" -// Cached wrapper interface namespace { m_IDirectDrawPalette* WrapperInterfaceBackup = nullptr; } -inline static void SaveInterfaceAddress(m_IDirectDrawPalette* Interface, m_IDirectDrawPalette*& InterfaceBackup) -{ - if (Interface) - { - Interface->SetProxy(nullptr, nullptr, 0, nullptr); - if (InterfaceBackup) - { - InterfaceBackup->DeleteMe(); - InterfaceBackup = nullptr; - } - InterfaceBackup = Interface; - } -} - -m_IDirectDrawPalette* CreateDirectDrawPalette(IDirectDrawPalette* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags, LPPALETTEENTRY lpDDColorArray) -{ - m_IDirectDrawPalette* Interface = nullptr; - if (WrapperInterfaceBackup) - { - Interface = WrapperInterfaceBackup; - WrapperInterfaceBackup = nullptr; - Interface->SetProxy(aOriginal, NewParent, dwFlags, lpDDColorArray); - } - else - { - if (aOriginal) - { - Interface = new m_IDirectDrawPalette(aOriginal); - } - else - { - Interface = new m_IDirectDrawPalette(NewParent, dwFlags, lpDDColorArray); - } - } - return Interface; -} +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawPalette::QueryInterface(REFIID riid, LPVOID FAR * ppvObj) { @@ -111,7 +77,7 @@ ULONG m_IDirectDrawPalette::AddRef() return 0; } - if (!ProxyInterface) + if (Config.Dd7to9) { return InterlockedIncrement(&RefCount); } @@ -128,17 +94,20 @@ ULONG m_IDirectDrawPalette::Release() return 0; } - ULONG ref; - - if (!ProxyInterface) - { - ref = InterlockedDecrement(&RefCount); - } - else + if (Config.Dd7to9) { - ref = ProxyInterface->Release(); + ULONG ref = (InterlockedCompareExchange(&RefCount, 0, 0)) ? InterlockedDecrement(&RefCount) : 0; + + if (ref == 0) + { + SaveInterfaceAddress(this, WrapperInterfaceBackup); + } + + return ref; } + ULONG ref = ProxyInterface->Release(); + if (ref == 0) { SaveInterfaceAddress(this, WrapperInterfaceBackup); @@ -147,6 +116,10 @@ ULONG m_IDirectDrawPalette::Release() return ref; } +// ****************************** +// IDirectDrawPalette functions +// ****************************** + HRESULT m_IDirectDrawPalette::GetCaps(LPDWORD lpdwCaps) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -156,7 +129,7 @@ HRESULT m_IDirectDrawPalette::GetCaps(LPDWORD lpdwCaps) return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { if (!lpdwCaps) { @@ -181,7 +154,7 @@ HRESULT m_IDirectDrawPalette::GetEntries(DWORD dwFlags, DWORD dwBase, DWORD dwNu return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // Do some error checking if (!lpEntries || dwBase > entryCount) @@ -213,7 +186,7 @@ HRESULT m_IDirectDrawPalette::Initialize(LPDIRECTDRAW lpDD, DWORD dwFlags, LPPAL return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // Because the DirectDrawPalette object is initialized when it is created, this method always returns DDERR_ALREADYINITIALIZED. return DDERR_ALREADYINITIALIZED; @@ -236,7 +209,7 @@ HRESULT m_IDirectDrawPalette::SetEntries(DWORD dwFlags, DWORD dwStartingEntry, D return DDERR_INVALIDOBJECT; } - if (!ProxyInterface) + if (Config.Dd7to9) { // Do some error checking if (!lpEntries || dwStartingEntry > entryCount) @@ -267,7 +240,7 @@ HRESULT m_IDirectDrawPalette::SetEntries(DWORD dwFlags, DWORD dwStartingEntry, D return DD_OK; // No new data found } - SetCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; // Translate new raw pallete entries to RGB for (UINT i = Start; i < End; i++, x++) @@ -306,22 +279,26 @@ HRESULT m_IDirectDrawPalette::SetEntries(DWORD dwFlags, DWORD dwStartingEntry, D } } - ReleaseCriticalSection(); - return DD_OK; } return ProxyInterface->SetEntries(dwFlags, dwStartingEntry, dwCount, lpEntries); } +// ****************************** +// Helper functions +// ****************************** + void m_IDirectDrawPalette::InitInterface(DWORD dwFlags, LPPALETTEENTRY lpDDColorArray) { + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->AddPalette(this); } - if (!ProxyInterface) + if (Config.Dd7to9) { paletteCaps = (dwFlags & ~DDPCAPS_INITIALIZE); @@ -400,8 +377,33 @@ void m_IDirectDrawPalette::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->ClearPalette(this); } } + +m_IDirectDrawPalette* m_IDirectDrawPalette::CreateDirectDrawPalette(IDirectDrawPalette* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags, LPPALETTEENTRY lpDDColorArray) +{ + m_IDirectDrawPalette* Interface = nullptr; + if (WrapperInterfaceBackup) + { + Interface = WrapperInterfaceBackup; + WrapperInterfaceBackup = nullptr; + Interface->SetProxy(aOriginal, NewParent, dwFlags, lpDDColorArray); + } + else + { + if (aOriginal) + { + Interface = new m_IDirectDrawPalette(aOriginal); + } + else + { + Interface = new m_IDirectDrawPalette(NewParent, dwFlags, lpDDColorArray); + } + } + return Interface; +} diff --git a/ddraw/IDirectDrawPalette.h b/ddraw/IDirectDrawPalette.h index 32a28838..c53ea18d 100644 --- a/ddraw/IDirectDrawPalette.h +++ b/ddraw/IDirectDrawPalette.h @@ -1,13 +1,11 @@ #pragma once -m_IDirectDrawPalette* CreateDirectDrawPalette(IDirectDrawPalette* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags, LPPALETTEENTRY lpDDColorArray); - class m_IDirectDrawPalette : public IDirectDrawPalette, public AddressLookupTableDdrawObject { private: IDirectDrawPalette *ProxyInterface = nullptr; - REFIID WrapperID = IID_IDirectDrawPalette; ULONG RefCount = 1; + REFIID WrapperID = IID_IDirectDrawPalette; // Convert to Direct3D9 m_IDirectDrawX *ddrawParent = nullptr; @@ -83,14 +81,15 @@ class m_IDirectDrawPalette : public IDirectDrawPalette, public AddressLookupTabl STDMETHOD(SetEntries)(THIS_ DWORD, DWORD, DWORD, LPPALETTEENTRY); // Functions handling the ddraw parent interface - inline void SetDdrawParent(m_IDirectDrawX *ddraw) { ddrawParent = ddraw; } - inline void ClearDdraw() { ddrawParent = nullptr; } + void SetDdrawParent(m_IDirectDrawX *ddraw) { ddrawParent = ddraw; } + void ClearDdraw() { ddrawParent = nullptr; } // Helper functions - inline const PALETTEENTRY* GetPaletteEntries() const { return rawPalette; } - inline const RGBQUAD* GetRGBPalette() const { return rgbPalette; } - inline DWORD GetPaletteUSN() const { return PaletteUSN; } - inline DWORD GetEntryCount() const { return entryCount; } - inline void SetPrimary() { paletteCaps |= DDPCAPS_PRIMARYSURFACE; } - inline void RemovePrimary() { paletteCaps &= ~DDPCAPS_PRIMARYSURFACE; } + const PALETTEENTRY* GetPaletteEntries() const { return rawPalette; } + const RGBQUAD* GetRGBPalette() const { return rgbPalette; } + DWORD GetPaletteUSN() const { return PaletteUSN; } + DWORD GetEntryCount() const { return entryCount; } + void SetPrimary() { paletteCaps |= DDPCAPS_PRIMARYSURFACE; } + void RemovePrimary() { paletteCaps &= ~DDPCAPS_PRIMARYSURFACE; } + static m_IDirectDrawPalette* CreateDirectDrawPalette(IDirectDrawPalette* aOriginal, m_IDirectDrawX* NewParent, DWORD dwFlags, LPPALETTEENTRY lpDDColorArray); }; diff --git a/ddraw/IDirectDrawSurfaceX.cpp b/ddraw/IDirectDrawSurfaceX.cpp index f70c1c39..c5fad83e 100644 --- a/ddraw/IDirectDrawSurfaceX.cpp +++ b/ddraw/IDirectDrawSurfaceX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -18,20 +18,27 @@ * Code to create emulated surface taken from: https://github.com/CnCNet/cnc-ddraw */ -#include +#include "winmm.h" #include "ddraw.h" -#include "d3dx9.h" +#include #include "Utils\Utils.h" -constexpr DWORD ExtraDataBufferSize = 200; +namespace { + constexpr DWORD ExtraDataBufferSize = 200; + constexpr DWORD SurfaceWaitTimeoutMS = 4; -// Used to allow presenting non-primary surfaces in case the primary surface present fails -bool dirtyFlag = false; -bool SceneReady = false; -bool IsPresentRunning = false; + // Used for dummy mipmaps + std::vector dummySurface; + + // Used to allow presenting non-primary surfaces in case the primary surface present fails + bool dirtyFlag = false; + bool SceneReady = false; + bool IsPresentRunning = false; + + // Used for sharing emulated memory + bool ShareEmulatedMemory = false; + std::vector memorySurfaces; -// Cached wrapper interface -namespace { m_IDirectDrawSurface* WrapperInterfaceBackup = nullptr; m_IDirectDrawSurface2* WrapperInterfaceBackup2 = nullptr; m_IDirectDrawSurface3* WrapperInterfaceBackup3 = nullptr; @@ -39,16 +46,9 @@ namespace { m_IDirectDrawSurface7* WrapperInterfaceBackup7 = nullptr; } -// Used for sharing emulated memory -bool ShareEmulatedMemory = false; -std::vector memorySurfaces; - -// Used for dummy mipmaps -std::vector dummySurface; - -/************************/ -/*** IUnknown methods ***/ -/************************/ +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, DWORD DirectXVersion) { @@ -76,13 +76,7 @@ HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, D return DD_OK; } - if (DirectXVersion != 1 && DirectXVersion != 2 && DirectXVersion != 3 && DirectXVersion != 4 && DirectXVersion != 7) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirectDraw7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; bool IsD3DDevice = (riid == IID_IDirect3DHALDevice || riid == IID_IDirect3DTnLHalDevice || riid == IID_IDirect3DRGBDevice || riid == IID_IDirect3DRampDevice || riid == IID_IDirect3DMMXDevice || @@ -137,6 +131,8 @@ HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, D LOG_LIMIT(100, __FUNCTION__ << " Warning: Direct3D not setup when creating Direct3DDevice."); } + DxVersion = (DxVersion == 4) ? 3 : DxVersion; + if (!attached3DDevice) { attached3DDevice = new m_IDirect3DDeviceX(ddrawParent, D3DX, (LPDIRECTDRAWSURFACE7)GetWrapperInterfaceX(DirectXVersion), riid, DirectXVersion); @@ -145,11 +141,9 @@ HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, D } else { - AddRef(DirectXVersion); // No need to add a ref when creating a device because it is already added by setting it as a render target + attached3DDevice->AddRef(DxVersion); // No need to add a ref when creating a device because it is already added when creating the device } - DxVersion = (DxVersion == 4) ? 3 : DxVersion; - *ppvObj = (LPDIRECT3DDEVICE7)attached3DDevice->GetWrapperInterfaceX(DxVersion); return D3D_OK; @@ -195,67 +189,32 @@ HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, D return DD_OK; } - } - - if (Config.ConvertToDirect3D7 && (riid == IID_IDirect3DTexture || riid == IID_IDirect3DTexture2) && ddrawParent && !ddrawParent->IsCreatedEx()) - { - DxVersion = GetGUIDVersion(riid); - - m_IDirect3DTextureX* InterfaceX = nullptr; - - if (!attached3DTexture) + if (riid == IID_IDirect3DTexture || riid == IID_IDirect3DTexture2) { - attached3DTexture = new m_IDirect3DTextureX(ddrawParent->GetCurrentD3DDevice(), DxVersion, this, DirectXVersion); - } - - InterfaceX = attached3DTexture; - - AddRef(DirectXVersion); // 3DTextures share reference count with surface - - *ppvObj = InterfaceX->GetWrapperInterfaceX(DxVersion); - - return DD_OK; - } + if (ddrawParent->IsCreatedEx()) + { + return E_NOINTERFACE; + } - if (Config.ConvertToDirect3D7 && IsD3DDevice && ddrawParent) - { - HRESULT hr = E_NOINTERFACE; + DxVersion = GetGUIDVersion(riid); - m_IDirect3DDeviceX** lplpD3DDevice = ddrawParent->GetCurrentD3DDevice(); - if (lplpD3DDevice && *lplpD3DDevice) - { - hr = DD_OK; - } + m_IDirect3DTextureX* InterfaceX = nullptr; - if (FAILED(hr)) - { - m_IDirect3DX** lplpD3D = ddrawParent->GetCurrentD3D(); - if (lplpD3D && *lplpD3D) + if (!attached3DTexture) { - - hr = (*lplpD3D)->CreateDevice(IID_IDirect3DHALDevice, - (LPDIRECTDRAWSURFACE7)GetWrapperInterfaceX(DirectXVersion), - (LPDIRECT3DDEVICE7*)ppvObj, - nullptr, - (DirectXVersion != 4) ? DirectXVersion : 3); + attached3DTexture = new m_IDirect3DTextureX(ddrawParent->GetCurrentD3DDevice(), DxVersion, this, DirectXVersion); + } + else + { + attached3DTexture->AddRef(DxVersion); // No need to add a ref when creating a texture because it is already added when creating the texture } - } - - if (SUCCEEDED(hr)) - { - m_IDirect3DDeviceX* lpD3DDeviceX = nullptr; - ((IDirect3DDevice7*)*ppvObj)->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpD3DDeviceX); + InterfaceX = attached3DTexture; - if (lpD3DDeviceX) - { - lpD3DDeviceX->SetDdrawParent(ddrawParent); + *ppvObj = InterfaceX->GetWrapperInterfaceX(DxVersion); - ddrawParent->SetD3DDevice(lpD3DDeviceX); - } + return DD_OK; } - - return SUCCEEDED(hr) ? DD_OK : E_NOINTERFACE; } HRESULT hr = ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); @@ -283,32 +242,6 @@ HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, D return hr; } -void *m_IDirectDrawSurfaceX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface7) return WrapperInterface7; - if (WrapperInterface4) return WrapperInterface4; - if (WrapperInterface3) return WrapperInterface3; - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECTDRAWSURFACE)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECTDRAWSURFACE2)ProxyInterface, this); - case 3: - return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECTDRAWSURFACE3)ProxyInterface, this); - case 4: - return GetInterfaceAddress(WrapperInterface4, WrapperInterfaceBackup4, (LPDIRECTDRAWSURFACE4)ProxyInterface, this); - case 7: - return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECTDRAWSURFACE7)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; -} - ULONG m_IDirectDrawSurfaceX::AddRef(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; @@ -340,10 +273,10 @@ ULONG m_IDirectDrawSurfaceX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - ULONG ref; - if (Config.Dd7to9) { + ULONG ref; + switch (DirectXVersion) { case 1: @@ -389,23 +322,23 @@ ULONG m_IDirectDrawSurfaceX::Release(DWORD DirectXVersion) } } } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } -/**********************************/ -/*** IDirectDrawSurface methods ***/ -/**********************************/ +// ****************************** +// IDirectDrawSurface v1 functions +// ****************************** HRESULT m_IDirectDrawSurfaceX::AddAttachedSurface(LPDIRECTDRAWSURFACE7 lpDDSurface, DWORD DirectXVersion) { @@ -606,6 +539,33 @@ HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDS lpDDSrcSurfaceX = this; } + // Set critical section for current surface + std::vector ThreadLockDS; + ThreadLockDS.reserve(2); + ThreadLockDS.emplace_back(&ddscs); + ThreadLockDS.emplace_back(&lpDDSrcSurfaceX->ddscs); + + // Check if locked from other thread + if (BltWait) + { + // Wait for lock from other thread + DWORD beginTime = timeGetTime(); + while (IsLockedFromOtherThread() || lpDDSrcSurfaceX->IsLockedFromOtherThread()) + { + Utils::BusyWaitYield((DWORD)-1); + + // Break once timeout has passed + if ((timeGetTime() - beginTime) >= SurfaceWaitTimeoutMS) + { + break; + } + } + } + + // Set critical section + ScopedDDCriticalSection ThreadLockDD; + ThreadLockDS.clear(); + // Check for device interface HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, true); HRESULT s_hr = (lpDDSrcSurfaceX == this) ? c_hr : lpDDSrcSurfaceX->CheckInterface(__FUNCTION__, true, true, true); @@ -626,10 +586,6 @@ HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDS return (*d3d9Device)->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, float(double(lpDDBltFx->dwFillDepth) / double(ConvertDepthValue(0xFFFFFFFF, surface.Format))), 0); } - // Set critical section - SetLockCriticalSection(); - lpDDSrcSurfaceX->SetLockCriticalSection(); - // Present before write if needed if (PresentBlt) { @@ -644,38 +600,10 @@ HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDS HRESULT hr = DD_OK; do { - // Check if locked from other thread - if (BltWait && (IsLockedFromOtherThread() || lpDDSrcSurfaceX->IsLockedFromOtherThread())) - { - // Wait for lock from other thread - while (IsLockedFromOtherThread() || lpDDSrcSurfaceX->IsLockedFromOtherThread()) - { - Utils::BusyWaitYield((DWORD)-1); - if (!surface.Surface && !surface.Texture) - { - break; - } - } - if (!surface.Surface && !surface.Texture) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: surface texture missing!"); - hr = DDERR_SURFACELOST; - break; - } - } - // Set blt flag IsInBlt = true; lpDDSrcSurfaceX->IsInBlt = true; - // Set locked ID - if ((LockedWithID && LockedWithID != GetCurrentThreadId()) || (lpDDSrcSurfaceX->LockedWithID && lpDDSrcSurfaceX->LockedWithID != GetCurrentThreadId())) - { - LOG_LIMIT(100, __FUNCTION__ << " Warning: surface locked thread ID set! " << LockedWithID << " " << lpDDSrcSurfaceX->LockedWithID); - } - LockedWithID = GetCurrentThreadId(); - lpDDSrcSurfaceX->LockedWithID = GetCurrentThreadId(); - do { // Do color fill if (dwFlags & DDBLT_COLORFILL) @@ -800,10 +728,6 @@ HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDS hr = DDERR_SURFACELOST; } - // Release critical section - lpDDSrcSurfaceX->ReleaseLockCriticalSection(); - ReleaseLockCriticalSection(); - // Return return hr; } @@ -878,6 +802,8 @@ HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount return DDERR_INVALIDPARAMS; } + ScopedDDCriticalSection ThreadLockDD; + // Check for device interface before doing batch HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, true); if (FAILED(c_hr)) @@ -889,8 +815,6 @@ HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount bool IsSkipScene = false; - SetLockCriticalSection(); - // Present before write if needed BeginWritePresent(IsSkipScene); @@ -900,7 +824,7 @@ HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount { IsSkipScene |= (lpDDBltBatch[x].lprDest) ? CheckRectforSkipScene(*lpDDBltBatch[x].lprDest) : false; - hr = Blt(lpDDBltBatch[x].lprDest, (LPDIRECTDRAWSURFACE7)lpDDBltBatch[x].lpDDSSrc, lpDDBltBatch[x].lprSrc, lpDDBltBatch[x].dwFlags, lpDDBltBatch[x].lpDDBltFx, MipMapLevel, false); + hr = Blt(lpDDBltBatch[x].lprDest, (LPDIRECTDRAWSURFACE7)lpDDBltBatch[x].lpDDSSrc, lpDDBltBatch[x].lprSrc, lpDDBltBatch[x].dwFlags | DDBLT_DONOTWAIT, lpDDBltBatch[x].lpDDBltFx, MipMapLevel, false); if (FAILED(hr)) { LOG_LIMIT(100, __FUNCTION__ << " Warning: BltBatch failed before the end! " << x << " of " << dwCount << " " << (DDERR)hr); @@ -924,8 +848,6 @@ HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount EndWritePresent(nullptr, false, true, IsSkipScene); } - ReleaseLockCriticalSection(); - return hr; } @@ -1111,95 +1033,18 @@ HRESULT m_IDirectDrawSurfaceX::DeleteAttachedSurface(DWORD dwFlags, LPDIRECTDRAW return ProxyInterface->DeleteAttachedSurface(dwFlags, lpDDSAttachedSurface); } -m_IDirectDrawSurfaceX* m_IDirectDrawSurfaceX::GetAttachedDepthStencil() -{ - for (auto& it : AttachedSurfaceMap) - { - if (it.second.pSurface->IsDepthStencil()) - { - return it.second.pSurface; - } - } - return nullptr; -} - -HRESULT m_IDirectDrawSurfaceX::GetMipMapLevelAddr(LPDIRECTDRAWSURFACE7 FAR* lplpDDAttachedSurface, MIPMAP& MipMapSurface, DWORD MipMapLevel, DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 1: - if (!MipMapSurface.Addr) - { - MipMapSurface.Addr = new m_IDirectDrawSurface(this, MipMapLevel); - } - *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr; - break; - case 2: - if (!MipMapSurface.Addr2) - { - MipMapSurface.Addr2 = new m_IDirectDrawSurface2(this, MipMapLevel); - } - *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr2; - break; - case 3: - if (!MipMapSurface.Addr3) - { - MipMapSurface.Addr3 = new m_IDirectDrawSurface3(this, MipMapLevel); - } - *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr3; - break; - case 4: - if (!MipMapSurface.Addr4) - { - MipMapSurface.Addr4 = new m_IDirectDrawSurface4(this, MipMapLevel); - } - *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr4; - break; - case 7: - if (!MipMapSurface.Addr7) - { - MipMapSurface.Addr7 = new m_IDirectDrawSurface7(this, MipMapLevel); - } - *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr7; - break; - default: - LOG_LIMIT(100, __FUNCTION__ << " Error: incorrect DirectX version: " << DirectXVersion); - return DDERR_NOTFOUND; - } - - return DD_OK; -} - -HRESULT m_IDirectDrawSurfaceX::GetMipMapSubLevel(LPDIRECTDRAWSURFACE7 FAR* lplpDDAttachedSurface, DWORD MipMapLevel, DWORD DirectXVersion) -{ - // Check for device interface to ensure correct max MipMap level - CheckInterface(__FUNCTION__, true, true, false); - - if (MaxMipMapLevel > MipMapLevel) - { - while (MipMaps.size() < MipMapLevel + 1) - { - MIPMAP MipMap; - MipMaps.push_back(MipMap); - } - - return GetMipMapLevelAddr(lplpDDAttachedSurface, MipMaps[MipMapLevel], MipMapLevel + 1, DirectXVersion); - } - return DDERR_NOTFOUND; -} - HRESULT m_IDirectDrawSurfaceX::EnumAttachedSurfaces(LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback, DWORD MipMapLevel, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!lpEnumSurfacesCallback) + if (Config.Dd7to9) { - return DDERR_INVALIDPARAMS; + return EnumAttachedSurfaces2(lpContext, (LPDDENUMSURFACESCALLBACK7)lpEnumSurfacesCallback, MipMapLevel, DirectXVersion); } - if (ProxyDirectXVersion > 3) + if (!lpEnumSurfacesCallback) { - return EnumAttachedSurfaces2(lpContext, (LPDDENUMSURFACESCALLBACK7)lpEnumSurfacesCallback, MipMapLevel, DirectXVersion); + return DDERR_INVALIDPARAMS; } struct EnumSurface @@ -1316,14 +1161,14 @@ HRESULT m_IDirectDrawSurfaceX::EnumOverlayZOrders(DWORD dwFlags, LPVOID lpContex { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!lpfnCallback) + if (Config.Dd7to9) { - return DDERR_INVALIDPARAMS; + return EnumOverlayZOrders2(dwFlags, lpContext, (LPDDENUMSURFACESCALLBACK7)lpfnCallback, DirectXVersion); } - if (ProxyDirectXVersion > 3) + if (!lpfnCallback) { - return EnumOverlayZOrders2(dwFlags, lpContext, (LPDDENUMSURFACESCALLBACK7)lpfnCallback, DirectXVersion); + return DDERR_INVALIDPARAMS; } struct EnumSurface @@ -1403,41 +1248,6 @@ HRESULT m_IDirectDrawSurfaceX::EnumOverlayZOrders2(DWORD dwFlags, LPVOID lpConte return ProxyInterface->EnumOverlayZOrders(dwFlags, &CallbackContext, EnumSurface::ConvertCallback); } -// Check if backbuffer can flip with current surface -inline HRESULT m_IDirectDrawSurfaceX::CheckBackBufferForFlip(m_IDirectDrawSurfaceX* lpTargetSurface) -{ - // Check if target surface exists - if (!lpTargetSurface || lpTargetSurface == this || !DoesFlipBackBufferExist(lpTargetSurface)) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: invalid surface!"); - return DDERR_INVALIDPARAMS; - } - - // Make sure that surface description on target is updated - lpTargetSurface->UpdateSurfaceDesc(); - - // Check for device interface - HRESULT c_hr = lpTargetSurface->CheckInterface(__FUNCTION__, true, true, true); - if (FAILED(c_hr)) - { - return c_hr; - } - - // Check if surface format and size matches - if (surface.Format != lpTargetSurface->surface.Format || - surfaceDesc2.dwWidth != lpTargetSurface->surfaceDesc2.dwWidth || - surfaceDesc2.dwHeight != lpTargetSurface->surfaceDesc2.dwHeight) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: backbuffer surface does not match: " << - surface.Format << " -> " << lpTargetSurface->surface.Format << " " << - surfaceDesc2.dwWidth << "x" << surfaceDesc2.dwHeight << " -> " << - lpTargetSurface->surfaceDesc2.dwWidth << "x" << lpTargetSurface->surfaceDesc2.dwHeight); - return DDERR_INVALIDPARAMS; - } - - return DD_OK; -} - HRESULT m_IDirectDrawSurfaceX::Flip(LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverride, DWORD dwFlags, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << @@ -1480,13 +1290,6 @@ HRESULT m_IDirectDrawSurfaceX::Flip(LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverri const bool FlipWait = (((dwFlags & DDFLIP_WAIT) || DirectXVersion == 7) && (dwFlags & DDFLIP_DONOTWAIT) == 0); - // Check for device interface - HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, true); - if (FAILED(c_hr)) - { - return c_hr; - } - // Check if is in scene if (Using3D) { @@ -1567,28 +1370,50 @@ HRESULT m_IDirectDrawSurfaceX::Flip(LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverri } return false; }; - // Set critical section for each surface - for (m_IDirectDrawSurfaceX*& pSurfaceX : FlipList) + // Prepare critical sections + std::vector ThreadLockDS; + ThreadLockDS.reserve(FlipList.size() + 1); + ThreadLockDS.emplace_back(&ddscs); + + // Construct ScopedCriticalSection and locks each surface + for (auto& pSurfaceX : FlipList) { - pSurfaceX->SetLockCriticalSection(); + ThreadLockDS.emplace_back(&pSurfaceX->ddscs); } - // Present before write if needed - BeginWritePresent(false); - - HRESULT hr = DD_OK; - - do { - // Check if locked from other thread - if (FlipWait) + // Check if locked from other thread + if (FlipWait) + { + // Wait for locks from other threads + DWORD beginTime = timeGetTime(); + while (FlipSurfacesAreLockedFromOtherThread()) { - // Wait for locks from other threads - while (FlipSurfacesAreLockedFromOtherThread()) + Utils::BusyWaitYield((DWORD)-1); + + // Break once timeout has passed + if ((timeGetTime() - beginTime) >= SurfaceWaitTimeoutMS) { - Utils::BusyWaitYield((DWORD)-1); + break; } } + } + + ScopedDDCriticalSection ThreadLockDD; + ThreadLockDS.clear(); + + // Check for device interface + HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, true); + if (FAILED(c_hr)) + { + return c_hr; + } + + // Present before write if needed + BeginWritePresent(false); + HRESULT hr = DD_OK; + + do { // Check if any surface is busy for (m_IDirectDrawSurfaceX*& pSurfaceX : FlipList) { @@ -1665,12 +1490,6 @@ HRESULT m_IDirectDrawSurfaceX::Flip(LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverri } while (false); - // Release critical section for each surface - for (m_IDirectDrawSurfaceX*& pSurfaceX : FlipList) - { - pSurfaceX->ReleaseLockCriticalSection(); - } - return hr; } @@ -1686,8 +1505,7 @@ HRESULT m_IDirectDrawSurfaceX::GetAttachedSurface(LPDDSCAPS lpDDSCaps, LPDIRECTD { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert DDSCAPS to DDSCAPS2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (!lplpDDAttachedSurface) { @@ -1816,18 +1634,6 @@ HRESULT m_IDirectDrawSurfaceX::GetAttachedSurface2(LPDDSCAPS2 lpDDSCaps2, LPDIRE if (SUCCEEDED(hr) && lplpDDAttachedSurface) { *lplpDDAttachedSurface = ProxyAddressLookupTable.FindAddress(*lplpDDAttachedSurface, DirectXVersion); - - if (Config.ConvertToDirectDraw7 && *lplpDDAttachedSurface) - { - m_IDirectDrawSurfaceX *lpDDSurfaceX = nullptr; - - (*lplpDDAttachedSurface)->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSurfaceX); - - if (lpDDSurfaceX) - { - lpDDSurfaceX->SetDdrawParent(ddrawParent); - } - } } return hr; @@ -1879,8 +1685,7 @@ HRESULT m_IDirectDrawSurfaceX::GetCaps(LPDDSCAPS lpDDSCaps) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert DDSCAPS to DDSCAPS2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (!lpDDSCaps) { @@ -2022,56 +1827,6 @@ HRESULT m_IDirectDrawSurfaceX::GetColorKey(DWORD dwFlags, LPDDCOLORKEY lpDDColor return ProxyInterface->GetColorKey(dwFlags, lpDDColorKey); } -bool m_IDirectDrawSurfaceX::GetColorKeyForPrimaryShader(float(&lowColorKey)[4], float(&highColorKey)[4]) -{ - // Primary 2D surface background color - if (IsPrimarySurface()) - { - if (!primary.ShaderColorKey.IsSet) - { - GetColorKeyArray(primary.ShaderColorKey.lowColorKey, primary.ShaderColorKey.highColorKey, Config.DdrawFlipFillColor, Config.DdrawFlipFillColor, surfaceDesc2.ddpfPixelFormat); - primary.ShaderColorKey.IsSet = true; - } - lowColorKey[0] = primary.ShaderColorKey.lowColorKey[0]; - lowColorKey[1] = primary.ShaderColorKey.lowColorKey[1]; - lowColorKey[2] = primary.ShaderColorKey.lowColorKey[2]; - lowColorKey[3] = primary.ShaderColorKey.lowColorKey[3]; - highColorKey[0] = primary.ShaderColorKey.highColorKey[0]; - highColorKey[1] = primary.ShaderColorKey.highColorKey[1]; - highColorKey[2] = primary.ShaderColorKey.highColorKey[2]; - highColorKey[3] = primary.ShaderColorKey.highColorKey[3]; - return true; - } - return false; -} - -bool m_IDirectDrawSurfaceX::GetColorKeyForShader(float(&lowColorKey)[4], float(&highColorKey)[4]) -{ - // Surface low and high color space - if (!ShaderColorKey.IsSet) - { - if (surfaceDesc2.dwFlags & DDSD_CKSRCBLT) - { - GetColorKeyArray(ShaderColorKey.lowColorKey, ShaderColorKey.highColorKey, - surfaceDesc2.ddckCKSrcBlt.dwColorSpaceLowValue, surfaceDesc2.ddckCKSrcBlt.dwColorSpaceHighValue, surfaceDesc2.ddpfPixelFormat); - ShaderColorKey.IsSet = true; - } - else - { - return false; - } - } - lowColorKey[0] = ShaderColorKey.lowColorKey[0]; - lowColorKey[1] = ShaderColorKey.lowColorKey[1]; - lowColorKey[2] = ShaderColorKey.lowColorKey[2]; - lowColorKey[3] = ShaderColorKey.lowColorKey[3]; - highColorKey[0] = ShaderColorKey.highColorKey[0]; - highColorKey[1] = ShaderColorKey.highColorKey[1]; - highColorKey[2] = ShaderColorKey.highColorKey[2]; - highColorKey[3] = ShaderColorKey.highColorKey[3]; - return true; -} - HRESULT m_IDirectDrawSurfaceX::GetDC(HDC FAR* lphDC, DWORD MipMapLevel) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << @@ -2093,6 +1848,10 @@ HRESULT m_IDirectDrawSurfaceX::GetDC(HDC FAR* lphDC, DWORD MipMapLevel) return DDERR_UNSUPPORTED; } + // Set critical section for current surface + std::vector ThreadLockDS; + ThreadLockDS.emplace_back(&ddscs); + if (LastDC && IsSurfaceInDC()) { *lphDC = LastDC; @@ -2105,6 +1864,9 @@ HRESULT m_IDirectDrawSurfaceX::GetDC(HDC FAR* lphDC, DWORD MipMapLevel) *lphDC = surface.emu->GameDC; } + ScopedDDCriticalSection ThreadLockDD; + ThreadLockDS.clear(); + // Check for device interface HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, true); if (FAILED(c_hr)) @@ -2129,8 +1891,6 @@ HRESULT m_IDirectDrawSurfaceX::GetDC(HDC FAR* lphDC, DWORD MipMapLevel) LOG_LIMIT(100, __FUNCTION__ << " Warning: does not support device context with bit alignment!"); } - SetLockCriticalSection(); - // Present before write if needed BeginWritePresent(false); @@ -2209,8 +1969,6 @@ HRESULT m_IDirectDrawSurfaceX::GetDC(HDC FAR* lphDC, DWORD MipMapLevel) IsPreparingDC = false; - ReleaseLockCriticalSection(); - if (FAILED(hr)) { hr = IsSurfaceBusy() ? DDERR_SURFACEBUSY : IsLost() == DDERR_SURFACELOST ? DDERR_SURFACELOST : DDERR_GENERIC; @@ -2390,8 +2148,7 @@ HRESULT m_IDirectDrawSurfaceX::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc, D { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (lpDDSurfaceDesc && lpDDSurfaceDesc->dwSize == sizeof(DDSURFACEDESC2)) { @@ -2421,18 +2178,6 @@ HRESULT m_IDirectDrawSurfaceX::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc, D return GetProxyInterfaceV3()->GetSurfaceDesc(lpDDSurfaceDesc); } -void m_IDirectDrawSurfaceX::FixTextureFlags(LPDDSURFACEDESC2 lpDDSurfaceDesc2) -{ - if (lpDDSurfaceDesc2) - { - if (lpDDSurfaceDesc2->dwFlags & DDSD_PITCH) - { - lpDDSurfaceDesc2->dwFlags |= DDSD_LINEARSIZE; - } - lpDDSurfaceDesc2->dwFlags &= ~(DDSD_PITCH | DDSD_LPSURFACE); - } -} - HRESULT m_IDirectDrawSurfaceX::GetSurfaceDesc2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, DWORD MipMapLevel, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -2548,7 +2293,7 @@ HRESULT m_IDirectDrawSurfaceX::Initialize(LPDIRECTDRAW lpDD, LPDDSURFACEDESC lpD { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (lpDDSurfaceDesc && lpDDSurfaceDesc->dwSize != sizeof(DDSURFACEDESC)) { @@ -2617,7 +2362,7 @@ HRESULT m_IDirectDrawSurfaceX::IsLost() return DDERR_SURFACELOST; case D3D_OK: case DDERR_NOEXCLUSIVEMODE: - if (IsSurfaceLost && (ComplexRoot || !(surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX))) + if (IsSurfaceLost && !ComplexChild) // Complex children don't get surface lost notice { return DDERR_SURFACELOST; } @@ -2638,7 +2383,7 @@ HRESULT m_IDirectDrawSurfaceX::Lock(LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfa Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (!lpDDSurfaceDesc || lpDDSurfaceDesc->dwSize != sizeof(DDSURFACEDESC)) { @@ -2693,6 +2438,33 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur ShouldEmulate = SC_FORCE_EMULATED; } + // Set to indicate that Lock should wait until it can obtain a valid memory pointer before returning. + const bool LockWait = (((dwFlags & DDLOCK_WAIT) || DirectXVersion == 7) && (dwFlags & DDLOCK_DONOTWAIT) == 0); + + // Set critical section for current surface + std::vector ThreadLockDS; + ThreadLockDS.emplace_back(&ddscs); + + // Check if locked from other thread + if (LockWait) + { + // Wait for lock from other thread + DWORD beginTime = timeGetTime(); + while (IsLockedFromOtherThread()) + { + Utils::BusyWaitYield((DWORD)-1); + + // Break once timeout has passed + if ((timeGetTime() - beginTime) >= SurfaceWaitTimeoutMS) + { + break; + } + } + } + + ScopedDDCriticalSection ThreadLockDD; + ThreadLockDS.clear(); + // Check for device interface HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, false); @@ -2761,9 +2533,6 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur return DD_OK; } - // Set to indicate that Lock should wait until it can obtain a valid memory pointer before returning. - const bool LockWait = (((dwFlags & DDLOCK_WAIT) || DirectXVersion == 7) && (dwFlags & DDLOCK_DONOTWAIT) == 0); - // Convert flags to d3d9 DWORD Flags = (dwFlags & (D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE)) | ((dwFlags & D3DLOCK_NOSYSLOCK) ? D3DLOCK_NOSYSLOCK : 0) | @@ -2773,8 +2542,6 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur // Check if the scene needs to be presented const bool IsSkipScene = (CheckRectforSkipScene(DestRect) || (Flags & D3DLOCK_READONLY)); - SetLockCriticalSection(); - // Present before write if needed BeginWritePresent(IsSkipScene); @@ -2802,26 +2569,6 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur HRESULT hr = DD_OK; do { - // Check if locked from other thread - if (LockWait && IsLockedFromOtherThread()) - { - // Wait for lock from other thread - while (IsLockedFromOtherThread()) - { - Utils::BusyWaitYield((DWORD)-1); - if (!surface.Surface && !surface.Texture) - { - break; - } - } - if (!surface.Surface && !surface.Texture) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: surface texture missing!"); - hr = DDERR_SURFACELOST; - break; - } - } - // Emulated surface D3DLOCKED_RECT LockedRect = {}; if (IsUsingEmulation()) @@ -2963,8 +2710,6 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur IsLocking = false; - ReleaseLockCriticalSection(); - #ifdef ENABLE_PROFILING Logging::Log() << __FUNCTION__ << " (" << this << ")" << " Type = " << surface.Type << " " << surface.Pool << @@ -2978,48 +2723,6 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur return ProxyInterface->Lock(lpDestRect, lpDDSurfaceDesc2, dwFlags, hEvent); } -inline HRESULT m_IDirectDrawSurfaceX::LockD3d9Surface(D3DLOCKED_RECT* pLockedRect, RECT* pRect, DWORD Flags, DWORD MipMapLevel) -{ - if (surface.UsingSurfaceMemory) - { - pLockedRect->Pitch = surfaceDesc2.dwWidth * surface.BitCount / 8; - pLockedRect->pBits = (pRect) ? (void*)((DWORD)surfaceDesc2.lpSurface + ((pRect->top * pLockedRect->Pitch) + (pRect->left * (surface.BitCount / 8)))) : surfaceDesc2.lpSurface; - return DD_OK; - } - // Lock shadow surface - else if (IsUsingShadowSurface()) - { - HRESULT hr = surface.Shadow->LockRect(pLockedRect, pRect, Flags); - if (FAILED(hr) && (Flags & D3DLOCK_NOSYSLOCK)) - { - hr = surface.Shadow->LockRect(pLockedRect, pRect, Flags & ~D3DLOCK_NOSYSLOCK); - } - return hr; - } - // Lock 3D surface - else if (surface.Surface) - { - HRESULT hr = surface.Surface->LockRect(pLockedRect, pRect, Flags); - if (FAILED(hr) && (Flags & D3DLOCK_NOSYSLOCK)) - { - hr = surface.Surface->LockRect(pLockedRect, pRect, Flags & ~D3DLOCK_NOSYSLOCK); - } - return hr; - } - // Lock surface texture - else if (surface.Texture) - { - HRESULT hr = surface.Texture->LockRect(GetD3d9MipMapLevel(MipMapLevel), pLockedRect, pRect, Flags); - if (FAILED(hr) && (Flags & D3DLOCK_NOSYSLOCK)) - { - hr = surface.Texture->LockRect(GetD3d9MipMapLevel(MipMapLevel), pLockedRect, pRect, Flags & ~D3DLOCK_NOSYSLOCK); - } - return hr; - } - - return DDERR_GENERIC; -} - HRESULT m_IDirectDrawSurfaceX::ReleaseDC(HDC hDC) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")" << @@ -3040,8 +2743,6 @@ HRESULT m_IDirectDrawSurfaceX::ReleaseDC(HDC hDC) return DDERR_GENERIC; } - SetSurfaceCriticalSection(); - #ifdef ENABLE_PROFILING auto startTime = std::chrono::high_resolution_clock::now(); #endif @@ -3049,7 +2750,6 @@ HRESULT m_IDirectDrawSurfaceX::ReleaseDC(HDC hDC) HRESULT hr = DD_OK; do { - if (IsUsingEmulation() || DCRequiresEmulation) { if (!IsUsingEmulation()) @@ -3089,8 +2789,6 @@ HRESULT m_IDirectDrawSurfaceX::ReleaseDC(HDC hDC) } while (false); - ReleaseSurfaceCriticalSection(); - #ifdef ENABLE_PROFILING Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); #endif @@ -3316,6 +3014,8 @@ HRESULT m_IDirectDrawSurfaceX::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) return DD_OK; } + ScopedDDCriticalSection ThreadLockDD; + // If palette exists increament ref if (lpDDPalette) { @@ -3349,8 +3049,6 @@ HRESULT m_IDirectDrawSurfaceX::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) // Set palette address attachedPalette = (m_IDirectDrawPalette*)lpDDPalette; - SetCriticalSection(); - // Reset data for new palette surface.LastPaletteUSN = 0; surface.PaletteEntryArray = nullptr; @@ -3358,8 +3056,6 @@ HRESULT m_IDirectDrawSurfaceX::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) // Set new palette data UpdatePaletteData(); - ReleaseCriticalSection(); - return DD_OK; } @@ -3386,8 +3082,6 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect, DWORD MipMapLevel) return DD_OK; } - SetSurfaceCriticalSection(); - #ifdef ENABLE_PROFILING auto startTime = std::chrono::high_resolution_clock::now(); #endif @@ -3507,73 +3201,12 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect, DWORD MipMapLevel) EndWritePresent(&LastLock.Rect, true, true, LastLock.IsSkipScene); } - ReleaseSurfaceCriticalSection(); - return hr; } return ProxyInterface->Unlock(lpRect); } -inline HRESULT m_IDirectDrawSurfaceX::UnLockD3d9Surface(DWORD MipMapLevel) -{ - if (surface.UsingSurfaceMemory) - { - return DD_OK; - } - // Unlock shadow surface - else if (IsUsingShadowSurface()) - { - return surface.Shadow->UnlockRect(); - } - // Unlock 3D surface - else if (surface.Surface) - { - return surface.Surface->UnlockRect(); - } - // Unlock surface texture - else if (surface.Texture) - { - return surface.Texture->UnlockRect(GetD3d9MipMapLevel(MipMapLevel)); - } - - return DDERR_GENERIC; -} - -HRESULT m_IDirectDrawSurfaceX::PresentOverlay(LPRECT lpSrcRect) -{ - if (SurfaceOverlay.OverlayEnabled) - { - RECT SrcRect = {}; - if (!lpSrcRect || SurfaceOverlay.isSrcRectNull || GetOverlappingRect(*lpSrcRect, SurfaceOverlay.SrcRect, SrcRect)) - { - LPRECT lpNewSrcRect = SurfaceOverlay.isSrcRectNull ? nullptr : &SurfaceOverlay.SrcRect; - LPRECT lpNewDestRect = SurfaceOverlay.isDestRectNull ? nullptr : &SurfaceOverlay.DestRect; - - DWORD DDBltFxFlags = SurfaceOverlay.DDBltFxFlags; - DDBLTFX DDBltFx = SurfaceOverlay.DDBltFx; - - // Handle color keying - if (!(DDBltFxFlags & (DDBLT_KEYDESTOVERRIDE | DDBLT_KEYSRCOVERRIDE))) - { - if ((SurfaceOverlay.DDOverlayFxFlags & DDOVER_KEYDEST) && (SurfaceOverlay.lpDDDestSurfaceX->surfaceDesc2.dwFlags & DDSD_CKDESTOVERLAY)) - { - DDBltFxFlags |= (DDBLT_DDFX | DDBLT_KEYDESTOVERRIDE); - DDBltFx.ddckDestColorkey = SurfaceOverlay.lpDDDestSurfaceX->surfaceDesc2.ddckCKDestOverlay; - } - else if ((SurfaceOverlay.DDOverlayFxFlags & DDOVER_KEYSRC) && (surfaceDesc2.dwFlags & DDSD_CKSRCOVERLAY)) - { - DDBltFxFlags |= (DDBLT_DDFX | DDBLT_KEYSRCOVERRIDE); - DDBltFx.ddckSrcColorkey = surfaceDesc2.ddckCKSrcOverlay; - } - } - - SurfaceOverlay.lpDDDestSurfaceX->Blt(lpNewDestRect, (LPDIRECTDRAWSURFACE7)GetWrapperInterfaceX(0), lpNewSrcRect, DDBltFxFlags, &DDBltFx, 0); - } - } - return DD_OK; -} - HRESULT m_IDirectDrawSurfaceX::UpdateOverlay(LPRECT lpSrcRect, LPDIRECTDRAWSURFACE7 lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -3777,9 +3410,9 @@ HRESULT m_IDirectDrawSurfaceX::UpdateOverlayZOrder(DWORD dwFlags, LPDIRECTDRAWSU return ProxyInterface->UpdateOverlayZOrder(dwFlags, lpDDSReference); } -/*********************************/ -/*** Added in the v2 interface ***/ -/*********************************/ +// ****************************** +// IDirectDrawSurface v2 functions +// ****************************** HRESULT m_IDirectDrawSurfaceX::GetDDInterface(LPVOID FAR * lplpDD, DWORD DirectXVersion) { @@ -3865,16 +3498,15 @@ HRESULT m_IDirectDrawSurfaceX::PageUnlock(DWORD dwFlags) return ProxyInterface->PageUnlock(dwFlags); } -/*********************************/ -/*** Added in the v3 interface ***/ -/*********************************/ +// ****************************** +// IDirectDrawSurface v3 functions +// ****************************** HRESULT m_IDirectDrawSurfaceX::SetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (!lpDDSurfaceDesc) { @@ -3904,6 +3536,8 @@ HRESULT m_IDirectDrawSurfaceX::SetSurfaceDesc2(LPDDSURFACEDESC2 lpDDSurfaceDesc2 // Check flags DWORD SurfaceFlags = lpDDSurfaceDesc2->dwFlags; + + // Handle lpSurface flag if ((SurfaceFlags & DDSD_LPSURFACE) && lpDDSurfaceDesc2->lpSurface) { LOG_LIMIT(100, __FUNCTION__ << " Warning: lpSurface not fully Implemented."); @@ -3917,20 +3551,54 @@ HRESULT m_IDirectDrawSurfaceX::SetSurfaceDesc2(LPDDSURFACEDESC2 lpDDSurfaceDesc2 CreateD9Surface(); } } + + // Handle width, height and pitch flags + if (SurfaceFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH)) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: surfaceDesc flags being updated: " << Logging::hex(SurfaceFlags)); + bool Flag = false; + if ((SurfaceFlags & DDSD_WIDTH) && lpDDSurfaceDesc2->dwWidth) + { + Flag = Flag || (surfaceDesc2.dwWidth != lpDDSurfaceDesc2->dwWidth); + SurfaceFlags &= ~DDSD_WIDTH; + ResetDisplayFlags &= ~DDSD_WIDTH; + surfaceDesc2.dwFlags |= DDSD_WIDTH; + surfaceDesc2.dwWidth = lpDDSurfaceDesc2->dwWidth; + } + if ((SurfaceFlags & DDSD_HEIGHT) && lpDDSurfaceDesc2->dwHeight) + { + Flag = Flag || (surfaceDesc2.dwHeight != lpDDSurfaceDesc2->dwHeight); + SurfaceFlags &= ~DDSD_HEIGHT; + ResetDisplayFlags &= ~DDSD_HEIGHT; + surfaceDesc2.dwFlags |= DDSD_HEIGHT; + surfaceDesc2.dwHeight = lpDDSurfaceDesc2->dwHeight; + } + if (SurfaceFlags & DDSD_PITCH) + { + SurfaceFlags &= ~DDSD_PITCH; + } + if (Flag && (surface.Surface || surface.Texture)) + { + CreateD9Surface(); + } + } + + // Check for unhandled flags if (SurfaceFlags) { LOG_LIMIT(100, __FUNCTION__ << " Error: flags not implemented " << Logging::hex(SurfaceFlags)); return DDERR_UNSUPPORTED; } + return DD_OK; } return ProxyInterface->SetSurfaceDesc(lpDDSurfaceDesc2, dwFlags); } -/*********************************/ -/*** Added in the v4 interface ***/ -/*********************************/ +// ****************************** +// IDirectDrawSurface v4 functions +// ****************************** HRESULT m_IDirectDrawSurfaceX::SetPrivateData(REFGUID guidTag, LPVOID lpData, DWORD cbSize, DWORD dwFlags) { @@ -4065,9 +3733,9 @@ HRESULT m_IDirectDrawSurfaceX::ChangeUniquenessValue() return ProxyInterface->ChangeUniquenessValue(); } -/***********************************/ -/*** Moved Texture7 methods here ***/ -/***********************************/ +// ****************************** +// IDirect3DTexture v7 functions moved here +// ****************************** HRESULT m_IDirectDrawSurfaceX::SetPriority(DWORD dwPriority) { @@ -4180,12 +3848,14 @@ HRESULT m_IDirectDrawSurfaceX::GetLOD(LPDWORD lpdwMaxLOD) return ProxyInterface->GetLOD(lpdwMaxLOD); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** void m_IDirectDrawSurfaceX::InitInterface(DWORD DirectXVersion) { + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->AddSurface(this); @@ -4196,7 +3866,6 @@ void m_IDirectDrawSurfaceX::InitInterface(DWORD DirectXVersion) AddRef(DirectXVersion); InitializeCriticalSection(&ddscs); - InitializeCriticalSection(&ddlcs); if (ddrawParent) { @@ -4218,6 +3887,8 @@ void m_IDirectDrawSurfaceX::ReleaseInterface() return; } + ScopedDDCriticalSection ThreadLockDD; + if (ddrawParent) { ddrawParent->ClearSurface(this); @@ -4251,14 +3922,165 @@ void m_IDirectDrawSurfaceX::ReleaseInterface() // Delete critical section last DeleteCriticalSection(&ddscs); - DeleteCriticalSection(&ddlcs); } } -void m_IDirectDrawSurfaceX::SetDdrawParent(m_IDirectDrawX* ddraw) +HRESULT m_IDirectDrawSurfaceX::CheckInterface(char* FunctionName, bool CheckD3DDevice, bool CheckD3DSurface, bool CheckLostSurface) { - if (!ddraw) - { + // Check ddrawParent device + if (!ddrawParent) + { + ScopedDDCriticalSection ThreadLockDD; + + m_IDirectDrawX* pInterface = m_IDirectDrawX::GetDirectDrawInterface(); + if (pInterface) + { + LOG_LIMIT(100, FunctionName << " Error: no ddraw parent!"); + return DDERR_INVALIDOBJECT; + } + + SetDdrawParent(pInterface); + ddrawParent->AddSurface(this); + } + + // Check d3d9 device + if (CheckD3DDevice) + { + if (!ddrawParent->CheckD9Device(FunctionName) || !d3d9Device || !*d3d9Device) + { + LOG_LIMIT(100, FunctionName << " Error: d3d9 device not setup!"); + return DDERR_INVALIDOBJECT; + } + if (ShouldPresentToWindow(true)) + { + HWND CurrentClipperHWnd = ddrawParent->GetClipperHWnd(); + + HWND hWnd = nullptr; + if (attachedClipper) + { + attachedClipper->GetHWnd(&hWnd); + if (IsWindow(hWnd) && hWnd != CurrentClipperHWnd) + { + ddrawParent->SetClipperHWnd(hWnd); + } + } + if (!IsWindow(hWnd) && (!IsWindow(CurrentClipperHWnd) || !Utils::IsMainWindow(CurrentClipperHWnd))) + { + hWnd = Utils::GetMainWindowForProcess(GetCurrentProcessId()); + if (hWnd != CurrentClipperHWnd) + { + ddrawParent->SetClipperHWnd(hWnd); + } + } + } + } + + // Check if device is lost + if (CheckLostSurface && (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) + { + HRESULT hr = ddrawParent->TestD3D9CooperativeLevel(); + switch (hr) + { + case DD_OK: + case DDERR_NOEXCLUSIVEMODE: + break; + case D3DERR_DEVICENOTRESET: + if (SUCCEEDED(ddrawParent->ResetD9Device())) + { + break; + } + [[fallthrough]]; + case D3DERR_DEVICELOST: + return DDERR_SURFACELOST; + default: + LOG_LIMIT(100, FunctionName << " Error: TestCooperativeLevel = " << (D3DERR)hr); + return DDERR_WRONGMODE; + } + } + + // Check surface + if (CheckD3DSurface) + { + // Check if using windowed mode + bool LastWindowedMode = surface.IsUsingWindowedMode; + surface.IsUsingWindowedMode = !ddrawParent->IsExclusiveMode(); + + // Check if using Direct3D + bool LastUsing3D = Using3D; + Using3D = ddrawParent->IsUsing3D(); + + // Remove emulated surface if not needed + if (IsUsingEmulation() && !CanSurfaceUseEmulation() && !IsSurfaceBusy()) + { + ReleaseDCSurface(); + } + + // Clear Using 3D if not needed + if (!Using3D && LastUsing3D) + { + ClearUsing3DFlag(); + } + + // Release d3d9 surface + if (attached3DTexture && surface.Pool != D3DPOOL_MANAGED) + { + ScopedDDCriticalSection ThreadLockDD; + + ReleaseD9Surface(true, false); + } + + // Make sure surface exists, if not then create it + if ((!surface.Surface && !surface.Texture) || + (IsPrimaryOrBackBuffer() && LastWindowedMode != surface.IsUsingWindowedMode) || + (PrimaryDisplayTexture && !ShouldPresentToWindow(false))) + { + if (FAILED(CreateD9Surface())) + { + LOG_LIMIT(100, FunctionName << " Error: d3d9 surface texture not setup!"); + return DDERR_WRONGMODE; + } + } + + // Check auxiliary surfaces + if ((RecreateAuxiliarySurfaces || surface.RecreateAuxiliarySurfaces) && FAILED(CreateD9AuxiliarySurfaces())) + { + return DDERR_WRONGMODE; + } + } + + return DD_OK; +} + +void* m_IDirectDrawSurfaceX::GetWrapperInterfaceX(DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 0: + if (WrapperInterface7) return WrapperInterface7; + if (WrapperInterface4) return WrapperInterface4; + if (WrapperInterface3) return WrapperInterface3; + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECTDRAWSURFACE)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECTDRAWSURFACE2)ProxyInterface, this); + case 3: + return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECTDRAWSURFACE3)ProxyInterface, this); + case 4: + return GetInterfaceAddress(WrapperInterface4, WrapperInterfaceBackup4, (LPDIRECTDRAWSURFACE4)ProxyInterface, this); + case 7: + return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECTDRAWSURFACE7)ProxyInterface, this); + } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} + +void m_IDirectDrawSurfaceX::SetDdrawParent(m_IDirectDrawX* ddraw) +{ + if (!ddraw) + { return; } @@ -4288,7 +4110,7 @@ void m_IDirectDrawSurfaceX::ClearDdraw() } } -inline void m_IDirectDrawSurfaceX::ReleaseDirectDrawResources() +void m_IDirectDrawSurfaceX::ReleaseDirectDrawResources() { if (attachedClipper) { @@ -4319,29 +4141,42 @@ inline void m_IDirectDrawSurfaceX::ReleaseDirectDrawResources() ddrawParent->ClearSurface(this); } - for (const auto& entry : AttachedSurfaceMap) + for (auto& entry : AttachedSurfaceMap) { if (entry.second.RefCount == 1) { + entry.second.RefCount = 0; // Clear ref count before release entry.second.pSurface->Release(entry.second.DxVersion); } } AttachedSurfaceMap.clear(); } -LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::GetD3d9Surface() +LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::GetD3d9Surface(bool ShouldCheckInterface) { // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true, true, true))) + if (ShouldCheckInterface) { - LOG_LIMIT(100, __FUNCTION__ << " Error: surface not setup!"); - return nullptr; + if (FAILED(CheckInterface(__FUNCTION__, true, true, true))) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: surface cannot be setup!"); + return nullptr; + } + } + // For threads that require no thread locks (CreateD9Device can be called from a different thread) + else + { + if (!surface.Surface && !surface.Texture) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: surface is not setup!"); + return nullptr; + } } return Get3DSurface(); } -inline LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::Get3DSurface() +LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::Get3DSurface() { if (surface.Surface) { @@ -4357,7 +4192,7 @@ inline LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::Get3DSurface() return nullptr; } -inline LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::Get3DMipMapSurface(DWORD MipMapLevel) +LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::Get3DMipMapSurface(DWORD MipMapLevel) { if (IsUsingShadowSurface()) { @@ -4376,7 +4211,7 @@ inline LPDIRECT3DSURFACE9 m_IDirectDrawSurfaceX::Get3DMipMapSurface(DWORD MipMap return nullptr; } -inline void m_IDirectDrawSurfaceX::Release3DMipMapSurface(LPDIRECT3DSURFACE9 pSurfaceD9, DWORD MipMapLevel) +void m_IDirectDrawSurfaceX::Release3DMipMapSurface(LPDIRECT3DSURFACE9 pSurfaceD9, DWORD MipMapLevel) { if (pSurfaceD9 && MipMapLevel != 0 && surface.Type == D3DTYPE_TEXTURE && !IsUsingShadowSurface()) { @@ -4435,7 +4270,7 @@ LPDIRECT3DTEXTURE9 m_IDirectDrawSurfaceX::GetD3d9Texture() return Get3DTexture(); } -inline LPDIRECT3DTEXTURE9 m_IDirectDrawSurfaceX::Get3DTexture() +LPDIRECT3DTEXTURE9 m_IDirectDrawSurfaceX::Get3DTexture() { // Primary display texture if (PrimaryDisplayTexture && ShouldPresentToWindow(true)) @@ -4513,175 +4348,53 @@ HRESULT m_IDirectDrawSurfaceX::GenerateMipMapLevels() return DD_OK; } -HRESULT m_IDirectDrawSurfaceX::CheckInterface(char *FunctionName, bool CheckD3DDevice, bool CheckD3DSurface, bool CheckLostSurface) +HRESULT m_IDirectDrawSurfaceX::CreateD9AuxiliarySurfaces() { - // Check ddrawParent device - if (!ddrawParent) + // Create shadow surface + if (!surface.Shadow && (surface.Usage & D3DUSAGE_RENDERTARGET)) { - if (DDrawVector.empty()) + D3DSURFACE_DESC Desc; + if (FAILED(surface.Surface ? surface.Surface->GetDesc(&Desc) : surface.Texture->GetLevelDesc(0, &Desc)) || + FAILED((*d3d9Device)->CreateOffscreenPlainSurface(Desc.Width, Desc.Height, Desc.Format, D3DPOOL_SYSTEMMEM, &surface.Shadow, nullptr))) { - LOG_LIMIT(100, FunctionName << " Error: no ddraw parent!"); - return DDERR_INVALIDOBJECT; + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create shadow surface. Size: " << surface.Width << "x" << surface.Height << " Format: " << surface.Format << " dwCaps: " << surfaceDesc2.ddsCaps); + return DDERR_GENERIC; } - - SetDdrawParent(DDrawVector[0]); - ddrawParent->AddSurface(this); } - // Check d3d9 device - if (CheckD3DDevice) + // Create primary surface texture + if (!PrimaryDisplayTexture && ShouldPresentToWindow(false)) { - if (!ddrawParent->CheckD9Device(FunctionName) || !d3d9Device || !*d3d9Device) - { - LOG_LIMIT(100, FunctionName << " Error: d3d9 device not setup!"); - return DDERR_INVALIDOBJECT; - } - if (ShouldPresentToWindow(true)) + D3DSURFACE_DESC Desc; + if (FAILED(surface.Surface ? surface.Surface->GetDesc(&Desc) : surface.Texture->GetLevelDesc(0, &Desc)) || + FAILED((*d3d9Device)->CreateTexture(Desc.Width, Desc.Height, 1, 0, Desc.Format, D3DPOOL_DEFAULT, &PrimaryDisplayTexture, nullptr))) { - HWND CurrentClipperHWnd = ddrawParent->GetClipperHWnd(); - - HWND hWnd = nullptr; - if (attachedClipper) - { - attachedClipper->GetHWnd(&hWnd); - if (IsWindow(hWnd) && hWnd != CurrentClipperHWnd) - { - ddrawParent->SetClipperHWnd(hWnd); - } - } - if (!IsWindow(hWnd) && (!IsWindow(CurrentClipperHWnd) || !Utils::IsMainWindow(CurrentClipperHWnd))) - { - hWnd = Utils::GetMainWindowForProcess(GetCurrentProcessId()); - if (hWnd != CurrentClipperHWnd) - { - ddrawParent->SetClipperHWnd(hWnd); - } - } + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create primary surface texture. Size: " << surface.Width << "x" << surface.Height << " Format: " << surface.Format << " dwCaps: " << surfaceDesc2.ddsCaps); + return DDERR_GENERIC; } } - // Check if device is lost - if (CheckLostSurface && (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) + // Create palette surface + if (!primary.PaletteTexture && IsPrimarySurface() && surface.Format == D3DFMT_P8) { - HRESULT hr = ddrawParent->TestD3D9CooperativeLevel(); - switch (hr) + if (FAILED((*d3d9Device)->CreateTexture(MaxPaletteSize, MaxPaletteSize, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &primary.PaletteTexture, nullptr))) { - case DD_OK: - case DDERR_NOEXCLUSIVEMODE: - break; - case D3DERR_DEVICENOTRESET: - if (SUCCEEDED(ddrawParent->ResetD9Device())) + // Try failover format + if (FAILED((*d3d9Device)->CreateTexture(MaxPaletteSize, MaxPaletteSize, 1, 0, GetFailoverFormat(D3DFMT_X8R8G8B8), D3DPOOL_MANAGED, &primary.PaletteTexture, nullptr))) { - break; + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create palette surface texture"); + return DDERR_GENERIC; } - [[fallthrough]]; - case D3DERR_DEVICELOST: - return DDERR_SURFACELOST; - default: - LOG_LIMIT(100, FunctionName << " Error: TestCooperativeLevel = " << (D3DERR)hr); - return DDERR_WRONGMODE; } } - // Check surface - if (CheckD3DSurface) - { - // Check if using windowed mode - bool LastWindowedMode = surface.IsUsingWindowedMode; - surface.IsUsingWindowedMode = !ddrawParent->IsExclusiveMode(); - - // Check if using Direct3D - bool LastUsing3D = Using3D; - Using3D = ddrawParent->IsUsing3D(); - - // Remove emulated surface if not needed - if (IsUsingEmulation() && !CanSurfaceUseEmulation() && !IsSurfaceBusy()) - { - ReleaseDCSurface(); - } + // Reset flags + RecreateAuxiliarySurfaces = false; + surface.RecreateAuxiliarySurfaces = false; - // Clear Using 3D if not needed - if (!Using3D && LastUsing3D) - { - ClearUsing3DFlag(); - } + return DD_OK; +} - // Release d3d9 surface - if (attached3DTexture && surface.Pool != D3DPOOL_MANAGED) - { - ReleaseD9Surface(true, false); - } - - // Make sure surface exists, if not then create it - if ((!surface.Surface && !surface.Texture) || - (IsPrimaryOrBackBuffer() && LastWindowedMode != surface.IsUsingWindowedMode) || - (PrimaryDisplayTexture && !ShouldPresentToWindow(false))) - { - if (FAILED(CreateD9Surface())) - { - LOG_LIMIT(100, FunctionName << " Error: d3d9 surface texture not setup!"); - return DDERR_WRONGMODE; - } - } - - // Check auxiliary surfaces - if ((RecreateAuxiliarySurfaces || surface.RecreateAuxiliarySurfaces) && FAILED(CreateD9AuxiliarySurfaces())) - { - return DDERR_WRONGMODE; - } - } - - return DD_OK; -} - -HRESULT m_IDirectDrawSurfaceX::CreateD9AuxiliarySurfaces() -{ - // Create shadow surface - if (!surface.Shadow && (surface.Usage & D3DUSAGE_RENDERTARGET)) - { - D3DSURFACE_DESC Desc; - if (FAILED(surface.Surface ? surface.Surface->GetDesc(&Desc) : surface.Texture->GetLevelDesc(0, &Desc)) || - FAILED((*d3d9Device)->CreateOffscreenPlainSurface(Desc.Width, Desc.Height, Desc.Format, D3DPOOL_SYSTEMMEM, &surface.Shadow, nullptr))) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create shadow surface. Size: " << surface.Width << "x" << surface.Height << " Format: " << surface.Format << " dwCaps: " << surfaceDesc2.ddsCaps); - return DDERR_GENERIC; - } - } - - // Create primary surface texture - if (!PrimaryDisplayTexture && ShouldPresentToWindow(false)) - { - D3DSURFACE_DESC Desc; - if (FAILED(surface.Surface ? surface.Surface->GetDesc(&Desc) : surface.Texture->GetLevelDesc(0, &Desc)) || - FAILED((*d3d9Device)->CreateTexture(Desc.Width, Desc.Height, 1, 0, Desc.Format, D3DPOOL_DEFAULT, &PrimaryDisplayTexture, nullptr))) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create primary surface texture. Size: " << surface.Width << "x" << surface.Height << " Format: " << surface.Format << " dwCaps: " << surfaceDesc2.ddsCaps); - return DDERR_GENERIC; - } - } - - // Create palette surface - if (!primary.PaletteTexture && IsPrimarySurface() && surface.Format == D3DFMT_P8) - { - if (FAILED((*d3d9Device)->CreateTexture(MaxPaletteSize, MaxPaletteSize, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &primary.PaletteTexture, nullptr))) - { - // Try failover format - if (FAILED((*d3d9Device)->CreateTexture(MaxPaletteSize, MaxPaletteSize, 1, 0, GetFailoverFormat(D3DFMT_X8R8G8B8), D3DPOOL_MANAGED, &primary.PaletteTexture, nullptr))) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create palette surface texture"); - return DDERR_GENERIC; - } - } - } - - // Reset flags - RecreateAuxiliarySurfaces = false; - surface.RecreateAuxiliarySurfaces = false; - - return DD_OK; -} - -// Create surface HRESULT m_IDirectDrawSurfaceX::CreateD9Surface() { // Don't recreate surface while it is locked @@ -4697,7 +4410,7 @@ HRESULT m_IDirectDrawSurfaceX::CreateD9Surface() return DDERR_GENERIC; } - SetLockCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; // Release existing surface ReleaseD9Surface(true, false); @@ -4934,9 +4647,9 @@ HRESULT m_IDirectDrawSurfaceX::CreateD9Surface() } else { - LPDIRECT3DSURFACE9 SrcSurface = nullptr; + ComPtr SrcSurface; DWORD t_Width = 128, t_Height = 128; - if (SUCCEEDED((*d3d9Device)->CreateOffscreenPlainSurface(t_Width, t_Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &SrcSurface, nullptr))) + if (SUCCEEDED((*d3d9Device)->CreateOffscreenPlainSurface(t_Width, t_Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, SrcSurface.GetAddressOf(), nullptr))) { D3DCOLOR NewColor = (Colors[Count].a & 0xFF000000) + @@ -4960,10 +4673,9 @@ HRESULT m_IDirectDrawSurfaceX::CreateD9Surface() LPDIRECT3DSURFACE9 DstSurface = Get3DSurface(); if (DstSurface) { - D3DXLoadSurfaceFromSurface(DstSurface, nullptr, nullptr, SrcSurface, nullptr, nullptr, D3DX_FILTER_POINT, 0); + D3DXLoadSurfaceFromSurface(DstSurface, nullptr, nullptr, SrcSurface.Get(), nullptr, nullptr, D3DX_FILTER_POINT, 0); } } - SrcSurface->Release(); } } if (++Count >= 24) @@ -5060,11 +4772,10 @@ HRESULT m_IDirectDrawSurfaceX::CreateD9Surface() IDirect3DSurface9* pSrcSurfaceD9 = Get3DSurface(); if (pSrcSurfaceD9) { - IDirect3DSurface9* pPrimaryDisplaySurfaceD9 = nullptr; - if (SUCCEEDED(PrimaryDisplayTexture->GetSurfaceLevel(0, &pPrimaryDisplaySurfaceD9))) + ComPtr pPrimaryDisplaySurfaceD9; + if (SUCCEEDED(PrimaryDisplayTexture->GetSurfaceLevel(0, pPrimaryDisplaySurfaceD9.GetAddressOf()))) { - D3DXLoadSurfaceFromSurface(pPrimaryDisplaySurfaceD9, nullptr, nullptr, pSrcSurfaceD9, nullptr, nullptr, D3DX_FILTER_NONE, 0); - pPrimaryDisplaySurfaceD9->Release(); + D3DXLoadSurfaceFromSurface(pPrimaryDisplaySurfaceD9.Get(), nullptr, nullptr, pSrcSurfaceD9, nullptr, nullptr, D3DX_FILTER_NONE, 0); } } } @@ -5079,12 +4790,10 @@ HRESULT m_IDirectDrawSurfaceX::CreateD9Surface() ReleaseDCSurface(); } - ReleaseLockCriticalSection(); - return hr; } -inline bool m_IDirectDrawSurfaceX::DoesDCMatch(EMUSURFACE* pEmuSurface) const +bool m_IDirectDrawSurfaceX::DoesDCMatch(EMUSURFACE* pEmuSurface) const { if (!pEmuSurface || !pEmuSurface->DC || !pEmuSurface->pBits) { @@ -5108,7 +4817,7 @@ inline bool m_IDirectDrawSurfaceX::DoesDCMatch(EMUSURFACE* pEmuSurface) const return false; } -inline void m_IDirectDrawSurfaceX::SetEmulationGameDC() +void m_IDirectDrawSurfaceX::SetEmulationGameDC() { if (IsUsingEmulation() && !surface.emu->UsingGameDC) { @@ -5131,7 +4840,7 @@ inline void m_IDirectDrawSurfaceX::SetEmulationGameDC() } } -inline void m_IDirectDrawSurfaceX::UnsetEmulationGameDC() +void m_IDirectDrawSurfaceX::UnsetEmulationGameDC() { if (IsUsingEmulation() && surface.emu->UsingGameDC) { @@ -5156,6 +4865,8 @@ inline void m_IDirectDrawSurfaceX::UnsetEmulationGameDC() HRESULT m_IDirectDrawSurfaceX::CreateDCSurface() { + ScopedDDCriticalSection ThreadLockDD; + // Check if color masks are needed bool ColorMaskReq = ((surface.BitCount == 16 || surface.BitCount == 24 || surface.BitCount == 32) && // Only valid when used with 16 bit, 24 bit and 32 bit surfaces (surfaceDesc2.ddpfPixelFormat.dwRBitMask || surfaceDesc2.ddpfPixelFormat.dwGBitMask || surfaceDesc2.ddpfPixelFormat.dwBBitMask)); // Check to make sure the masks actually exist @@ -5187,10 +4898,8 @@ HRESULT m_IDirectDrawSurfaceX::CreateDCSurface() // Save current emulated surface and prepare for creating a new one. if (ShareEmulatedMemory) { - SetCriticalSection(); memorySurfaces.push_back(surface.emu); surface.emu = nullptr; - ReleaseCriticalSection(); } else { @@ -5202,7 +4911,6 @@ HRESULT m_IDirectDrawSurfaceX::CreateDCSurface() // If sharing memory than check the shared memory vector for a surface that matches if (ShareEmulatedMemory) { - SetCriticalSection(); for (auto it = memorySurfaces.begin(); it != memorySurfaces.end(); it++) { EMUSURFACE* pEmuSurface = *it; @@ -5216,7 +4924,6 @@ HRESULT m_IDirectDrawSurfaceX::CreateDCSurface() break; } } - ReleaseCriticalSection(); if (surface.emu && surface.emu->pBits) { @@ -5318,6 +5025,8 @@ void m_IDirectDrawSurfaceX::UpdateAttachedDepthStencil(m_IDirectDrawSurfaceX* lp // If depth stencil changed if (HasChanged) { + ScopedDDCriticalSection ThreadLockDD; + lpAttachedSurfaceX->ReleaseD9Surface(false, false); } // Set depth stencil @@ -5327,7 +5036,6 @@ void m_IDirectDrawSurfaceX::UpdateAttachedDepthStencil(m_IDirectDrawSurfaceX* lp } } -// Update surface description void m_IDirectDrawSurfaceX::UpdateSurfaceDesc() { bool IsChanged = false; @@ -5343,7 +5051,7 @@ void m_IDirectDrawSurfaceX::UpdateSurfaceDesc() if (Width && Height && (surfaceDesc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT)) != (DDSD_WIDTH | DDSD_HEIGHT)) { - ResetDisplayFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH; + ResetDisplayFlags |= DDSD_WIDTH | DDSD_HEIGHT; surfaceDesc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT; surfaceDesc2.dwWidth = Width; surfaceDesc2.dwHeight = Height; @@ -5359,7 +5067,7 @@ void m_IDirectDrawSurfaceX::UpdateSurfaceDesc() // Set PixelFormat if (BPP && !(surfaceDesc2.dwFlags & DDSD_PIXELFORMAT)) { - ResetDisplayFlags |= DDSD_PIXELFORMAT | DDSD_PITCH; + ResetDisplayFlags |= DDSD_PIXELFORMAT; surfaceDesc2.dwFlags |= DDSD_PIXELFORMAT; ddrawParent->GetDisplayPixelFormat(surfaceDesc2.ddpfPixelFormat, BPP); surfaceDesc2.lPitch = 0; @@ -5411,6 +5119,8 @@ void m_IDirectDrawSurfaceX::UpdateSurfaceDesc() m_IDirectDrawSurfaceX* lpAttachedSurfaceX = GetAttachedDepthStencil(); if (lpAttachedSurfaceX && (surfaceDesc2.dwWidth != lpAttachedSurfaceX->surfaceDesc2.dwWidth || surfaceDesc2.dwHeight != lpAttachedSurfaceX->surfaceDesc2.dwHeight)) { + ScopedDDCriticalSection ThreadLockDD; + lpAttachedSurfaceX->ReleaseD9Surface(false, false); lpAttachedSurfaceX->surfaceDesc2.dwWidth = surfaceDesc2.dwWidth; lpAttachedSurfaceX->surfaceDesc2.dwHeight = surfaceDesc2.dwHeight; @@ -5468,7 +5178,6 @@ void m_IDirectDrawSurfaceX::ClearUsing3DFlag() } } -// Release surface and vertext buffer void m_IDirectDrawSurfaceX::ReleaseD9AuxiliarySurfaces() { // Release d3d9 shadow surface when surface is released @@ -5560,10 +5269,9 @@ void m_IDirectDrawSurfaceX::ReleaseD9AuxiliarySurfaces() surface.RecreateAuxiliarySurfaces = true; } -// Release surface and vertext buffer void m_IDirectDrawSurfaceX::ReleaseD9Surface(bool BackupData, bool ResetSurface) { - SetLockCriticalSection(); + // To avoid threadlock, cannot have any critical sections in this function or any sub-functions // Check if surface is busy if (IsSurfaceBusy()) @@ -5601,7 +5309,7 @@ void m_IDirectDrawSurfaceX::ReleaseD9Surface(bool BackupData, bool ResetSurface) // Backup d3d9 surface texture if (BackupData) { - if (surface.HasData && (surface.Surface || surface.Texture) && !IsRenderTarget() && !IsDepthStencil() && (!ResetSurface || IsD9UsingVideoMemory())) + if (surface.HasData && (surface.Surface || surface.Texture) && !(surface.Usage & D3DUSAGE_RENDERTARGET) && !IsDepthStencil() && (!ResetSurface || IsD9UsingVideoMemory())) { IsSurfaceLost = true; @@ -5693,35 +5401,32 @@ void m_IDirectDrawSurfaceX::ReleaseD9Surface(bool BackupData, bool ResetSurface) if (ResetDisplayFlags && !ResetSurface) { surfaceDesc2.dwFlags &= ~ResetDisplayFlags; + ClearUnusedValues(surfaceDesc2); } if (surfaceDesc2.dwFlags & DDSD_REFRESHRATE) { surfaceDesc2.dwRefreshRate = 0; } - - ReleaseLockCriticalSection(); } -// Release emulated surface -inline void m_IDirectDrawSurfaceX::ReleaseDCSurface() +void m_IDirectDrawSurfaceX::ReleaseDCSurface() { if (surface.emu) { + ScopedDDCriticalSection ThreadLockDD; + if (!ShareEmulatedMemory || !IsUsingEmulation()) { DeleteEmulatedMemory(&surface.emu); } else { - SetCriticalSection(); memorySurfaces.push_back(surface.emu); surface.emu = nullptr; - ReleaseCriticalSection(); } } } -// Present surface HRESULT m_IDirectDrawSurfaceX::PresentSurface(bool IsSkipScene) { // Check for device interface @@ -5782,7 +5487,6 @@ HRESULT m_IDirectDrawSurfaceX::PresentSurface(bool IsSkipScene) return hr; } -// Reset primary surface display settings void m_IDirectDrawSurfaceX::ResetSurfaceDisplay() { if (ResetDisplayFlags) @@ -5791,8 +5495,7 @@ void m_IDirectDrawSurfaceX::ResetSurfaceDisplay() } } -// Check surface reck dimensions and copy rect to new rect -inline bool m_IDirectDrawSurfaceX::CheckCoordinates(RECT& OutRect, LPRECT lpInRect, LPDDSURFACEDESC2 lpDDSurfaceDesc2) +bool m_IDirectDrawSurfaceX::CheckCoordinates(RECT& OutRect, LPRECT lpInRect, LPDDSURFACEDESC2 lpDDSurfaceDesc2) { if (!lpDDSurfaceDesc2) { @@ -5864,7 +5567,6 @@ inline bool m_IDirectDrawSurfaceX::CheckCoordinates(RECT& OutRect, LPRECT lpInRe return OutRect.left < OutRect.right && OutRect.top < OutRect.bottom; } -// Fix issue with some games that ignore the pitch size void m_IDirectDrawSurfaceX::LockEmuLock(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSurfaceDesc) { // Only works if entire surface is locked @@ -5921,7 +5623,6 @@ void m_IDirectDrawSurfaceX::LockEmuLock(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDD } } -// Fix issue with some games that ignore the pitch size void m_IDirectDrawSurfaceX::UnlockEmuLock() { if (EmuLock.Locked && EmuLock.Addr) @@ -5944,7 +5645,6 @@ void m_IDirectDrawSurfaceX::UnlockEmuLock() } } -// Restore removed scanlines before locking surface void m_IDirectDrawSurfaceX::RestoreScanlines(LASTLOCK& LLock) const { DWORD ByteCount = surface.BitCount / 8; @@ -5986,7 +5686,6 @@ void m_IDirectDrawSurfaceX::RestoreScanlines(LASTLOCK& LLock) const } } -// Remove scanlines before unlocking surface void m_IDirectDrawSurfaceX::RemoveScanlines(LASTLOCK& LLock) const { DWORD ByteCount = surface.BitCount / 8; @@ -6087,7 +5786,7 @@ void m_IDirectDrawSurfaceX::RemoveScanlines(LASTLOCK& LLock) const } } -inline HRESULT m_IDirectDrawSurfaceX::LockEmulatedSurface(D3DLOCKED_RECT* pLockedRect, LPRECT lpDestRect) const +HRESULT m_IDirectDrawSurfaceX::LockEmulatedSurface(D3DLOCKED_RECT* pLockedRect, LPRECT lpDestRect) const { if (!pLockedRect) { @@ -6132,7 +5831,6 @@ void m_IDirectDrawSurfaceX::SetRenderTargetShadow() } } -// Set dirty flag void m_IDirectDrawSurfaceX::SetDirtyFlag(DWORD MipMapLevel) { if (MipMapLevel == 0) @@ -6172,15 +5870,14 @@ void m_IDirectDrawSurfaceX::ClearDirtyFlags() SceneReady = false; } -// Check if rect is a single line and should be skipped -inline bool m_IDirectDrawSurfaceX::CheckRectforSkipScene(RECT& DestRect) +bool m_IDirectDrawSurfaceX::CheckRectforSkipScene(RECT& DestRect) { bool isSingleLine = (DestRect.bottom - DestRect.top == 1); // Only handles horizontal lines at this point return Config.DdrawRemoveInterlacing ? isSingleLine : false; } -inline void m_IDirectDrawSurfaceX::BeginWritePresent(bool IsSkipScene) +void m_IDirectDrawSurfaceX::BeginWritePresent(bool IsSkipScene) { // Check if data needs to be presented before write if (dirtyFlag) @@ -6192,7 +5889,7 @@ inline void m_IDirectDrawSurfaceX::BeginWritePresent(bool IsSkipScene) } } -inline void m_IDirectDrawSurfaceX::EndWritePresent(LPRECT lpDestRect, bool WriteToWindow, bool FullPresent, bool IsSkipScene) +void m_IDirectDrawSurfaceX::EndWritePresent(LPRECT lpDestRect, bool WriteToWindow, bool FullPresent, bool IsSkipScene) { // Handle overlays PresentOverlay(lpDestRect); @@ -6227,7 +5924,7 @@ inline void m_IDirectDrawSurfaceX::EndWritePresent(LPRECT lpDestRect, bool Write } } -inline void m_IDirectDrawSurfaceX::EndWriteSyncSurfaces(LPRECT lpDestRect) +void m_IDirectDrawSurfaceX::EndWriteSyncSurfaces(LPRECT lpDestRect) { // Copy emulated surface to real surface if (IsUsingEmulation()) @@ -6236,8 +5933,7 @@ inline void m_IDirectDrawSurfaceX::EndWriteSyncSurfaces(LPRECT lpDestRect) } } -// Update surface description and create backbuffers -inline void m_IDirectDrawSurfaceX::InitSurfaceDesc(DWORD DirectXVersion) +void m_IDirectDrawSurfaceX::InitSurfaceDesc(DWORD DirectXVersion) { // Update dds caps flags surfaceDesc2.dwFlags |= DDSD_CAPS; @@ -6250,50 +5946,48 @@ inline void m_IDirectDrawSurfaceX::InitSurfaceDesc(DWORD DirectXVersion) surfaceDesc2.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY; surfaceDesc2.ddsCaps.dwCaps &= ~DDSCAPS_NONLOCALVIDMEM; } - if ((surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX) && (surfaceDesc2.ddsCaps.dwCaps4 & DDSCAPS4_CREATESURFACE)) - { - ComplexRoot = true; - } // Create backbuffers - if (surfaceDesc2.dwBackBufferCount) + if ((surfaceDesc2.dwFlags & DDSD_BACKBUFFERCOUNT) && surfaceDesc2.dwBackBufferCount) { DDSURFACEDESC2 Desc2 = surfaceDesc2; Desc2.ddsCaps.dwCaps4 &= ~(DDSCAPS4_CREATESURFACE); // Clear surface creation flag Desc2.dwBackBufferCount--; - if (Desc2.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) + Desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; + Desc2.ddsCaps.dwCaps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER); + Desc2.ddsCaps.dwCaps4 |= DDSCAPS4_COMPLEXCHILD; + + if (surfaceDesc2.ddsCaps.dwCaps4 & DDSCAPS4_CREATESURFACE) { - Desc2.ddsCaps.dwCaps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER); - Desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; + ComplexRoot = true; Desc2.dwReserved = (DWORD)this; } // Create complex surfaces - if (Desc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX) - { - BackBufferInterface = std::make_unique(ddrawParent, DirectXVersion, &Desc2); + BackBufferInterface = std::make_unique(ddrawParent, DirectXVersion, &Desc2); - m_IDirectDrawSurfaceX *attachedSurface = BackBufferInterface.get(); + m_IDirectDrawSurfaceX* attachedSurface = BackBufferInterface.get(); - AddAttachedSurfaceToMap(attachedSurface, false, DirectXVersion, 1); - } - else - { - m_IDirectDrawSurfaceX *attachedSurface = new m_IDirectDrawSurfaceX(ddrawParent, DirectXVersion, &Desc2); - - AddAttachedSurfaceToMap(attachedSurface, false, DirectXVersion, 0); - } + AddAttachedSurfaceToMap(attachedSurface, false, DirectXVersion, 1); } - // Add first surface as attached surface to the last surface in a surface chain - else if (surfaceDesc2.dwReserved) + // Set flags for complex child surface + if (surfaceDesc2.ddsCaps.dwCaps4 & DDSCAPS4_COMPLEXCHILD) { - m_IDirectDrawSurfaceX *attachedSurface = (m_IDirectDrawSurfaceX *)surfaceDesc2.dwReserved; + ComplexChild = true; + surfaceDesc2.dwFlags &= ~DDSD_BACKBUFFERCOUNT; + surfaceDesc2.dwBackBufferCount = 0; - // Check if source Surface exists and add to surface map - if (ddrawParent && ddrawParent->DoesSurfaceExist(attachedSurface)) + // Add first surface as attached surface to the last surface in a surface chain + if (surfaceDesc2.dwReserved) { - AddAttachedSurfaceToMap(attachedSurface, false, DirectXVersion, 0); + m_IDirectDrawSurfaceX* attachedSurface = (m_IDirectDrawSurfaceX*)surfaceDesc2.dwReserved; + + // Check if source Surface exists add to surface map + if (ddrawParent && ddrawParent->DoesSurfaceExist(attachedSurface)) + { + AddAttachedSurfaceToMap(attachedSurface, false, DirectXVersion, 0); + } } } @@ -6344,19 +6038,13 @@ inline void m_IDirectDrawSurfaceX::InitSurfaceDesc(DWORD DirectXVersion) surface.UsingSurfaceMemory = ((surfaceDesc2.dwFlags & DDSD_LPSURFACE) && surfaceDesc2.lpSurface); // Clear flags used in creating a surface structure - if (!(surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)) - { - surfaceDesc2.dwFlags &= ~DDSD_BACKBUFFERCOUNT; - surfaceDesc2.dwBackBufferCount = 0; - } - surfaceDesc2.ddsCaps.dwCaps4 = 0x00; + surfaceDesc2.ddsCaps.dwCaps4 = 0; surfaceDesc2.dwReserved = 0; // Clear unused values ClearUnusedValues(surfaceDesc2); } -// Add attached surface to map void m_IDirectDrawSurfaceX::AddAttachedSurfaceToMap(m_IDirectDrawSurfaceX* lpSurfaceX, bool MarkAttached, DWORD DxVersion, DWORD RefCount) { if (!lpSurfaceX) @@ -6377,7 +6065,6 @@ void m_IDirectDrawSurfaceX::AddAttachedSurfaceToMap(m_IDirectDrawSurfaceX* lpSur } } -// Remove attached surface from map void m_IDirectDrawSurfaceX::RemoveAttachedSurfaceFromMap(m_IDirectDrawSurfaceX* lpSurfaceX) { auto it = std::find_if(AttachedSurfaceMap.begin(), AttachedSurfaceMap.end(), @@ -6387,13 +6074,13 @@ void m_IDirectDrawSurfaceX::RemoveAttachedSurfaceFromMap(m_IDirectDrawSurfaceX* { if (it->second.RefCount == 1) { + it->second.RefCount = 0; // Clear ref count before release it->second.pSurface->Release(it->second.DxVersion); } AttachedSurfaceMap.erase(it); } } -// Check if attached surface exists bool m_IDirectDrawSurfaceX::DoesAttachedSurfaceExist(m_IDirectDrawSurfaceX* lpSurfaceX) { if (!lpSurfaceX) @@ -6416,7 +6103,6 @@ bool m_IDirectDrawSurfaceX::WasAttachedSurfaceAdded(m_IDirectDrawSurfaceX* lpSur [=](auto Map) -> bool { return (Map.second.pSurface == lpSurfaceX) && Map.second.isAttachedSurfaceAdded; }) != std::end(AttachedSurfaceMap)); } -// Check if backbuffer surface exists bool m_IDirectDrawSurfaceX::DoesFlipBackBufferExist(m_IDirectDrawSurfaceX* lpSurfaceX) { if (!lpSurfaceX) @@ -6604,7 +6290,6 @@ HRESULT m_IDirectDrawSurfaceX::ColorFill(RECT* pRect, D3DCOLOR dwFillColor, DWOR return DD_OK; } -// Save DXT data as a DDS file HRESULT m_IDirectDrawSurfaceX::SaveDXTDataToDDS(const void *data, size_t dataSize, const char *filename, int dxtVersion) const { int blockSize = 0; @@ -6663,80 +6348,90 @@ HRESULT m_IDirectDrawSurfaceX::SaveDXTDataToDDS(const void *data, size_t dataSiz return DDERR_GENERIC; } -// Save a surface for debugging -HRESULT m_IDirectDrawSurfaceX::SaveSurfaceToFile(const char *filename, D3DXIMAGE_FILEFORMAT format) +HRESULT m_IDirectDrawSurfaceX::Load(LPDIRECTDRAWSURFACE7 lpDestTex, LPPOINT lpDestPoint, LPDIRECTDRAWSURFACE7 lpSrcTex, LPRECT lprcSrcRect, DWORD dwFlags) { - LPD3DXBUFFER pDestBuf = nullptr; - HRESULT hr = D3DXSaveSurfaceToFileInMemory(&pDestBuf, format, Get3DSurface(), nullptr, nullptr); - - if (SUCCEEDED(hr)) + if (!lpDestTex || !lpSrcTex) { - // Save the buffer to a file - std::ofstream outFile(filename, std::ios::binary | std::ios::out); - if (outFile.is_open()) - { - outFile.write((const char*)pDestBuf->GetBufferPointer(), pDestBuf->GetBufferSize()); - outFile.close(); - } - - // Release the buffer - pDestBuf->Release(); + return DDERR_INVALIDPARAMS; } - return hr; -} + // ToDo: support the following dwFlags: + // DDSCAPS2_CUBEMAP_ALLFACES - All faces should be loaded with the image data within the source texture. + // DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_NEGATIVEY, or DDSCAPS2_CUBEMAP_NEGATIVEZ + // The negative x, y, or z faces should receive the image data. + // DDSCAPS2_CUBEMAP_POSITIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, or DDSCAPS2_CUBEMAP_POSITIVEZ + // The positive x, y, or z faces should receive the image data. -// Simple copy with ColorKey and Mirroring -template -void SimpleColorKeyCopy(T ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight) -{ - T* SrcBufferLoop = reinterpret_cast(SrcBuffer); - T* DestBufferLoop = reinterpret_cast(DestBuffer); + if (dwFlags) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: flags not supported. dwFlags: " << Logging::hex(dwFlags)); + } - for (LONG y = 0; y < DestRectHeight; y++) + if (!lprcSrcRect && (!lpDestPoint || (lpDestPoint && lpDestPoint->x == 0 && lpDestPoint->y == 0))) + { + return lpDestTex->Blt(nullptr, lpSrcTex, nullptr, 0, nullptr); + } + else { - for (LONG x = 0; x < DestRectWidth; x++) + // Get source rect + RECT SrcRect = {}; + if (lprcSrcRect) { - T PixelColor = SrcBufferLoop[IsMirrorLeftRight ? DestRectWidth - x - 1 : x]; - if (!IsColorKey || PixelColor != ColorKey) + SrcRect = *lprcSrcRect; + } + else + { + DDSURFACEDESC2 Desc2 = {}; + Desc2.dwSize = sizeof(DDSURFACEDESC2); + lpSrcTex->GetSurfaceDesc(&Desc2); + + if ((Desc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT)) != (DDSD_WIDTH | DDSD_HEIGHT)) { - DestBufferLoop[x] = PixelColor; + LOG_LIMIT(100, __FUNCTION__ << " Error: rect size doesn't match!"); + return DDERR_GENERIC; } + + SrcRect = { 0, 0, (LONG)Desc2.dwWidth, (LONG)Desc2.dwHeight }; + } + + // Get destination point + POINT DestPoint = {}; + if (lpDestPoint) + { + DestPoint = *lpDestPoint; } - SrcBufferLoop = reinterpret_cast((BYTE*)SrcBufferLoop + SrcPitch); - DestBufferLoop = reinterpret_cast((BYTE*)DestBufferLoop + DestPitch); + + // Get destination rect + RECT DestRect = { + DestPoint.x, // left + DestPoint.y, // top + DestPoint.x + (SrcRect.right - SrcRect.left), // right + DestPoint.y + (SrcRect.bottom - SrcRect.top), // bottom + }; + + return lpDestTex->Blt(&DestRect, lpSrcTex, &SrcRect, 0, nullptr); } } -// Copy memory (complex) -template -void ComplexCopy(T ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight) +HRESULT m_IDirectDrawSurfaceX::SaveSurfaceToFile(const char *filename, D3DXIMAGE_FILEFORMAT format) { - float WidthRatio = ((float)SrcRectWidth / (float)DestRectWidth); - float HeightRatio = ((float)SrcRectHeight / (float)DestRectHeight); + ComPtr pDestBuf; + HRESULT hr = D3DXSaveSurfaceToFileInMemory(pDestBuf.GetAddressOf(), format, Get3DSurface(), nullptr, nullptr); - T* SrcBufferLoop = reinterpret_cast(SrcLockRect.pBits); - T* DestBufferLoop = reinterpret_cast(DestLockRect.pBits); - - for (LONG y = 0; y < DestRectHeight; y++) + if (SUCCEEDED(hr)) { - for (LONG x = 0; x < DestRectWidth; x++) + // Save the buffer to a file + std::ofstream outFile(filename, std::ios::binary | std::ios::out); + if (outFile.is_open()) { - DWORD sx = (DWORD)((float)x * WidthRatio); - T PixelColor = SrcBufferLoop[IsMirrorLeftRight ? SrcRectWidth - sx - 1 : sx]; - - if (!IsColorKey || PixelColor != ColorKey) - { - DestBufferLoop[x] = PixelColor; - } + outFile.write((const char*)pDestBuf->GetBufferPointer(), pDestBuf->GetBufferSize()); + outFile.close(); } - DWORD sx = (DWORD)((float)(y + 1) * HeightRatio); - SrcBufferLoop = reinterpret_cast((BYTE*)SrcLockRect.pBits + SrcLockRect.Pitch * (IsMirrorUpDown ? SrcRectHeight - sx - 1 : sx)); - DestBufferLoop = reinterpret_cast((BYTE*)DestBufferLoop + DestLockRect.Pitch); } + + return hr; } -// Copy surface HRESULT m_IDirectDrawSurfaceX::CopySurface(m_IDirectDrawSurfaceX* pSourceSurface, RECT* pSourceRect, RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter, D3DCOLOR ColorKey, DWORD dwFlags, DWORD SrcMipMapLevel, DWORD MipMapLevel) { // Check parameters @@ -7294,8 +6989,8 @@ HRESULT m_IDirectDrawSurfaceX::CopyToDrawTexture(LPRECT lpDestRect) } IDirect3DSurface9* SrcSurface = Get3DMipMapSurface(0); - IDirect3DSurface9* DestSurface = nullptr; - if (!SrcSurface || FAILED(surface.DrawTexture->GetSurfaceLevel(0, &DestSurface))) + ComPtr DestSurface; + if (!SrcSurface || FAILED(surface.DrawTexture->GetSurfaceLevel(0, DestSurface.GetAddressOf()))) { LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get surface texture!"); return DDERR_GENERIC; @@ -7320,19 +7015,15 @@ HRESULT m_IDirectDrawSurfaceX::CopyToDrawTexture(LPRECT lpDestRect) } } - if (FAILED(D3DXLoadSurfaceFromSurface(DestSurface, nullptr, lpDestRect, SrcSurface, surface.PaletteEntryArray, lpDestRect, D3DX_FILTER_NONE, ColorKey))) + if (FAILED(D3DXLoadSurfaceFromSurface(DestSurface.Get(), nullptr, lpDestRect, SrcSurface, surface.PaletteEntryArray, lpDestRect, D3DX_FILTER_NONE, ColorKey))) { Logging::Log() << __FUNCTION__ " Error: failed to copy data from surface: " << surface.Format << " " << (void*)ColorKey << " " << lpDestRect; - DestSurface->Release(); - return DDERR_GENERIC; } surface.IsDrawTextureDirty = false; - DestSurface->Release(); - return DD_OK; } @@ -7428,7 +7119,6 @@ HRESULT m_IDirectDrawSurfaceX::LoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSur return DD_OK; } -// Copy from emulated surface to real surface HRESULT m_IDirectDrawSurfaceX::CopyFromEmulatedSurface(LPRECT lpDestRect) { if (!IsUsingEmulation()) @@ -7469,7 +7159,6 @@ HRESULT m_IDirectDrawSurfaceX::CopyFromEmulatedSurface(LPRECT lpDestRect) return DD_OK; } -// Copy from real surface to emulated surface HRESULT m_IDirectDrawSurfaceX::CopyToEmulatedSurface(LPRECT lpDestRect) { if (!IsUsingEmulation()) @@ -7610,7 +7299,7 @@ HRESULT m_IDirectDrawSurfaceX::CopyToEmulatedSurface(LPRECT lpDestRect) return hr; } -inline HRESULT m_IDirectDrawSurfaceX::CopyEmulatedPaletteSurface(LPRECT lpDestRect) +HRESULT m_IDirectDrawSurfaceX::CopyEmulatedPaletteSurface(LPRECT lpDestRect) { if (!IsPalette()) { @@ -7623,7 +7312,7 @@ inline HRESULT m_IDirectDrawSurfaceX::CopyEmulatedPaletteSurface(LPRECT lpDestRe return DDERR_GENERIC; } - SetCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; HRESULT hr = DD_OK; @@ -7692,8 +7381,6 @@ inline HRESULT m_IDirectDrawSurfaceX::CopyEmulatedPaletteSurface(LPRECT lpDestRe } while (false); - ReleaseCriticalSection(); - return hr; } @@ -7915,8 +7602,8 @@ HRESULT m_IDirectDrawSurfaceX::GetPresentWindowRect(LPRECT pRect, RECT& DestRect } // Get destination surface - IDirect3DSurface9* pDestSurfaceD9 = nullptr; - if (FAILED(PrimaryDisplayTexture->GetSurfaceLevel(0, &pDestSurfaceD9))) + ComPtr pDestSurfaceD9; + if (FAILED(PrimaryDisplayTexture->GetSurfaceLevel(0, pDestSurfaceD9.GetAddressOf()))) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to get destination surface!"); return DDERR_GENERIC; @@ -7926,13 +7613,13 @@ HRESULT m_IDirectDrawSurfaceX::GetPresentWindowRect(LPRECT pRect, RECT& DestRect HRESULT hr = DDERR_GENERIC; if (IsD9UsingVideoMemory()) { - hr = (*d3d9Device)->StretchRect(pSourceSurfaceD9, &Rect, pDestSurfaceD9, &MapClient, D3DTEXF_NONE); + hr = (*d3d9Device)->StretchRect(pSourceSurfaceD9, &Rect, pDestSurfaceD9.Get(), &MapClient, D3DTEXF_NONE); } else { - hr = (*d3d9Device)->UpdateSurface(pSourceSurfaceD9, &Rect, pDestSurfaceD9, (LPPOINT)&MapClient); + hr = (*d3d9Device)->UpdateSurface(pSourceSurfaceD9, &Rect, pDestSurfaceD9.Get(), (LPPOINT)&MapClient); } - pDestSurfaceD9->Release(); + if (FAILED(hr)) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to copy surface: " << Rect << " -> " << MapClient); @@ -7972,7 +7659,7 @@ void m_IDirectDrawSurfaceX::UpdatePaletteData() const PALETTEENTRY* NewPaletteEntry = nullptr; const RGBQUAD* NewRGBPalette = nullptr; - SetCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; // Get palette data if (attachedPalette) @@ -8001,16 +7688,15 @@ void m_IDirectDrawSurfaceX::UpdatePaletteData() if (primary.PaletteTexture && NewPaletteEntry && primary.LastPaletteUSN != NewPaletteUSN) { // Get palette display context surface - LPDIRECT3DSURFACE9 paletteSurface = nullptr; - if (SUCCEEDED(primary.PaletteTexture->GetSurfaceLevel(0, &paletteSurface))) + ComPtr paletteSurface; + if (SUCCEEDED(primary.PaletteTexture->GetSurfaceLevel(0, paletteSurface.GetAddressOf()))) { // Use LoadSurfaceFromMemory to copy to the surface RECT Rect = { 0, 0, MaxPaletteSize, 1 }; - if (FAILED(LoadSurfaceFromMemory(paletteSurface, Rect, NewRGBPalette, D3DFMT_X8R8G8B8, MaxPaletteSize * sizeof(D3DCOLOR)))) + if (FAILED(LoadSurfaceFromMemory(paletteSurface.Get(), Rect, NewRGBPalette, D3DFMT_X8R8G8B8, MaxPaletteSize * sizeof(D3DCOLOR)))) { LOG_LIMIT(100, __FUNCTION__ << " Warning: could not full palette textur!"); } - paletteSurface->Release(); primary.LastPaletteUSN = NewPaletteUSN; } } @@ -8030,10 +7716,286 @@ void m_IDirectDrawSurfaceX::UpdatePaletteData() surface.LastPaletteUSN = NewPaletteUSN; surface.PaletteEntryArray = NewPaletteEntry; } +} + +m_IDirectDrawSurfaceX* m_IDirectDrawSurfaceX::GetAttachedDepthStencil() +{ + for (auto& it : AttachedSurfaceMap) + { + if (it.second.pSurface->IsDepthStencil()) + { + return it.second.pSurface; + } + } + return nullptr; +} + +HRESULT m_IDirectDrawSurfaceX::GetMipMapLevelAddr(LPDIRECTDRAWSURFACE7 FAR* lplpDDAttachedSurface, MIPMAP& MipMapSurface, DWORD MipMapLevel, DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 1: + if (!MipMapSurface.Addr) + { + MipMapSurface.Addr = new m_IDirectDrawSurface(this, MipMapLevel); + } + *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr; + break; + case 2: + if (!MipMapSurface.Addr2) + { + MipMapSurface.Addr2 = new m_IDirectDrawSurface2(this, MipMapLevel); + } + *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr2; + break; + case 3: + if (!MipMapSurface.Addr3) + { + MipMapSurface.Addr3 = new m_IDirectDrawSurface3(this, MipMapLevel); + } + *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr3; + break; + case 4: + if (!MipMapSurface.Addr4) + { + MipMapSurface.Addr4 = new m_IDirectDrawSurface4(this, MipMapLevel); + } + *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr4; + break; + case 7: + if (!MipMapSurface.Addr7) + { + MipMapSurface.Addr7 = new m_IDirectDrawSurface7(this, MipMapLevel); + } + *lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)MipMapSurface.Addr7; + break; + default: + LOG_LIMIT(100, __FUNCTION__ << " Error: incorrect DirectX version: " << DirectXVersion); + return DDERR_NOTFOUND; + } + + return DD_OK; +} + +HRESULT m_IDirectDrawSurfaceX::GetMipMapSubLevel(LPDIRECTDRAWSURFACE7 FAR* lplpDDAttachedSurface, DWORD MipMapLevel, DWORD DirectXVersion) +{ + // Check for device interface to ensure correct max MipMap level + CheckInterface(__FUNCTION__, true, true, false); + + if (MaxMipMapLevel > MipMapLevel) + { + while (MipMaps.size() < MipMapLevel + 1) + { + MIPMAP MipMap; + MipMaps.push_back(MipMap); + } + + return GetMipMapLevelAddr(lplpDDAttachedSurface, MipMaps[MipMapLevel], MipMapLevel + 1, DirectXVersion); + } + return DDERR_NOTFOUND; +} + +HRESULT m_IDirectDrawSurfaceX::CheckBackBufferForFlip(m_IDirectDrawSurfaceX* lpTargetSurface) +{ + // Check if target surface exists + if (!lpTargetSurface || lpTargetSurface == this || !DoesFlipBackBufferExist(lpTargetSurface)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid surface!"); + return DDERR_INVALIDPARAMS; + } + + // Make sure that surface description on target is updated + lpTargetSurface->UpdateSurfaceDesc(); + + // Check for device interface + HRESULT c_hr = lpTargetSurface->CheckInterface(__FUNCTION__, true, true, true); + if (FAILED(c_hr)) + { + return c_hr; + } - ReleaseCriticalSection(); + // Check if surface format and size matches + if (surface.Format != lpTargetSurface->surface.Format || + surfaceDesc2.dwWidth != lpTargetSurface->surfaceDesc2.dwWidth || + surfaceDesc2.dwHeight != lpTargetSurface->surfaceDesc2.dwHeight) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: backbuffer surface does not match: " << + surface.Format << " -> " << lpTargetSurface->surface.Format << " " << + surfaceDesc2.dwWidth << "x" << surfaceDesc2.dwHeight << " -> " << + lpTargetSurface->surfaceDesc2.dwWidth << "x" << lpTargetSurface->surfaceDesc2.dwHeight); + return DDERR_INVALIDPARAMS; + } + + return DD_OK; } +bool m_IDirectDrawSurfaceX::GetColorKeyForPrimaryShader(float(&lowColorKey)[4], float(&highColorKey)[4]) +{ + // Primary 2D surface background color + if (IsPrimarySurface()) + { + if (!primary.ShaderColorKey.IsSet) + { + GetColorKeyArray(primary.ShaderColorKey.lowColorKey, primary.ShaderColorKey.highColorKey, Config.DdrawFlipFillColor, Config.DdrawFlipFillColor, surfaceDesc2.ddpfPixelFormat); + primary.ShaderColorKey.IsSet = true; + } + lowColorKey[0] = primary.ShaderColorKey.lowColorKey[0]; + lowColorKey[1] = primary.ShaderColorKey.lowColorKey[1]; + lowColorKey[2] = primary.ShaderColorKey.lowColorKey[2]; + lowColorKey[3] = primary.ShaderColorKey.lowColorKey[3]; + highColorKey[0] = primary.ShaderColorKey.highColorKey[0]; + highColorKey[1] = primary.ShaderColorKey.highColorKey[1]; + highColorKey[2] = primary.ShaderColorKey.highColorKey[2]; + highColorKey[3] = primary.ShaderColorKey.highColorKey[3]; + return true; + } + return false; +} + +bool m_IDirectDrawSurfaceX::GetColorKeyForShader(float(&lowColorKey)[4], float(&highColorKey)[4]) +{ + // Surface low and high color space + if (!ShaderColorKey.IsSet) + { + if (surfaceDesc2.dwFlags & DDSD_CKSRCBLT) + { + GetColorKeyArray(ShaderColorKey.lowColorKey, ShaderColorKey.highColorKey, + surfaceDesc2.ddckCKSrcBlt.dwColorSpaceLowValue, surfaceDesc2.ddckCKSrcBlt.dwColorSpaceHighValue, surfaceDesc2.ddpfPixelFormat); + ShaderColorKey.IsSet = true; + } + else + { + return false; + } + } + lowColorKey[0] = ShaderColorKey.lowColorKey[0]; + lowColorKey[1] = ShaderColorKey.lowColorKey[1]; + lowColorKey[2] = ShaderColorKey.lowColorKey[2]; + lowColorKey[3] = ShaderColorKey.lowColorKey[3]; + highColorKey[0] = ShaderColorKey.highColorKey[0]; + highColorKey[1] = ShaderColorKey.highColorKey[1]; + highColorKey[2] = ShaderColorKey.highColorKey[2]; + highColorKey[3] = ShaderColorKey.highColorKey[3]; + return true; +} + +void m_IDirectDrawSurfaceX::FixTextureFlags(LPDDSURFACEDESC2 lpDDSurfaceDesc2) +{ + if (lpDDSurfaceDesc2) + { + if (lpDDSurfaceDesc2->dwFlags & DDSD_PITCH) + { + lpDDSurfaceDesc2->dwFlags |= DDSD_LINEARSIZE; + } + lpDDSurfaceDesc2->dwFlags &= ~(DDSD_PITCH | DDSD_LPSURFACE); + } +} + +HRESULT m_IDirectDrawSurfaceX::LockD3d9Surface(D3DLOCKED_RECT* pLockedRect, RECT* pRect, DWORD Flags, DWORD MipMapLevel) +{ + if (surface.UsingSurfaceMemory) + { + pLockedRect->Pitch = surfaceDesc2.dwWidth * surface.BitCount / 8; + pLockedRect->pBits = (pRect) ? (void*)((DWORD)surfaceDesc2.lpSurface + ((pRect->top * pLockedRect->Pitch) + (pRect->left * (surface.BitCount / 8)))) : surfaceDesc2.lpSurface; + return DD_OK; + } + // Lock shadow surface + else if (IsUsingShadowSurface()) + { + HRESULT hr = surface.Shadow->LockRect(pLockedRect, pRect, Flags); + if (FAILED(hr) && (Flags & D3DLOCK_NOSYSLOCK)) + { + hr = surface.Shadow->LockRect(pLockedRect, pRect, Flags & ~D3DLOCK_NOSYSLOCK); + } + return hr; + } + // Lock 3D surface + else if (surface.Surface) + { + HRESULT hr = surface.Surface->LockRect(pLockedRect, pRect, Flags); + if (FAILED(hr) && (Flags & D3DLOCK_NOSYSLOCK)) + { + hr = surface.Surface->LockRect(pLockedRect, pRect, Flags & ~D3DLOCK_NOSYSLOCK); + } + return hr; + } + // Lock surface texture + else if (surface.Texture) + { + HRESULT hr = surface.Texture->LockRect(GetD3d9MipMapLevel(MipMapLevel), pLockedRect, pRect, Flags); + if (FAILED(hr) && (Flags & D3DLOCK_NOSYSLOCK)) + { + hr = surface.Texture->LockRect(GetD3d9MipMapLevel(MipMapLevel), pLockedRect, pRect, Flags & ~D3DLOCK_NOSYSLOCK); + } + return hr; + } + + return DDERR_GENERIC; +} + +HRESULT m_IDirectDrawSurfaceX::UnLockD3d9Surface(DWORD MipMapLevel) +{ + if (surface.UsingSurfaceMemory) + { + return DD_OK; + } + // Unlock shadow surface + else if (IsUsingShadowSurface()) + { + return surface.Shadow->UnlockRect(); + } + // Unlock 3D surface + else if (surface.Surface) + { + return surface.Surface->UnlockRect(); + } + // Unlock surface texture + else if (surface.Texture) + { + return surface.Texture->UnlockRect(GetD3d9MipMapLevel(MipMapLevel)); + } + + return DDERR_GENERIC; +} + +HRESULT m_IDirectDrawSurfaceX::PresentOverlay(LPRECT lpSrcRect) +{ + if (SurfaceOverlay.OverlayEnabled) + { + RECT SrcRect = {}; + if (!lpSrcRect || SurfaceOverlay.isSrcRectNull || GetOverlappingRect(*lpSrcRect, SurfaceOverlay.SrcRect, SrcRect)) + { + LPRECT lpNewSrcRect = SurfaceOverlay.isSrcRectNull ? nullptr : &SurfaceOverlay.SrcRect; + LPRECT lpNewDestRect = SurfaceOverlay.isDestRectNull ? nullptr : &SurfaceOverlay.DestRect; + + DWORD DDBltFxFlags = SurfaceOverlay.DDBltFxFlags; + DDBLTFX DDBltFx = SurfaceOverlay.DDBltFx; + + // Handle color keying + if (!(DDBltFxFlags & (DDBLT_KEYDESTOVERRIDE | DDBLT_KEYSRCOVERRIDE))) + { + if ((SurfaceOverlay.DDOverlayFxFlags & DDOVER_KEYDEST) && (SurfaceOverlay.lpDDDestSurfaceX->surfaceDesc2.dwFlags & DDSD_CKDESTOVERLAY)) + { + DDBltFxFlags |= (DDBLT_DDFX | DDBLT_KEYDESTOVERRIDE); + DDBltFx.ddckDestColorkey = SurfaceOverlay.lpDDDestSurfaceX->surfaceDesc2.ddckCKDestOverlay; + } + else if ((SurfaceOverlay.DDOverlayFxFlags & DDOVER_KEYSRC) && (surfaceDesc2.dwFlags & DDSD_CKSRCOVERLAY)) + { + DDBltFxFlags |= (DDBLT_DDFX | DDBLT_KEYSRCOVERRIDE); + DDBltFx.ddckSrcColorkey = surfaceDesc2.ddckCKSrcOverlay; + } + } + + SurfaceOverlay.lpDDDestSurfaceX->Blt(lpNewDestRect, (LPDIRECTDRAWSURFACE7)GetWrapperInterfaceX(0), lpNewSrcRect, DDBltFxFlags, &DDBltFx, 0); + } + } + return DD_OK; +} + +// ****************************** +// External static functions +// ****************************** + void m_IDirectDrawSurfaceX::StartSharedEmulatedMemory() { ShareEmulatedMemory = true; @@ -8048,7 +8010,7 @@ void m_IDirectDrawSurfaceX::DeleteEmulatedMemory(EMUSURFACE **ppEmuSurface) LOG_LIMIT(100, __FUNCTION__ << " Deleting emulated surface (" << *ppEmuSurface << ")"); - SetCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; // Release device context memory if ((*ppEmuSurface)->DC) @@ -8076,8 +8038,6 @@ void m_IDirectDrawSurfaceX::DeleteEmulatedMemory(EMUSURFACE **ppEmuSurface) } delete (*ppEmuSurface); *ppEmuSurface = nullptr; - - ReleaseCriticalSection(); } void m_IDirectDrawSurfaceX::CleanupSharedEmulatedMemory() @@ -8085,16 +8045,24 @@ void m_IDirectDrawSurfaceX::CleanupSharedEmulatedMemory() // Disable shared memory ShareEmulatedMemory = false; - SetCriticalSection(); - LOG_LIMIT(100, __FUNCTION__ << " Deleting " << memorySurfaces.size() << " emulated surface" << ((memorySurfaces.size() != 1) ? "s" : "") << "!"); + ScopedDDCriticalSection ThreadLockDD; + // Clean up unused emulated surfaces for (EMUSURFACE* pEmuSurface: memorySurfaces) { DeleteEmulatedMemory(&pEmuSurface); } memorySurfaces.clear(); +} + +void m_IDirectDrawSurfaceX::SizeDummySurface(size_t size) +{ + dummySurface.resize(size); +} - ReleaseCriticalSection(); +void m_IDirectDrawSurfaceX::CleanupDummySurface() +{ + dummySurface.clear(); } diff --git a/ddraw/IDirectDrawSurfaceX.h b/ddraw/IDirectDrawSurfaceX.h index e944da56..0a866dd6 100644 --- a/ddraw/IDirectDrawSurfaceX.h +++ b/ddraw/IDirectDrawSurfaceX.h @@ -1,26 +1,5 @@ #pragma once -#include -#include "d3dx9.h" - -// Emulated surface -struct EMUSURFACE -{ - HDC DC = nullptr; - HDC GameDC = nullptr; - bool UsingGameDC = false; - DWORD Size = 0; - D3DFORMAT Format = D3DFMT_UNKNOWN; - void *pBits = nullptr; - DWORD Pitch = 0; - HBITMAP bitmap = nullptr; - BYTE bmiMemory[(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256)] = {}; - PBITMAPINFO bmi = (PBITMAPINFO)bmiMemory; - HGDIOBJ OldDCObject = nullptr; - HGDIOBJ OldGameDCObject = nullptr; - DWORD LastPaletteUSN = 0; -}; - class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObject { private: @@ -32,6 +11,13 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj ULONG RefCount4 = 0; ULONG RefCount7 = 0; + // Store version wrappers + m_IDirectDrawSurface* WrapperInterface = nullptr; + m_IDirectDrawSurface2* WrapperInterface2 = nullptr; + m_IDirectDrawSurface3* WrapperInterface3 = nullptr; + m_IDirectDrawSurface4* WrapperInterface4 = nullptr; + m_IDirectDrawSurface7* WrapperInterface7 = nullptr; + // Remember the last lock info struct LASTLOCK { @@ -165,7 +151,6 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj // Convert to Direct3D9 const DWORD CreatedVersion; CRITICAL_SECTION ddscs = {}; - CRITICAL_SECTION ddlcs = {}; m_IDirectDrawX *ddrawParent = nullptr; // DirectDraw parent device SURFACEOVERLAY SurfaceOverlay; // The overlays for this surface std::vector MipMaps; // MipMaps structure with addresses @@ -188,6 +173,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj bool DCRequiresEmulation = false; bool SurfaceRequiresEmulation = false; bool ComplexRoot = false; + bool ComplexChild = false; bool IsSurfaceLost = false; bool IsInFlip = false; bool PresentOnUnlock = false; @@ -217,52 +203,12 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj // Direct3D9 device address LPDIRECT3DDEVICE9* d3d9Device = nullptr; - // Store ddraw surface version wrappers - m_IDirectDrawSurface *WrapperInterface = nullptr; - m_IDirectDrawSurface2 *WrapperInterface2 = nullptr; - m_IDirectDrawSurface3 *WrapperInterface3 = nullptr; - m_IDirectDrawSurface4 *WrapperInterface4 = nullptr; - m_IDirectDrawSurface7 *WrapperInterface7 = nullptr; - // Store a list of attached surfaces std::unique_ptr BackBufferInterface; std::map AttachedSurfaceMap; DWORD MapKey = 0; - // Wrapper interface functions - inline REFIID GetWrapperType(DWORD DirectXVersion) - { - return (DirectXVersion == 1) ? IID_IDirectDrawSurface : - (DirectXVersion == 2) ? IID_IDirectDrawSurface2 : - (DirectXVersion == 3) ? IID_IDirectDrawSurface3 : - (DirectXVersion == 4) ? IID_IDirectDrawSurface4 : - (DirectXVersion == 7) ? IID_IDirectDrawSurface7 : IID_IUnknown; - } - inline bool CheckWrapperType(REFIID IID) - { - return (IID == IID_IDirectDrawSurface || - IID == IID_IDirectDrawSurface2 || - IID == IID_IDirectDrawSurface3 || - IID == IID_IDirectDrawSurface4 || - IID == IID_IDirectDrawSurface7) ? true : false; - } - inline IDirectDrawSurface *GetProxyInterfaceV1() { return (IDirectDrawSurface *)ProxyInterface; } - inline IDirectDrawSurface2 *GetProxyInterfaceV2() { return (IDirectDrawSurface2 *)ProxyInterface; } - inline IDirectDrawSurface3 *GetProxyInterfaceV3() { return (IDirectDrawSurface3 *)ProxyInterface; } - inline IDirectDrawSurface4 *GetProxyInterfaceV4() { return (IDirectDrawSurface4 *)ProxyInterface; } - inline IDirectDrawSurface7 *GetProxyInterfaceV7() { return ProxyInterface; } - - // Swap surface addresses for Flip - template - inline void SwapAddresses(T *Address1, T *Address2) - { - T tmpAddr = *Address1; - *Address1 = *Address2; - *Address2 = tmpAddr; - } - HRESULT CheckBackBufferForFlip(m_IDirectDrawSurfaceX* lpTargetSurface); - - // Direct3D9 interface functions + // Helper functions LPDIRECT3DSURFACE9 Get3DSurface(); LPDIRECT3DSURFACE9 Get3DMipMapSurface(DWORD MipMapLevel); void Release3DMipMapSurface(LPDIRECT3DSURFACE9 pSurfaceD9, DWORD MipMapLevel); @@ -280,8 +226,19 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj void UpdateSurfaceDesc(); // Direct3D9 interfaces - inline HRESULT LockD3d9Surface(D3DLOCKED_RECT* pLockedRect, RECT* pRect, DWORD Flags, DWORD MipMapLevel); - inline HRESULT UnLockD3d9Surface(DWORD MipMapLevel); + HRESULT LockD3d9Surface(D3DLOCKED_RECT* pLockedRect, RECT* pRect, DWORD Flags, DWORD MipMapLevel); + HRESULT UnLockD3d9Surface(DWORD MipMapLevel); + void SetDirtyFlag(DWORD MipMapLevel); + + // Swap surface addresses for Flip + template + inline void SwapAddresses(T* Address1, T* Address2) + { + T tmpAddr = *Address1; + *Address1 = *Address2; + *Address2 = tmpAddr; + } + HRESULT CheckBackBufferForFlip(m_IDirectDrawSurfaceX* lpTargetSurface); // Locking rect coordinates bool CheckCoordinates(LPRECT lpInRect) @@ -298,21 +255,19 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj void EndWriteSyncSurfaces(LPRECT lpDestRect); // Surface information functions - inline bool IsSurfaceLocked(bool CheckLocking = true) const { return (IsLocked || (CheckLocking && IsLocking)); } - inline bool IsSurfaceBlitting() const { return (IsInBlt || IsInBltBatch); } - inline bool IsSurfaceInDC(bool CheckGettingDC = true) const { return (IsInDC || (CheckGettingDC && IsPreparingDC)); } - inline bool IsSurfaceBusy(bool CheckLocking = true, bool CheckGettingDC = true) const { return (IsSurfaceBlitting() || IsSurfaceLocked(CheckLocking) || IsSurfaceInDC(CheckGettingDC)); } - inline bool IsD9UsingVideoMemory() const { return ((surface.Surface || surface.Texture) ? surface.Pool == D3DPOOL_DEFAULT : false); } - inline bool IsUsingShadowSurface() const { return (surface.UsingShadowSurface && surface.Shadow); } - inline bool IsLockedFromOtherThread() const { return (IsSurfaceBlitting() || IsSurfaceLocked()) && LockedWithID && LockedWithID != GetCurrentThreadId(); } - inline bool IsDummyMipMap(DWORD MipMapLevel) { return (MipMapLevel > MaxMipMapLevel || ((MipMapLevel & ~DXW_IS_MIPMAP_DUMMY) - 1 < MipMaps.size() && MipMaps[(MipMapLevel & ~DXW_IS_MIPMAP_DUMMY) - 1].IsDummy)); } - inline DWORD GetD3d9MipMapLevel(DWORD MipMapLevel) const { return min(MipMapLevel, MaxMipMapLevel); } - inline DWORD GetWidth() const { return surfaceDesc2.dwWidth; } - inline DWORD GetHeight() const { return surfaceDesc2.dwHeight; } - inline DDSCAPS2 GetSurfaceCaps() const { return surfaceDesc2.ddsCaps; } - inline D3DFORMAT GetSurfaceFormat() const { return surface.Format; } - - void SetDirtyFlag(DWORD MipMapLevel); + bool IsSurfaceLocked(bool CheckLocking = true) const { return (IsLocked || (CheckLocking && IsLocking)); } + bool IsSurfaceBlitting() const { return (IsInBlt || IsInBltBatch); } + bool IsSurfaceInDC(bool CheckGettingDC = true) const { return (IsInDC || (CheckGettingDC && IsPreparingDC)); } + bool IsSurfaceBusy(bool CheckLocking = true, bool CheckGettingDC = true) const { return (IsSurfaceBlitting() || IsSurfaceLocked(CheckLocking) || IsSurfaceInDC(CheckGettingDC)); } + bool IsD9UsingVideoMemory() const { return ((surface.Surface || surface.Texture) ? surface.Pool == D3DPOOL_DEFAULT : false); } + bool IsUsingShadowSurface() const { return (surface.UsingShadowSurface && surface.Shadow); } + bool IsLockedFromOtherThread() const { return (IsSurfaceBlitting() || IsSurfaceLocked()) && LockedWithID && LockedWithID != GetCurrentThreadId(); } + bool IsDummyMipMap(DWORD MipMapLevel) { return (MipMapLevel > MaxMipMapLevel || ((MipMapLevel & ~DXW_IS_MIPMAP_DUMMY) - 1 < MipMaps.size() && MipMaps[(MipMapLevel & ~DXW_IS_MIPMAP_DUMMY) - 1].IsDummy)); } + DWORD GetD3d9MipMapLevel(DWORD MipMapLevel) const { return min(MipMapLevel, MaxMipMapLevel); } + DWORD GetWidth() const { return surfaceDesc2.dwWidth; } + DWORD GetHeight() const { return surfaceDesc2.dwHeight; } + DDSCAPS2 GetSurfaceCaps() const { return surfaceDesc2.ddsCaps; } + D3DFORMAT GetSurfaceFormat() const { return surface.Format; } // Attached surfaces void InitSurfaceDesc(DWORD DirectXVersion); @@ -334,6 +289,29 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj HRESULT CopyEmulatedSurfaceFromGDI(LPRECT lpDestRect); HRESULT CopyEmulatedSurfaceToGDI(LPRECT lpDestRect); + // Wrapper interface functions + inline REFIID GetWrapperType(DWORD DirectXVersion) + { + return (DirectXVersion == 1) ? IID_IDirectDrawSurface : + (DirectXVersion == 2) ? IID_IDirectDrawSurface2 : + (DirectXVersion == 3) ? IID_IDirectDrawSurface3 : + (DirectXVersion == 4) ? IID_IDirectDrawSurface4 : + (DirectXVersion == 7) ? IID_IDirectDrawSurface7 : IID_IUnknown; + } + inline bool CheckWrapperType(REFIID IID) + { + return (IID == IID_IDirectDrawSurface || + IID == IID_IDirectDrawSurface2 || + IID == IID_IDirectDrawSurface3 || + IID == IID_IDirectDrawSurface4 || + IID == IID_IDirectDrawSurface7) ? true : false; + } + inline IDirectDrawSurface *GetProxyInterfaceV1() { return (IDirectDrawSurface *)ProxyInterface; } + inline IDirectDrawSurface2 *GetProxyInterfaceV2() { return (IDirectDrawSurface2 *)ProxyInterface; } + inline IDirectDrawSurface3 *GetProxyInterfaceV3() { return (IDirectDrawSurface3 *)ProxyInterface; } + inline IDirectDrawSurface4 *GetProxyInterfaceV4() { return (IDirectDrawSurface4 *)ProxyInterface; } + inline IDirectDrawSurface7 *GetProxyInterfaceV7() { return ProxyInterface; } + // Interface initialization functions void InitInterface(DWORD DirectXVersion); void ReleaseDirectDrawResources(); @@ -342,7 +320,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj public: m_IDirectDrawSurfaceX(IDirectDrawSurface7 *pOriginal, DWORD DirectXVersion) : ProxyInterface(pOriginal), CreatedVersion(DirectXVersion) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -456,10 +434,6 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj void *GetWrapperInterfaceX(DWORD DirectXVersion); ULONG AddRef(DWORD DirectXVersion); ULONG Release(DWORD DirectXVersion); - void SetSurfaceCriticalSection() { EnterCriticalSection(&ddscs); } - void ReleaseSurfaceCriticalSection() { LeaveCriticalSection(&ddscs); } - void SetLockCriticalSection() { EnterCriticalSection(&ddlcs); } - void ReleaseLockCriticalSection() { LeaveCriticalSection(&ddlcs); } // Fix byte alignment issue void LockEmuLock(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSurfaceDesc); @@ -481,32 +455,32 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj void ResetSurfaceDisplay(); // Surface information functions - inline bool IsPrimarySurface() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) != 0; } - inline bool IsBackBuffer() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) != 0; } - inline bool IsPrimaryOrBackBuffer() const { return (IsPrimarySurface() || IsBackBuffer()); } - inline bool IsRenderTarget() const { return surface.CanBeRenderTarget; } - inline bool IsFlipSurface() const { return ((surfaceDesc2.ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER)); } - inline bool IsSurface3D() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) != 0; } - inline bool IsSurfaceTexture() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE) != 0; } - inline bool IsColorKeyTexture() const { return (IsSurfaceTexture() && (surfaceDesc2.dwFlags & DDSD_CKSRCBLT)); } - inline bool IsPalette() const { return (surface.Format == D3DFMT_P8); } - inline bool IsDepthStencil() const { return (surfaceDesc2.ddpfPixelFormat.dwFlags & (DDPF_ZBUFFER | DDPF_STENCILBUFFER)) != 0; } - inline bool IsSurfaceManaged() const { return (surfaceDesc2.ddsCaps.dwCaps2 & (DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_D3DTEXTUREMANAGE)) != 0; } - inline bool CanSurfaceBeDeleted() const { return (ComplexRoot || (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX) == 0); } - inline bool CanSurfaceUseEmulation() const + bool IsPrimarySurface() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) != 0; } + bool IsBackBuffer() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) != 0; } + bool IsPrimaryOrBackBuffer() const { return (IsPrimarySurface() || IsBackBuffer()); } + bool IsRenderTarget() const { return surface.CanBeRenderTarget; } + bool IsFlipSurface() const { return ((surfaceDesc2.ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER)); } + bool IsSurface3D() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) != 0; } + bool IsSurfaceTexture() const { return (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE) != 0; } + bool IsColorKeyTexture() const { return (IsSurfaceTexture() && (surfaceDesc2.dwFlags & DDSD_CKSRCBLT)); } + bool IsPalette() const { return (surface.Format == D3DFMT_P8); } + bool IsDepthStencil() const { return (surfaceDesc2.ddpfPixelFormat.dwFlags & (DDPF_ZBUFFER | DDPF_STENCILBUFFER)) != 0; } + bool IsSurfaceManaged() const { return (surfaceDesc2.ddsCaps.dwCaps2 & (DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_D3DTEXTUREMANAGE)) != 0; } + bool CanSurfaceBeDeleted() const { return !ComplexChild; } + bool CanSurfaceUseEmulation() const { return ((IsPixelFormatRGB(surfaceDesc2.ddpfPixelFormat) || IsPixelFormatPalette(surfaceDesc2.ddpfPixelFormat)) && (!IsSurface3D() || !Using3D) && !surface.UsingSurfaceMemory); } - inline bool IsUsingEmulation() const { return (surface.emu && surface.emu->DC && surface.emu->GameDC && surface.emu->pBits); } - inline bool IsEmulationDCReady() const { return (IsUsingEmulation() && !surface.emu->UsingGameDC); } - inline bool IsSurfaceDirty() const { return surface.IsDirtyFlag; } - inline bool IsMipMapAutogen() const { return surface.Texture && (surface.Usage & D3DUSAGE_AUTOGENMIPMAP); } - inline bool IsMipMapGenerated() const { return IsMipMapReadyToUse || IsMipMapAutogen(); } - inline void FixTextureFlags(LPDDSURFACEDESC2 lpDDSurfaceDesc2); + bool IsUsingEmulation() const { return (surface.emu && surface.emu->DC && surface.emu->GameDC && surface.emu->pBits); } + bool IsEmulationDCReady() const { return (IsUsingEmulation() && !surface.emu->UsingGameDC); } + bool IsSurfaceDirty() const { return surface.IsDirtyFlag; } + bool IsMipMapAutogen() const { return surface.Texture && (surface.Usage & D3DUSAGE_AUTOGENMIPMAP); } + bool IsMipMapGenerated() const { return IsMipMapReadyToUse || IsMipMapAutogen(); } + void FixTextureFlags(LPDDSURFACEDESC2 lpDDSurfaceDesc2); void PrepareRenderTarget(); void ClearDirtyFlags(); bool GetColorKeyForShader(float(&lowColorKey)[4], float(&highColorKey)[4]); bool GetColorKeyForPrimaryShader(float(&lowColorKey)[4], float(&highColorKey)[4]); bool GetWasBitAlignLocked() const { return WasBitAlignLocked; } - inline bool GetSurfaceSetSize(DWORD& Width, DWORD& Height) const + bool GetSurfaceSetSize(DWORD& Width, DWORD& Height) const { if ((surfaceDesc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT)) == (DDSD_WIDTH | DDSD_HEIGHT) && (ResetDisplayFlags & (DDSD_WIDTH | DDSD_HEIGHT)) == 0 && @@ -519,22 +493,25 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj return false; } m_IDirectDrawSurfaceX* GetAttachedDepthStencil(); - LPDIRECT3DSURFACE9 GetD3d9Surface(); + LPDIRECT3DSURFACE9 GetD3d9Surface(bool ShouldCheckInterface = true); LPDIRECT3DTEXTURE9 GetD3d9DrawTexture(); LPDIRECT3DTEXTURE9 GetD3d9Texture(); HRESULT GenerateMipMapLevels(); - inline DWORD GetD3d9Width() const { return surface.Width; } - inline DWORD GetD3d9Height() const { return surface.Height; } - inline D3DFORMAT GetD3d9Format() const { return surface.Format; } - inline LPDIRECT3DTEXTURE9 GetD3d9PaletteTexture() const { return primary.PaletteTexture; } - inline m_IDirect3DTextureX* GetAttachedTexture() { return attached3DTexture; } + DWORD GetD3d9Width() const { return surface.Width; } + DWORD GetD3d9Height() const { return surface.Height; } + D3DFORMAT GetD3d9Format() const { return surface.Format; } + LPDIRECT3DTEXTURE9 GetD3d9PaletteTexture() const { return primary.PaletteTexture; } + m_IDirect3DTextureX* GetAttachedTexture() { return attached3DTexture; } void ClearUsing3DFlag(); HRESULT GetPresentWindowRect(LPRECT pRect, RECT& DestRect); + // For texture loading + HRESULT Load(LPDIRECTDRAWSURFACE7 lpDestTex, LPPOINT lpDestPoint, LPDIRECTDRAWSURFACE7 lpSrcTex, LPRECT lprcSrcRect, DWORD dwFlags); + // For Present checking - inline bool ShouldReadFromGDI() const { return (Config.DdrawReadFromGDI && IsPrimarySurface() && IsUsingEmulation() && !Using3D); } - inline bool ShouldWriteToGDI() const { return (Config.DdrawWriteToGDI && IsPrimarySurface() && IsUsingEmulation() && !Using3D); } - inline bool ShouldPresentToWindow(bool IsPresenting) const + bool ShouldReadFromGDI() const { return (Config.DdrawReadFromGDI && IsPrimarySurface() && IsUsingEmulation() && !Using3D); } + bool ShouldWriteToGDI() const { return (Config.DdrawWriteToGDI && IsPrimarySurface() && IsUsingEmulation() && !Using3D); } + bool ShouldPresentToWindow(bool IsPresenting) const { return (surface.IsUsingWindowedMode && (IsPresenting ? (IsPrimarySurface() && !IsRenderTarget()) : IsPrimaryOrBackBuffer()) && !Config.DdrawWriteToGDI); } @@ -549,12 +526,14 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj void RemoveClipper(m_IDirectDrawClipper* ClipperToRemove); // For palettes - inline m_IDirectDrawPalette *GetAttachedPalette() { return attachedPalette; } + m_IDirectDrawPalette *GetAttachedPalette() { return attachedPalette; } void RemovePalette(m_IDirectDrawPalette* PaletteToRemove); void UpdatePaletteData(); - // For emulated surfaces + // External static functions static void StartSharedEmulatedMemory(); static void DeleteEmulatedMemory(EMUSURFACE **ppEmuSurface); static void CleanupSharedEmulatedMemory(); + static void SizeDummySurface(size_t size); + static void CleanupDummySurface(); }; diff --git a/ddraw/IDirectDrawTypes.cpp b/ddraw/IDirectDrawTypes.cpp index 7c3c1b39..046c5486 100644 --- a/ddraw/IDirectDrawTypes.cpp +++ b/ddraw/IDirectDrawTypes.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -17,6 +17,15 @@ #include "ddraw.h" #include "Utils\Utils.h" +float ScaleDDWidthRatio = 1.0f; +float ScaleDDHeightRatio = 1.0f; +DWORD ScaleDDLastWidth = 0; +DWORD ScaleDDLastHeight = 0; +DWORD ScaleDDCurrentWidth = 0; +DWORD ScaleDDCurrentHeight = 0; +DWORD ScaleDDPadX = 0; +DWORD ScaleDDPadY = 0; + // For storing resolution list std::vector> CashedDisplayResolutions; @@ -40,6 +49,64 @@ bool IsDisplayResolution(DWORD Width, DWORD Height) return false; } +// Simple copy with ColorKey and Mirroring +template void SimpleColorKeyCopy(BYTE ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight); +template void SimpleColorKeyCopy(WORD ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight); +template void SimpleColorKeyCopy(TRIBYTE ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight); +template void SimpleColorKeyCopy(DWORD ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight); +template +void SimpleColorKeyCopy(T ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight) +{ + T* SrcBufferLoop = reinterpret_cast(SrcBuffer); + T* DestBufferLoop = reinterpret_cast(DestBuffer); + + for (LONG y = 0; y < DestRectHeight; y++) + { + for (LONG x = 0; x < DestRectWidth; x++) + { + T PixelColor = SrcBufferLoop[IsMirrorLeftRight ? DestRectWidth - x - 1 : x]; + if (!IsColorKey || PixelColor != ColorKey) + { + DestBufferLoop[x] = PixelColor; + } + } + SrcBufferLoop = reinterpret_cast((BYTE*)SrcBufferLoop + SrcPitch); + DestBufferLoop = reinterpret_cast((BYTE*)DestBufferLoop + DestPitch); + } +} + +// Copy memory (complex) +template void ComplexCopy(BYTE ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight); +template void ComplexCopy(WORD ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight); +template void ComplexCopy(TRIBYTE ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight); +template void ComplexCopy(DWORD ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight); +template +void ComplexCopy(T ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight) +{ + float WidthRatio = ((float)SrcRectWidth / (float)DestRectWidth); + float HeightRatio = ((float)SrcRectHeight / (float)DestRectHeight); + + T* SrcBufferLoop = reinterpret_cast(SrcLockRect.pBits); + T* DestBufferLoop = reinterpret_cast(DestLockRect.pBits); + + for (LONG y = 0; y < DestRectHeight; y++) + { + for (LONG x = 0; x < DestRectWidth; x++) + { + DWORD sx = (DWORD)((float)x * WidthRatio); + T PixelColor = SrcBufferLoop[IsMirrorLeftRight ? SrcRectWidth - sx - 1 : sx]; + + if (!IsColorKey || PixelColor != ColorKey) + { + DestBufferLoop[x] = PixelColor; + } + } + DWORD sx = (DWORD)((float)(y + 1) * HeightRatio); + SrcBufferLoop = reinterpret_cast((BYTE*)SrcLockRect.pBits + SrcLockRect.Pitch * (IsMirrorUpDown ? SrcRectHeight - sx - 1 : sx)); + DestBufferLoop = reinterpret_cast((BYTE*)DestBufferLoop + DestLockRect.Pitch); + } +} + DWORD ComputeRND(DWORD Seed, DWORD Num) { LARGE_INTEGER PerformanceCount = {}; @@ -783,7 +850,7 @@ DWORD GetSurfaceSize(D3DFORMAT Format, DWORD Width, DWORD Height, INT Pitch) } // Count leading zeros and total number of bits -inline static void CountBits(DWORD value, DWORD& LeadingZeros, DWORD& TotalBits) +static void CountBits(DWORD value, DWORD& LeadingZeros, DWORD& TotalBits) { LeadingZeros = 0; while (value && !(value & 1)) diff --git a/ddraw/IDirectDrawTypes.h b/ddraw/IDirectDrawTypes.h index 49cfdf61..8bd5ce86 100644 --- a/ddraw/IDirectDrawTypes.h +++ b/ddraw/IDirectDrawTypes.h @@ -4,8 +4,12 @@ class m_IDirectDrawX; -constexpr DWORD MaxVidMemory = 512 * 1024 * 1024; // 512 MBs -constexpr DWORD MinUsedVidMemory = 8 * 1024; // 8 KBs +static constexpr DWORD MaxVidMemory = 512 * 1024 * 1024; // 512 MBs +static constexpr DWORD MinUsedVidMemory = 8 * 1024; // 8 KBs + +static constexpr D3DFORMAT D9DisplayFormat = D3DFMT_X8R8G8B8; + +static constexpr DWORD MaxPaletteSize = 256; #define BLT_MIRRORLEFTRIGHT 0x00000002l #define BLT_MIRRORUPDOWN 0x00000004l @@ -62,7 +66,10 @@ static constexpr D3DFORMAT FourCCTypes[] = (D3DFORMAT)MAKEFOURCC('A', 'T', 'I', '1'), (D3DFORMAT)MAKEFOURCC('A', 'T', 'I', '2'), (D3DFORMAT)MAKEFOURCC('3', 'x', '1', '1'), - (D3DFORMAT)MAKEFOURCC('3', 'x', '1', '6') + (D3DFORMAT)MAKEFOURCC('3', 'x', '1', '6'), + D3DFMT_YUY2, + D3DFMT_UYVY, + D3DFMT_AYUV, }; typedef struct { @@ -170,12 +177,29 @@ struct HIGHRESCOUNTER struct PRESENTTHREAD { + const bool& ExitFlag = Config.Exiting; bool IsInitialized = false; - CRITICAL_SECTION ddpt = {}; - HANDLE workerEvent = {}; HANDLE workerThread = {}; + HANDLE exitEvent = {}; LARGE_INTEGER LastPresentTime = {}; - bool EnableThreadFlag = false; +}; + +// Emulated surface +struct EMUSURFACE +{ + HDC DC = nullptr; + HDC GameDC = nullptr; + bool UsingGameDC = false; + DWORD Size = 0; + D3DFORMAT Format = D3DFMT_UNKNOWN; + void* pBits = nullptr; + DWORD Pitch = 0; + HBITMAP bitmap = nullptr; + BYTE bmiMemory[(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256)] = {}; + PBITMAPINFO bmi = (PBITMAPINFO)bmiMemory; + HGDIOBJ OldDCObject = nullptr; + HGDIOBJ OldGameDCObject = nullptr; + DWORD LastPaletteUSN = 0; }; // Used for 24-bit surfaces @@ -206,10 +230,21 @@ static constexpr DWORD DDS_HEADER_SIZE = sizeof(DWORD) + sizeof(DDS_HEADER); static constexpr DWORD DDS_HEADER_FLAGS_TEXTURE = 0x00001007; // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT static constexpr DWORD DDS_HEADER_FLAGS_PITCH = 0x00000008; -static constexpr DWORD MaxPaletteSize = 256; +extern float ScaleDDWidthRatio; +extern float ScaleDDHeightRatio; +extern DWORD ScaleDDLastWidth; +extern DWORD ScaleDDLastHeight; +extern DWORD ScaleDDCurrentWidth; +extern DWORD ScaleDDCurrentHeight; +extern DWORD ScaleDDPadX; +extern DWORD ScaleDDPadY; void AddDisplayResolution(DWORD Width, DWORD Height); bool IsDisplayResolution(DWORD Width, DWORD Height); +template +void SimpleColorKeyCopy(T ColorKey, BYTE* SrcBuffer, BYTE* DestBuffer, INT SrcPitch, INT DestPitch, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorLeftRight); +template +void ComplexCopy(T ColorKey, D3DLOCKED_RECT SrcLockRect, D3DLOCKED_RECT DestLockRect, LONG SrcRectWidth, LONG SrcRectHeight, LONG DestRectWidth, LONG DestRectHeight, bool IsColorKey, bool IsMirrorUpDown, bool IsMirrorLeftRight); DWORD ComputeRND(DWORD Seed, DWORD Num); bool DoRectsMatch(const RECT& lhs, const RECT& rhs); bool GetOverlappingRect(const RECT& rect1, const RECT& rect2, RECT& outOverlapRect); diff --git a/ddraw/IDirectDrawX.cpp b/ddraw/IDirectDrawX.cpp index dc3d6f91..2ed1e759 100644 --- a/ddraw/IDirectDrawX.cpp +++ b/ddraw/IDirectDrawX.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -17,7 +17,6 @@ */ #include "ddraw.h" -#include "ddrawExternal.h" #include "Utils\Utils.h" #include "GDI\GDI.h" #include "GDI\WndProc.h" @@ -28,132 +27,96 @@ #include "Shaders\ColorKeyShader.h" #include "Shaders\GammaPixelShader.h" -const D3DFORMAT D9DisplayFormat = D3DFMT_X8R8G8B8; - -DWORD WINAPI PresentThreadFunction(LPVOID); - -float ScaleDDWidthRatio = 1.0f; -float ScaleDDHeightRatio = 1.0f; -DWORD ScaleDDLastWidth = 0; -DWORD ScaleDDLastHeight = 0; -DWORD ScaleDDCurrentWidth = 0; -DWORD ScaleDDCurrentHeight = 0; -DWORD ScaleDDPadX = 0; -DWORD ScaleDDPadY = 0; - -// Store a list of ddraw devices -std::vector DDrawVector; - -// Cached wrapper interface namespace { - m_IDirectDraw* WrapperInterfaceBackup = nullptr; - m_IDirectDraw2* WrapperInterfaceBackup2 = nullptr; - m_IDirectDraw3* WrapperInterfaceBackup3 = nullptr; - m_IDirectDraw4* WrapperInterfaceBackup4 = nullptr; - m_IDirectDraw7* WrapperInterfaceBackup7 = nullptr; -} - -// Default resolution -DWORD DefaultWidth = 0; -DWORD DefaultHeight = 0; -RECT LastWindowRect = {}; + // Store a list of ddraw devices + std::vector DDrawVector; -// Exclusive mode settings -bool ExclusiveMode = false; -bool FullScreenWindowed = false; -DISPLAYSETTINGS Exclusive = {}; -HWND LastUsedHWnd = nullptr; // Only initialize this here + // Store a list of base clipper interfaces + std::vector BaseClipperVector; -// Clipper -HWND ClipperHWnd = nullptr; + // Default resolution + RECT LastWindowRect = {}; -// Display mode settings -DISPLAYSETTINGS DisplayMode = {}; + // Exclusive mode settings + bool ExclusiveMode = false; + bool FullScreenWindowed = false; + DISPLAYSETTINGS Exclusive = {}; + HWND LastUsedHWnd = nullptr; // Only initialize this here -// Device settings -DEVICESETTINGS Device = {}; + // Clipper + HWND ClipperHWnd = nullptr; -// Display pixel format -DDPIXELFORMAT DisplayPixelFormat = {}; + // Display mode settings + DISPLAYSETTINGS DisplayMode = {}; -// Gamma data -bool IsGammaSet = false; -D3DGAMMARAMP RampData; -D3DGAMMARAMP DefaultRampData; + // Device settings + DEVICESETTINGS Device = {}; -// Last used surface resolution -DWORD LastSetWidth = 0; -DWORD LastSetHeight = 0; -DWORD LastSetBPP = 0; + // Display pixel format + DDPIXELFORMAT DisplayPixelFormat = {}; -// Initial screen resolution -DWORD InitWidth = 0; -DWORD InitHeight = 0; + // Gamma data + bool IsGammaSet = false; + D3DGAMMARAMP RampData; + D3DGAMMARAMP DefaultRampData; -// Cached FourCC list -std::vector FourCCsList; + // Last used surface resolution + DWORD LastSetWidth = 0; + DWORD LastSetHeight = 0; + DWORD LastSetBPP = 0; -// Used for dummy mipmaps -extern std::vector dummySurface; + // Cached FourCC list + std::vector FourCCsList; -// Mouse hook -MOUSEHOOK MouseHook = {}; + // Mouse hook + MOUSEHOOK MouseHook = {}; -// High resolution counter used for auto frame skipping -HIGHRESCOUNTER Counter = {}; + // High resolution counter used for auto frame skipping + HIGHRESCOUNTER Counter = {}; #ifdef ENABLE_PROFILING -std::chrono::steady_clock::time_point presentTime; + std::chrono::steady_clock::time_point presentTime; #endif -// Preset from another thread -PRESENTTHREAD PresentThread = {}; - -inline static void SetPTCriticalSection() -{ - if (PresentThread.IsInitialized) - { - EnterCriticalSection(&PresentThread.ddpt); - } -} + // Preset from another thread + PRESENTTHREAD PresentThread; + + // Direct3D9 flags + bool EnableWaitVsync = false; + + // Direct3D9 Objects + LPDIRECT3D9 d3d9Object = nullptr; + LPDIRECT3DDEVICE9 d3d9Device = nullptr; + D3DPRESENT_PARAMETERS presParams = {}; + LPDIRECT3DTEXTURE9 GammaLUTTexture = nullptr; + LPDIRECT3DTEXTURE9 ScreenCopyTexture = nullptr; + LPDIRECT3DPIXELSHADER9 palettePixelShader = nullptr; + LPDIRECT3DPIXELSHADER9 colorkeyPixelShader = nullptr; + LPDIRECT3DPIXELSHADER9 gammaPixelShader = nullptr; + LPDIRECT3DVERTEXBUFFER9 validateDeviceVertexBuffer = nullptr; + LPDIRECT3DINDEXBUFFER9 d3d9IndexBuffer = nullptr; + + bool UsingCustomRenderTarget = false; + TLVERTEX DeviceVertices[4]; + bool IsDeviceVerticesSet = false; + bool UsingShader32f = false; + DWORD IndexBufferSize = 0; + DWORD BehaviorFlags = 0; + HWND hFocusWindow = nullptr; + DWORD FocusWindowThreadID = 0; + + std::unordered_map g_hookmap; -inline static void ReleasePTCriticalSection() -{ - if (PresentThread.IsInitialized) - { - LeaveCriticalSection(&PresentThread.ddpt); - } + m_IDirectDraw* WrapperInterfaceBackup = nullptr; + m_IDirectDraw2* WrapperInterfaceBackup2 = nullptr; + m_IDirectDraw3* WrapperInterfaceBackup3 = nullptr; + m_IDirectDraw4* WrapperInterfaceBackup4 = nullptr; + m_IDirectDraw7* WrapperInterfaceBackup7 = nullptr; } -// Direct3D9 flags -bool EnableWaitVsync = false; - -// Direct3D9 Objects -LPDIRECT3D9 d3d9Object = nullptr; -LPDIRECT3DDEVICE9 d3d9Device = nullptr; -D3DPRESENT_PARAMETERS presParams = {}; -LPDIRECT3DTEXTURE9 GammaLUTTexture = nullptr; -LPDIRECT3DTEXTURE9 ScreenCopyTexture = nullptr; -LPDIRECT3DPIXELSHADER9 palettePixelShader = nullptr; -LPDIRECT3DPIXELSHADER9 colorkeyPixelShader = nullptr; -LPDIRECT3DPIXELSHADER9 gammaPixelShader = nullptr; -LPDIRECT3DVERTEXBUFFER9 validateDeviceVertexBuffer = nullptr; -LPDIRECT3DINDEXBUFFER9 d3d9IndexBuffer = nullptr; - -bool UsingCustomRenderTarget = false; -TLVERTEX DeviceVertices[4]; -bool IsDeviceVerticesSet = false; -bool UsingShader32f = false; -DWORD IndexBufferSize = 0; -DWORD BehaviorFlags = 0; -HWND hFocusWindow = nullptr; -DWORD FocusWindowThreadID = 0; - -std::unordered_map g_hookmap; - -/************************/ -/*** IUnknown methods ***/ -/************************/ +// ****************************** +// IUnknown functions +// ****************************** HRESULT m_IDirectDrawX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD DirectXVersion) { @@ -176,13 +139,7 @@ HRESULT m_IDirectDrawX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD D return DD_OK; } - if (DirectXVersion != 1 && DirectXVersion != 2 && DirectXVersion != 3 && DirectXVersion != 4 && DirectXVersion != 7) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return E_NOINTERFACE; - } - - DWORD DxVersion = (CheckWrapperType(riid) && (Config.Dd7to9 || Config.ConvertToDirectDraw7)) ? GetGUIDVersion(riid) : DirectXVersion; + DWORD DxVersion = (CheckWrapperType(riid) && Config.Dd7to9) ? GetGUIDVersion(riid) : DirectXVersion; if ((riid == GetWrapperType(DxVersion) && riid != IID_IDirectDraw3) || riid == IID_IUnknown) { @@ -195,9 +152,9 @@ HRESULT m_IDirectDrawX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD D if (Config.Dd7to9) { - if (((riid == IID_IDirect3D || riid == IID_IDirect3D2 || riid == IID_IDirect3D3) && !IsCreatedEx()) || (riid == IID_IDirect3D7 && IsCreatedEx())) + if (riid == IID_IDirect3D || riid == IID_IDirect3D2 || riid == IID_IDirect3D3 || (riid == IID_IDirect3D7 && DirectXVersion == 7)) { - if (Config.DdrawDisableDirect3DCaps) + if (Config.DdrawDisableDirect3DCaps || (IsCreatedEx() && riid != IID_IDirect3D7) || (!IsCreatedEx() && riid == IID_IDirect3D7)) { return E_NOINTERFACE; } @@ -208,8 +165,10 @@ HRESULT m_IDirectDrawX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD D { D3DInterface = new m_IDirect3DX(this, DxVersion, DirectXVersion); } - - AddRef(DirectXVersion); + else + { + D3DInterface->AddRef(DxVersion); // No need to add a ref when creating a device because it is already added when creating the device + } *ppvObj = D3DInterface->GetWrapperInterfaceX(DxVersion); @@ -217,52 +176,7 @@ HRESULT m_IDirectDrawX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj, DWORD D } } - HRESULT hr = ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); - - if (SUCCEEDED(hr) && Config.ConvertToDirect3D7) - { - if (riid == IID_IDirect3D || riid == IID_IDirect3D2 || riid == IID_IDirect3D3 || riid == IID_IDirect3D7) - { - m_IDirect3DX *lpD3DirectX = nullptr; - - ((IDirect3D7*)*ppvObj)->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpD3DirectX); - - if (lpD3DirectX) - { - lpD3DirectX->SetDdrawParent(this); - - D3DInterface = lpD3DirectX; - } - } - } - - return hr; -} - -void *m_IDirectDrawX::GetWrapperInterfaceX(DWORD DirectXVersion) -{ - switch (DirectXVersion) - { - case 0: - if (WrapperInterface7) return WrapperInterface7; - if (WrapperInterface4) return WrapperInterface4; - if (WrapperInterface3) return WrapperInterface3; - if (WrapperInterface2) return WrapperInterface2; - if (WrapperInterface) return WrapperInterface; - break; - case 1: - return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECTDRAW)ProxyInterface, this); - case 2: - return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECTDRAW2)ProxyInterface, this); - case 3: - return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECTDRAW3)ProxyInterface, this); - case 4: - return GetInterfaceAddress(WrapperInterface4, WrapperInterfaceBackup4, (LPDIRECTDRAW4)ProxyInterface, this); - case 7: - return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECTDRAW7)ProxyInterface, this); - } - LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); - return nullptr; + return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion)); } ULONG m_IDirectDrawX::AddRef(DWORD DirectXVersion) @@ -296,10 +210,10 @@ ULONG m_IDirectDrawX::Release(DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ") v" << DirectXVersion; - ULONG ref; - if (Config.Dd7to9) { + ULONG ref; + switch (DirectXVersion) { case 1: @@ -328,23 +242,23 @@ ULONG m_IDirectDrawX::Release(DWORD DirectXVersion) { delete this; } + + return ref; } - else - { - ref = ProxyInterface->Release(); - if (ref == 0) - { - delete this; - } + ULONG ref = ProxyInterface->Release(); + + if (ref == 0) + { + delete this; } return ref; } -/***************************/ -/*** IDirectDraw methods ***/ -/***************************/ +// ****************************** +// IDirectDraw v1 functions +// ****************************** HRESULT m_IDirectDrawX::Compact() { @@ -370,7 +284,7 @@ HRESULT m_IDirectDrawX::CreateClipper(DWORD dwFlags, LPDIRECTDRAWCLIPPER FAR * l return DDERR_INVALIDPARAMS; } - m_IDirectDrawClipper* Interface = CreateDirectDrawClipper(nullptr, this, dwFlags); + m_IDirectDrawClipper* Interface = m_IDirectDrawClipper::CreateDirectDrawClipper(nullptr, this, dwFlags); if (DirectXVersion > 3) { @@ -397,39 +311,12 @@ HRESULT m_IDirectDrawX::CreateClipper(DWORD dwFlags, LPDIRECTDRAWCLIPPER FAR * l if (SUCCEEDED(hr) && lplpDDClipper) { - *lplpDDClipper = CreateDirectDrawClipper(*lplpDDClipper, nullptr, dwFlags); + *lplpDDClipper = m_IDirectDrawClipper::CreateDirectDrawClipper(*lplpDDClipper, nullptr, dwFlags); } return hr; } -void m_IDirectDrawX::AddClipper(m_IDirectDrawClipper* lpClipper) -{ - if (!lpClipper) - { - return; - } - - ClipperList.push_back({ lpClipper, 0, 0 }); -} - -void m_IDirectDrawX::ClearClipper(m_IDirectDrawClipper* lpClipper) -{ - // Find and remove the clipper from the list - auto it = std::find_if(ClipperList.begin(), ClipperList.end(), - [lpClipper](auto entry) { - return entry.Interface == lpClipper; - }); - if (it != ClipperList.end()) - { - if (it->RefCount == 1) - { - Release(it->DxVersion); - } - ClipperList.erase(it); - } -} - HRESULT m_IDirectDrawX::CreatePalette(DWORD dwFlags, LPPALETTEENTRY lpDDColorArray, LPDIRECTDRAWPALETTE FAR * lplpDDPalette, IUnknown FAR * pUnkOuter, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -441,7 +328,7 @@ HRESULT m_IDirectDrawX::CreatePalette(DWORD dwFlags, LPPALETTEENTRY lpDDColorArr return DDERR_INVALIDPARAMS; } - m_IDirectDrawPalette* Interface = CreateDirectDrawPalette(nullptr, this, dwFlags, lpDDColorArray); + m_IDirectDrawPalette* Interface = m_IDirectDrawPalette::CreateDirectDrawPalette(nullptr, this, dwFlags, lpDDColorArray); if (DirectXVersion > 3) { @@ -468,51 +355,23 @@ HRESULT m_IDirectDrawX::CreatePalette(DWORD dwFlags, LPPALETTEENTRY lpDDColorArr if (SUCCEEDED(hr) && lplpDDPalette) { - *lplpDDPalette = CreateDirectDrawPalette(*lplpDDPalette, nullptr, 0, nullptr); + *lplpDDPalette = m_IDirectDrawPalette::CreateDirectDrawPalette(*lplpDDPalette, nullptr, 0, nullptr); } return hr; } -void m_IDirectDrawX::AddPalette(m_IDirectDrawPalette* lpPalette) -{ - if (!lpPalette) - { - return; - } - - PaletteList.push_back({ lpPalette, 0, 0 }); -} - -void m_IDirectDrawX::ClearPalette(m_IDirectDrawPalette* lpPalette) -{ - // Find and remove the palette from the list - auto it = std::find_if(PaletteList.begin(), PaletteList.end(), - [lpPalette](auto entry) { - return entry.Interface == lpPalette; - }); - if (it != PaletteList.end()) - { - if (it->RefCount == 1) - { - Release(it->DxVersion); - } - PaletteList.erase(it); - } -} - HRESULT m_IDirectDrawX::CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE7 FAR * lplpDDSurface, IUnknown FAR * pUnkOuter, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!lplpDDSurface || !lpDDSurfaceDesc || pUnkOuter) + if (Config.Dd7to9) { - return DDERR_INVALIDPARAMS; - } + if (!lplpDDSurface || !lpDDSurfaceDesc || pUnkOuter) + { + return DDERR_INVALIDPARAMS; + } - // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) - { if (lpDDSurfaceDesc->dwSize != sizeof(DDSURFACEDESC)) { LOG_LIMIT(100, __FUNCTION__ << " Error: Invalid parameters. dwSize: " << lpDDSurfaceDesc->dwSize); @@ -548,14 +407,14 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!lplpDDSurface || !lpDDSurfaceDesc2 || pUnkOuter) - { - return DDERR_INVALIDPARAMS; - } - *lplpDDSurface = nullptr; - if (Config.Dd7to9) { + if (!lplpDDSurface || !lpDDSurfaceDesc2 || pUnkOuter) + { + return DDERR_INVALIDPARAMS; + } + *lplpDDSurface = nullptr; + if (lpDDSurfaceDesc2->dwSize != sizeof(DDSURFACEDESC2)) { LOG_LIMIT(100, __FUNCTION__ << " Error: Invalid parameters. dwSize: " << lpDDSurfaceDesc2->dwSize); @@ -569,6 +428,15 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE return DDERR_PRIMARYSURFACEALREADYEXISTS; } + // Validate backbuffer + if (((lpDDSurfaceDesc2->dwFlags & DDSD_BACKBUFFERCOUNT) && lpDDSurfaceDesc2->dwBackBufferCount) && + (!(lpDDSurfaceDesc2->ddsCaps.dwCaps & DDSCAPS_COMPLEX) || lpDDSurfaceDesc2->dwBackBufferCount > 3)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: invalid backbuffer requested. Count: " << lpDDSurfaceDesc2->dwBackBufferCount << + " dwFlags: " << Logging::hex(lpDDSurfaceDesc2->dwFlags)); + return DDERR_INVALIDPARAMS; + } + // Check for invalid surface flip flags if ((lpDDSurfaceDesc2->ddsCaps.dwCaps & DDSCAPS_FLIP) && (!(lpDDSurfaceDesc2->dwFlags & DDSD_BACKBUFFERCOUNT) || !(lpDDSurfaceDesc2->ddsCaps.dwCaps & DDSCAPS_COMPLEX))) @@ -587,7 +455,7 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE // Check for other unsupported pixel formats if ((lpDDSurfaceDesc2->dwFlags & DDSD_PIXELFORMAT) && (lpDDSurfaceDesc2->ddpfPixelFormat.dwFlags & - (DDPF_RGBTOYUV | DDPF_YUV | DDPF_BUMPDUDV | DDPF_BUMPLUMINANCE | DDPF_ALPHAPREMULT | DDPF_COMPRESSED | DDPF_ZPIXELS | + (DDPF_RGBTOYUV | DDPF_YUV | DDPF_ALPHAPREMULT | DDPF_COMPRESSED | DDPF_ZPIXELS | DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXEDTO8))) { LOG_LIMIT(100, __FUNCTION__ << " Error: PixelForamt not Implemented: " << lpDDSurfaceDesc2->ddpfPixelFormat); @@ -657,12 +525,6 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE DDSURFACEDESC2 Desc2 = *lpDDSurfaceDesc2; - // Add 3D device flag - if (DirectXVersion <= 2 && (Desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)) - { - Desc2.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; - } - // Check pixel format flag if ((Desc2.dwFlags & DDSD_PIXELFORMAT) && !Desc2.ddpfPixelFormat.dwFlags) { @@ -695,14 +557,19 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE // Updates for surface description Desc2.dwFlags |= DDSD_CAPS; - Desc2.ddsCaps.dwCaps4 = DDSCAPS4_CREATESURFACE | // Indicates surface was created using CreateSurface() - ((Desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ? DDSCAPS4_PRIMARYSURFACE : NULL); // Indicates surface is a primary surface or a backbuffer of a primary surface + Desc2.ddsCaps.dwCaps4 = DDSCAPS4_CREATESURFACE; // Indicates surface was created using CreateSurface() if (Desc2.ddsCaps.dwCaps & DDSCAPS_FLIP) { Desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER; } Desc2.dwReserved = 0; + // Check BackBufferCount flag + if ((Desc2.dwFlags & DDSD_BACKBUFFERCOUNT) && !(lpDDSurfaceDesc2->ddsCaps.dwCaps & DDSCAPS_COMPLEX)) + { + Desc2.dwFlags &= ~DDSD_BACKBUFFERCOUNT; + } + // BackBufferCount must be at least 1 if (Desc2.dwFlags & DDSD_BACKBUFFERCOUNT) { @@ -759,12 +626,6 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE Logging::Log() << __FUNCTION__ << " Found depth stencil surface: " << GetDisplayFormat(Desc2.ddpfPixelFormat); } - // Add flag for 3D device - if (DirectXVersion == 1 && (Desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)) - { - Desc2.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; - } - // Log primary surface if (Desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { @@ -806,42 +667,13 @@ HRESULT m_IDirectDrawX::CreateSurface2(LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRE return DD_OK; } - DDSURFACEDESC2 Desc2 = *lpDDSurfaceDesc2; - - if (ProxyDirectXVersion != DirectXVersion) - { - // BackBufferCount must be at least 1 - if (Desc2.dwFlags & DDSD_BACKBUFFERCOUNT) - { - if (!Desc2.dwBackBufferCount) - { - Desc2.dwBackBufferCount = 1; - } - } - else - { - Desc2.dwBackBufferCount = 0; - } - - // Add 3D device flag - if (DirectXVersion <= 2 && (Desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)) - { - Desc2.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; - } - } - - HRESULT hr = ProxyInterface->CreateSurface(&Desc2, lplpDDSurface, pUnkOuter); + HRESULT hr = ProxyInterface->CreateSurface(lpDDSurfaceDesc2, lplpDDSurface, pUnkOuter); if (SUCCEEDED(hr) && lplpDDSurface) { m_IDirectDrawSurfaceX *D3DSurfaceDevice = new m_IDirectDrawSurfaceX((IDirectDrawSurface7*)*lplpDDSurface, DirectXVersion); *lplpDDSurface = (LPDIRECTDRAWSURFACE7)D3DSurfaceDevice->GetWrapperInterfaceX(DirectXVersion); - - if (Config.ConvertToDirectDraw7) - { - D3DSurfaceDevice->SetDdrawParent(this); - } } return hr; @@ -893,78 +725,16 @@ HRESULT m_IDirectDrawX::DuplicateSurface(LPDIRECTDRAWSURFACE7 lpDDSurface, LPDIR m_IDirectDrawSurfaceX *D3DSurfaceDevice = new m_IDirectDrawSurfaceX((IDirectDrawSurface7*)*lplpDupDDSurface, DirectXVersion); *lplpDupDDSurface = (LPDIRECTDRAWSURFACE7)D3DSurfaceDevice->GetWrapperInterfaceX(DirectXVersion); - - if (Config.ConvertToDirectDraw7) - { - D3DSurfaceDevice->SetDdrawParent(this); - } } return hr; } -void m_IDirectDrawX::AddSurface(m_IDirectDrawSurfaceX* lpSurfaceX) -{ - if (!lpSurfaceX) - { - return; - } - - SurfaceList.push_back({ lpSurfaceX, 0, 0 }); -} - -void m_IDirectDrawX::ClearSurface(m_IDirectDrawSurfaceX* lpSurfaceX) -{ - // Remove attached surface from map - for (const auto& pDDraw : DDrawVector) - { - m_IDirect3DDeviceX* D3DDevice = pDDraw->D3DDeviceInterface; - if (D3DDevice) - { - D3DDevice->ClearSurface(lpSurfaceX); - } - if (lpSurfaceX == pDDraw->PrimarySurface) - { - pDDraw->PrimarySurface = nullptr; - ClipperHWnd = nullptr; - DisplayPixelFormat = {}; - } - if (lpSurfaceX == pDDraw->RenderTargetSurface) - { - pDDraw->SetRenderTargetSurface(nullptr); - } - if (lpSurfaceX == pDDraw->DepthStencilSurface) - { - pDDraw->SetDepthStencilSurface(nullptr); - } - - auto it = std::find_if(pDDraw->SurfaceList.begin(), pDDraw->SurfaceList.end(), - [lpSurfaceX](auto entry) { - return entry.Interface == lpSurfaceX; - }); - if (it != std::end(pDDraw->SurfaceList)) - { - for (UINT x = 0; x < it->RefCount; x++) - { - if (!Release(it->DxVersion)) break; - } - - pDDraw->SurfaceList.erase(it); - } - - for (const auto& pSurface : pDDraw->SurfaceList) - { - pSurface.Interface->RemoveAttachedSurfaceFromMap(lpSurfaceX); - } - } -} - HRESULT m_IDirectDrawX::EnumDisplayModes(DWORD dwFlags, LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext, LPDDENUMMODESCALLBACK lpEnumModesCallback, DWORD DirectXVersion) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (!lpEnumModesCallback || (lpDDSurfaceDesc && lpDDSurfaceDesc->dwSize != sizeof(DDSURFACEDESC))) { @@ -1043,8 +813,7 @@ HRESULT m_IDirectDrawX::EnumDisplayModes2(DWORD dwFlags, LPDDSURFACEDESC2 lpDDSu std::vector ResolutionList; // For games that require limited resolution return - SIZE LimitedResolutionList[] = - { + const SIZE LimitedResolutionList[] = { { 320, 200 }, { 320, 240 }, { 512, 384 }, @@ -1056,9 +825,8 @@ HRESULT m_IDirectDrawX::EnumDisplayModes2(DWORD dwFlags, LPDDSURFACEDESC2 lpDDSu { 1280, 720 }, { 1280, 1024 }, { 1600, 1200 }, - { (LONG)InitWidth, (LONG)InitHeight }, - { (LONG)Config.DdrawCustomWidth, (LONG)Config.DdrawCustomHeight }, - }; + { InitWidth, InitHeight }, + { (LONG)Config.DdrawCustomWidth, (LONG)Config.DdrawCustomHeight } }; // Enumerate modes for format XRGB UINT modeCount = d3d9Object->GetAdapterModeCount(D3DADAPTER_DEFAULT, D9DisplayFormat); @@ -1080,21 +848,21 @@ HRESULT m_IDirectDrawX::EnumDisplayModes2(DWORD dwFlags, LPDDSURFACEDESC2 lpDDSu // Set display refresh rate DWORD RefreshRate = (dwFlags & DDEDM_REFRESHRATES) ? d3ddispmode.RefreshRate : 0; + // Check if resolution has already been sent + bool IsResolutionAlreadySent = std::any_of(ResolutionList.begin(), ResolutionList.end(), + [&](const auto& res) { + return (res.Width == d3ddispmode.Width && res.Height == d3ddispmode.Height && (!RefreshRate || res.RefreshRate == RefreshRate)); + }); + // Check if the resolution is on the LimitedResolutionList - bool ResolutionOkToUse = (!Config.DdrawLimitDisplayModeCount || + bool IsResolutionSupported = (!Config.DdrawLimitDisplayModeCount || std::any_of(std::begin(LimitedResolutionList), std::end(LimitedResolutionList), - [&](const SIZE& entry) { - return ((DWORD)entry.cx == d3ddispmode.Width && (DWORD)entry.cy == d3ddispmode.Height); + [&](const auto& res) { + return ((DWORD)res.cx == d3ddispmode.Width && (DWORD)res.cy == d3ddispmode.Height); })); - // Check if resolution has already been sent - bool ResolutionAlreadySent = std::any_of(ResolutionList.begin(), ResolutionList.end(), - [&](const RESLIST& Entry) { - return (Entry.Width == d3ddispmode.Width && Entry.Height == d3ddispmode.Height && Entry.RefreshRate == RefreshRate); - }); - // Check mode - if (ResolutionOkToUse && !ResolutionAlreadySent && + if (!IsResolutionAlreadySent && IsResolutionSupported && (!EnumWidth || d3ddispmode.Width == EnumWidth) && (!EnumHeight || d3ddispmode.Height == EnumHeight)) { @@ -1188,8 +956,7 @@ HRESULT m_IDirectDrawX::EnumSurfaces(DWORD dwFlags, LPDDSURFACEDESC lpDDSurfaceD return DDERR_INVALIDPARAMS; } - // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if ((lpDDSurfaceDesc && lpDDSurfaceDesc->dwSize != sizeof(DDSURFACEDESC)) || (!lpDDSurfaceDesc && !(dwFlags & DDENUMSURFACES_ALL))) { @@ -1344,44 +1111,44 @@ HRESULT m_IDirectDrawX::GetCaps(LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (!lpDDDriverCaps && !lpDDHELCaps) - { - return DDERR_INVALIDPARAMS; - } - - if (lpDDDriverCaps) - { - lpDDDriverCaps->dwSize = - lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX3) ? sizeof(DDCAPS_DX3) : - lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX5) ? sizeof(DDCAPS_DX5) : - lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX6) ? sizeof(DDCAPS_DX6) : - lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX7) ? sizeof(DDCAPS_DX7) : - sizeof(DDCAPS_DX1); - } - if (lpDDHELCaps) + if (Config.Dd7to9) { - lpDDHELCaps->dwSize = - lpDDHELCaps->dwSize == sizeof(DDCAPS_DX3) ? sizeof(DDCAPS_DX3) : - lpDDHELCaps->dwSize == sizeof(DDCAPS_DX5) ? sizeof(DDCAPS_DX5) : - lpDDHELCaps->dwSize == sizeof(DDCAPS_DX6) ? sizeof(DDCAPS_DX6) : - lpDDHELCaps->dwSize == sizeof(DDCAPS_DX7) ? sizeof(DDCAPS_DX7) : - sizeof(DDCAPS_DX1); - } + if (!lpDDDriverCaps && !lpDDHELCaps) + { + return DDERR_INVALIDPARAMS; + } - DDCAPS DriverCaps = {}, HELCaps = {}; - DriverCaps.dwSize = sizeof(DDCAPS); - HELCaps.dwSize = sizeof(DDCAPS); + if (lpDDDriverCaps) + { + lpDDDriverCaps->dwSize = + lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX3) ? sizeof(DDCAPS_DX3) : + lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX5) ? sizeof(DDCAPS_DX5) : + lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX6) ? sizeof(DDCAPS_DX6) : + lpDDDriverCaps->dwSize == sizeof(DDCAPS_DX7) ? sizeof(DDCAPS_DX7) : + sizeof(DDCAPS_DX1); + } + if (lpDDHELCaps) + { + lpDDHELCaps->dwSize = + lpDDHELCaps->dwSize == sizeof(DDCAPS_DX3) ? sizeof(DDCAPS_DX3) : + lpDDHELCaps->dwSize == sizeof(DDCAPS_DX5) ? sizeof(DDCAPS_DX5) : + lpDDHELCaps->dwSize == sizeof(DDCAPS_DX6) ? sizeof(DDCAPS_DX6) : + lpDDHELCaps->dwSize == sizeof(DDCAPS_DX7) ? sizeof(DDCAPS_DX7) : + sizeof(DDCAPS_DX1); + } - HRESULT hr = DD_OK; + DDCAPS DriverCaps = {}, HELCaps = {}; + DriverCaps.dwSize = sizeof(DDCAPS); + HELCaps.dwSize = sizeof(DDCAPS); - if (Config.Dd7to9) - { // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, false))) { return DDERR_GENERIC; } + HRESULT hr = DD_OK; + // Get video memory DDSCAPS2 ddsCaps2 = {}; ddsCaps2.dwCaps = DDSCAPS_VIDEOMEMORY; @@ -1413,36 +1180,31 @@ HRESULT m_IDirectDrawX::GetCaps(LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) DriverCaps.dwNumFourCCCodes = dwNumFourCCCodes; HELCaps.dwNumFourCCCodes = dwNumFourCCCodes; } - } - else - { if (lpDDDriverCaps) { - DriverCaps.dwSize = lpDDDriverCaps->dwSize; + ConvertCaps(*lpDDDriverCaps, DriverCaps); } if (lpDDHELCaps) { - HELCaps.dwSize = lpDDHELCaps->dwSize; + ConvertCaps(*lpDDHELCaps, HELCaps); } - hr = ProxyInterface->GetCaps((lpDDDriverCaps) ? &DriverCaps : nullptr, (lpDDHELCaps) ? &HELCaps : nullptr); + return hr; } + HRESULT hr = ProxyInterface->GetCaps(lpDDDriverCaps, lpDDHELCaps); + if (SUCCEEDED(hr)) { if (lpDDDriverCaps) { - ConvertCaps(*lpDDDriverCaps, DriverCaps); + AdjustVidMemory(&lpDDDriverCaps->dwVidMemTotal, &lpDDDriverCaps->dwVidMemFree); } if (lpDDHELCaps) { - ConvertCaps(*lpDDHELCaps, HELCaps); + AdjustVidMemory(&lpDDHELCaps->dwVidMemTotal, &lpDDHELCaps->dwVidMemFree); } } - else - { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to GetCaps!"); - } return hr; } @@ -1451,8 +1213,7 @@ HRESULT m_IDirectDrawX::GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert to LPDDSURFACEDESC2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { if (!lpDDSurfaceDesc || lpDDSurfaceDesc->dwSize != sizeof(DDSURFACEDESC)) { @@ -1729,7 +1490,6 @@ HRESULT m_IDirectDrawX::Initialize(GUID FAR * lpGUID) return (hr == DDERR_ALREADYINITIALIZED) ? DD_OK : hr; } -// Resets the mode of the display device hardware for the primary surface to what it was before the IDirectDraw7::SetDisplayMode method was called. HRESULT m_IDirectDrawX::RestoreDisplayMode() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -1742,23 +1502,35 @@ HRESULT m_IDirectDrawX::RestoreDisplayMode() return DDERR_NOEXCLUSIVEMODE; } - // Reset mode - Exclusive.Width = DefaultWidth; - Exclusive.Height = DefaultHeight; - Exclusive.BPP = Utils::GetBitCount(GetHwnd()); - DisplayMode.Width = DefaultWidth; - DisplayMode.Height = DefaultHeight; - DisplayMode.BPP = Exclusive.BPP; - Device.Width = (Config.DdrawUseNativeResolution || Config.DdrawOverrideWidth) ? Device.Width : DefaultWidth; - Device.Height = (Config.DdrawUseNativeResolution || Config.DdrawOverrideHeight) ? Device.Height : DefaultHeight; + // Resets the mode of the display device hardware for the primary surface to what it was before the IDirectDraw7::SetDisplayMode method was called. + + ScopedDDCriticalSection ThreadLockDD; // Release d3d9 device if (d3d9Device) { ReleaseAllD9Resources(true, false); ReleaseD9Device(); + + // Reset display + if (Config.EnableWindowMode) + { + ChangeDisplaySettingsEx(nullptr, nullptr, nullptr, CDS_RESET, nullptr); + } } + // Reset mode + DisplayMode.Width = 0; + DisplayMode.Height = 0; + DisplayMode.BPP = 0; + DisplayMode.RefreshRate = 0; + Exclusive.Width = 0; + Exclusive.Height = 0; + Exclusive.BPP = 0; + Exclusive.RefreshRate = 0; + Device.Width = (Config.DdrawUseNativeResolution || Config.DdrawOverrideWidth) ? Device.Width : 0; + Device.Height = (Config.DdrawUseNativeResolution || Config.DdrawOverrideHeight) ? Device.Height : 0; + return DD_OK; } @@ -1795,6 +1567,8 @@ HRESULT m_IDirectDrawX::SetCooperativeLevel(HWND hWnd, DWORD dwFlags, DWORD Dire bool LastFPUPreserve = Device.FPUPreserve; bool LastWindowed = Device.IsWindowed; + ScopedDDCriticalSection ThreadLockDD; + // Set windowed mode if (dwFlags & DDSCL_NORMAL) { @@ -1991,6 +1765,8 @@ HRESULT m_IDirectDrawX::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBP DWORD NewBPP = (Config.DdrawOverrideBitMode) ? Config.DdrawOverrideBitMode : dwBPP; + ScopedDDCriticalSection ThreadLockDD; + if (DisplayMode.Width != dwWidth || DisplayMode.Height != dwHeight || DisplayMode.BPP != NewBPP || (dwRefreshRate && DisplayMode.RefreshRate != dwRefreshRate)) { DWORD FoundWidth = dwWidth; @@ -2069,12 +1845,6 @@ HRESULT m_IDirectDrawX::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBP Exclusive.RefreshRate = dwRefreshRate; } - // Get screensize - if (!d3d9Device || presParams.Windowed) - { - Utils::GetScreenSize(DisplayMode.hWnd, (LONG&)DefaultWidth, (LONG&)DefaultHeight); - } - // Update the d3d9 device to use new display mode if (LastWidth != Device.Width || LastHeight != Device.Height || (!Device.IsWindowed && LastRefreshRate != DisplayMode.RefreshRate)) { @@ -2139,8 +1909,14 @@ HRESULT m_IDirectDrawX::WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent) return DDERR_GENERIC; } +#ifdef ENABLE_PROFILING + auto startTime = std::chrono::high_resolution_clock::now(); +#endif + D3DRASTER_STATUS RasterStatus = {}; + HRESULT hr = DD_OK; + // Check flags switch (dwFlags) { @@ -2149,7 +1925,7 @@ HRESULT m_IDirectDrawX::WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent) if (OpenD3DDDI(GetDC()) && D3DDDIWaitForVsync()) { // Success using D3DKMTWaitForVerticalBlankEvent - return DD_OK; + break; } // Fallback: Wait for vertical blank begin using raster status @@ -2157,7 +1933,7 @@ HRESULT m_IDirectDrawX::WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent) { Utils::BusyWaitYield(0); } - return DD_OK; + break; case DDWAITVB_BLOCKEND: // First, wait for the vertical blank to begin @@ -2179,33 +1955,39 @@ HRESULT m_IDirectDrawX::WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent) { Utils::BusyWaitYield(0); } - return DD_OK; + break; case DDWAITVB_BLOCKBEGINEVENT: // This value is unsupported Logging::Log() << __FUNCTION__ << " Error: DDWAITVB_BLOCKBEGINEVENT is not supported!"; - return DDERR_UNSUPPORTED; + hr = DDERR_UNSUPPORTED; + break; default: // Invalid parameter - return DDERR_INVALIDPARAMS; + hr = DDERR_INVALIDPARAMS; + break; } + +#ifdef ENABLE_PROFILING + Logging::Log() << __FUNCTION__ << " (" << this << ") hr = " << (D3DERR)hr << " Timing = " << Logging::GetTimeLapseInMS(startTime); +#endif + + return hr; } - // Call the original interface if not using D3D9 return ProxyInterface->WaitForVerticalBlank(dwFlags, hEvent); } -/*********************************/ -/*** Added in the v2 interface ***/ -/*********************************/ +// ****************************** +// IDirectDraw v2 functions +// ****************************** HRESULT m_IDirectDrawX::GetAvailableVidMem(LPDDSCAPS lpDDSCaps, LPDWORD lpdwTotal, LPDWORD lpdwFree) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - // Game using old DirectX, Convert DDSCAPS to DDSCAPS2 - if (ProxyDirectXVersion > 3) + if (Config.Dd7to9) { DDSCAPS2 Caps2; if (lpDDSCaps) @@ -2228,8 +2010,6 @@ HRESULT m_IDirectDrawX::GetAvailableVidMem2(LPDDSCAPS2 lpDDSCaps2, LPDWORD lpdwT { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - HRESULT hr = DD_OK; - if (Config.Dd7to9) { if (!lpdwTotal && !lpdwFree) @@ -2294,11 +2074,14 @@ HRESULT m_IDirectDrawX::GetAvailableVidMem2(LPDDSCAPS2 lpDDSCaps2, LPDWORD lpdwT { *lpdwFree = AvailableMemory; } + + // Ajdust available memory + AdjustVidMemory(lpdwTotal, lpdwFree); + + return DD_OK; } - else - { - hr = ProxyInterface->GetAvailableVidMem(lpDDSCaps2, lpdwTotal, lpdwFree); - } + + HRESULT hr = ProxyInterface->GetAvailableVidMem(lpDDSCaps2, lpdwTotal, lpdwFree); // Ajdust available memory AdjustVidMemory(lpdwTotal, lpdwFree); @@ -2306,9 +2089,9 @@ HRESULT m_IDirectDrawX::GetAvailableVidMem2(LPDDSCAPS2 lpDDSCaps2, LPDWORD lpdwT return hr; } -/*********************************/ -/*** Added in the V4 Interface ***/ -/*********************************/ +// ****************************** +// IDirectDraw v4 functions +// ****************************** HRESULT m_IDirectDrawX::GetSurfaceFromDC(HDC hdc, LPDIRECTDRAWSURFACE7 * lpDDS, DWORD DirectXVersion) { @@ -2336,6 +2119,8 @@ HRESULT m_IDirectDrawX::RestoreAllSurfaces() if (Config.Dd7to9) { + ScopedDDCriticalSection ThreadLockDD; + // Check for device interface if (FAILED(CheckInterface(__FUNCTION__, true))) { @@ -2406,7 +2191,7 @@ HRESULT m_IDirectDrawX::GetDeviceIdentifier(LPDDDEVICEIDENTIFIER lpdddi, DWORD d { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; - if (ProxyDirectXVersion > 4) + if (Config.Dd7to9) { if (!lpdddi) { @@ -2463,6 +2248,10 @@ HRESULT m_IDirectDrawX::GetDeviceIdentifier2(LPDDDEVICEIDENTIFIER2 lpdddi2, DWOR return ProxyInterface->GetDeviceIdentifier(lpdddi2, dwFlags); } +// ****************************** +// IDirectDraw v7 functions +// ****************************** + HRESULT m_IDirectDrawX::StartModeTest(LPSIZE lpModesToTest, DWORD dwNumEntries, DWORD dwFlags) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -2489,9 +2278,9 @@ HRESULT m_IDirectDrawX::EvaluateMode(DWORD dwFlags, DWORD * pSecondsUntilTimeout return ProxyInterface->EvaluateMode(dwFlags, pSecondsUntilTimeout); } -/************************/ -/*** Helper functions ***/ -/************************/ +// ****************************** +// Helper functions +// ****************************** void m_IDirectDrawX::InitInterface(DWORD DirectXVersion) { @@ -2502,16 +2291,13 @@ void m_IDirectDrawX::InitInterface(DWORD DirectXVersion) AddRef(DirectXVersion); - SetCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; DDrawVector.push_back(this); if (DDrawVector.size() == 1) { // Get screensize - DefaultWidth = 0; - DefaultHeight = 0; - Utils::GetScreenSize(nullptr, (LONG&)DefaultWidth, (LONG&)DefaultHeight); LastWindowRect = {}; // Release DC @@ -2583,11 +2369,10 @@ void m_IDirectDrawX::InitInterface(DWORD DirectXVersion) FocusWindowThreadID = 0; // Display resolution - Utils::GetScreenSize(GetHwnd(), (LONG&)InitWidth, (LONG&)InitHeight); if (Config.DdrawUseNativeResolution) { - Device.Width = InitWidth; - Device.Height = InitHeight; + Device.Width = static_cast(InitWidth); + Device.Height = static_cast(InitHeight); } else { @@ -2599,9 +2384,7 @@ void m_IDirectDrawX::InitInterface(DWORD DirectXVersion) // Prepare for present from another thread if (Config.DdrawAutoFrameSkip) { - PresentThread.IsInitialized = true; - InitializeCriticalSection(&PresentThread.ddpt); - PresentThread.workerEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + PresentThread.exitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); PresentThread.workerThread = CreateThread(NULL, 0, PresentThreadFunction, NULL, 0, NULL); } @@ -2694,8 +2477,6 @@ void m_IDirectDrawX::InitInterface(DWORD DirectXVersion) m_IDirectDrawSurfaceX::StartSharedEmulatedMemory(); } - ReleaseCriticalSection(); - // Check interface to create d3d9 object CheckInterface(__FUNCTION__, false); } @@ -2707,8 +2488,7 @@ void m_IDirectDrawX::ReleaseInterface() return; } - SetCriticalSection(); - SetPTCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; // Don't delete wrapper interface SaveInterfaceAddress(WrapperInterface, WrapperInterfaceBackup); @@ -2726,7 +2506,7 @@ void m_IDirectDrawX::ReleaseInterface() DDrawVector.erase(std::remove(DDrawVector.begin(), DDrawVector.end(), this), DDrawVector.end()); // Re-enable exclusive mode once non-exclusive device is released - if (ExclusiveMode && + if (!DDrawVector.empty() && ExclusiveMode && Device.IsWindowed && FullScreenWindowed && DisplayMode.SetBy == this && DisplayMode.SetBy != Exclusive.SetBy && std::find(DDrawVector.begin(), DDrawVector.end(), Exclusive.SetBy) != DDrawVector.end()) @@ -2735,7 +2515,10 @@ void m_IDirectDrawX::ReleaseInterface() Device.IsWindowed = false; FullScreenWindowed = false; - CreateD9Device(__FUNCTION__); + if (d3d9Device) + { + CreateD9Device(__FUNCTION__); + } } // Clear SetBy handles @@ -2748,19 +2531,13 @@ void m_IDirectDrawX::ReleaseInterface() Exclusive.SetBy = nullptr; } - // Release Direct3DDevice interfaces - if (D3DDeviceInterface) - { - D3DDeviceInterface->ClearDdraw(); - D3DDeviceInterface = nullptr; - } - - // Release Direct3D interfaces - if (D3DInterface) + // Delete released surfaces + for (const auto& pSurface : ReleasedSurfaceList) { - D3DInterface->DeleteMe(); - D3DInterface = nullptr; + pSurface->ClearDdraw(); + pSurface->DeleteMe(); } + ReleasedSurfaceList.clear(); // Release color control if (ColorControlInterface) @@ -2798,13 +2575,6 @@ void m_IDirectDrawX::ReleaseInterface() } SurfaceList.clear(); - // Delete released surfaces - for (const auto& pSurface : ReleasedSurfaceList) - { - pSurface->DeleteMe(); - } - ReleasedSurfaceList.clear(); - // Release vertex buffers for (const auto& pVertexBuffer : VertexBufferList) { @@ -2813,21 +2583,41 @@ void m_IDirectDrawX::ReleaseInterface() } VertexBufferList.clear(); - ReleasePTCriticalSection(); + // Release Direct3DDevice interfaces + if (D3DDeviceInterface) + { + D3DDeviceInterface->ClearDdraw(); + D3DDeviceInterface = nullptr; + } + + // Release Direct3D interfaces + if (D3DInterface) + { + D3DInterface->ClearDdraw(); + D3DInterface->DeleteMe(); + D3DInterface = nullptr; + } if (DDrawVector.empty()) { // Close present thread first if (PresentThread.IsInitialized) { - PresentThread.EnableThreadFlag = false; // Tell thread to exit - EnterCriticalSection(&PresentThread.ddpt); // Ensure thread is not running present - SetEvent(PresentThread.workerEvent); // Trigger thread - LeaveCriticalSection(&PresentThread.ddpt); - WaitForSingleObject(PresentThread.workerThread, INFINITE); // Wait for thread to finish - CloseHandle(PresentThread.workerThread); // Close thread handle - CloseHandle(PresentThread.workerEvent); // Close event handle - PresentThread.IsInitialized = false; + // Trigger thread and terminate the thread + DWORD exitCode = 0; + while (GetExitCodeThread(PresentThread.workerThread, &exitCode) && exitCode == STILL_ACTIVE) + { + SetEvent(PresentThread.exitEvent); + Sleep(0); + } + + // Close handles + CloseHandle(PresentThread.workerThread); + CloseHandle(PresentThread.exitEvent); + + // Clean up variables + PresentThread.workerThread = nullptr; + PresentThread.exitEvent = nullptr; } // Release all resources @@ -2853,22 +2643,74 @@ void m_IDirectDrawX::ReleaseInterface() { ReleaseDC(DisplayMode.hWnd, DisplayMode.DC); DisplayMode.DC = nullptr; + DisplayMode.hWnd = nullptr; } // Clean up shared memory m_IDirectDrawSurfaceX::CleanupSharedEmulatedMemory(); - // Delete critical section - if (PresentThread.IsInitialized) + // Clean up dummy memory + m_IDirectDrawSurfaceX::CleanupDummySurface(); + } +} + +HRESULT m_IDirectDrawX::CheckInterface(char* FunctionName, bool CheckD3DDevice) +{ + // Check for object, if not then create it + if (!d3d9Object) + { + // Create d3d9 object + if (FAILED(CreateD9Object())) { - DeleteCriticalSection(&PresentThread.ddpt); + LOG_LIMIT(100, FunctionName << " Error: d3d9 object not setup!"); + return DDERR_GENERIC; } + } - // Clean up dummy memory - dummySurface.clear(); + // Check for device, if not then create it + if (CheckD3DDevice && !CheckD9Device(__FUNCTION__)) + { + LOG_LIMIT(100, FunctionName << " Error: d3d9 device not setup!"); + return DDERR_GENERIC; + } + + return DD_OK; +} + +void* m_IDirectDrawX::GetWrapperInterfaceX(DWORD DirectXVersion) +{ + switch (DirectXVersion) + { + case 0: + if (WrapperInterface7) return WrapperInterface7; + if (WrapperInterface4) return WrapperInterface4; + if (WrapperInterface3) return WrapperInterface3; + if (WrapperInterface2) return WrapperInterface2; + if (WrapperInterface) return WrapperInterface; + break; + case 1: + return GetInterfaceAddress(WrapperInterface, WrapperInterfaceBackup, (LPDIRECTDRAW)ProxyInterface, this); + case 2: + return GetInterfaceAddress(WrapperInterface2, WrapperInterfaceBackup2, (LPDIRECTDRAW2)ProxyInterface, this); + case 3: + return GetInterfaceAddress(WrapperInterface3, WrapperInterfaceBackup3, (LPDIRECTDRAW3)ProxyInterface, this); + case 4: + return GetInterfaceAddress(WrapperInterface4, WrapperInterfaceBackup4, (LPDIRECTDRAW4)ProxyInterface, this); + case 7: + return GetInterfaceAddress(WrapperInterface7, WrapperInterfaceBackup7, (LPDIRECTDRAW7)ProxyInterface, this); } + LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion); + return nullptr; +} - ReleaseCriticalSection(); +m_IDirectDrawX* m_IDirectDrawX::GetDirectDrawInterface() +{ + if (DDrawVector.empty()) + { + return nullptr; + } + + return DDrawVector[0]; } HWND m_IDirectDrawX::GetHwnd() @@ -2948,39 +2790,16 @@ void m_IDirectDrawX::GetSurfaceDisplay(DWORD& Width, DWORD& Height, DWORD& BPP, } void m_IDirectDrawX::GetDisplayPixelFormat(DDPIXELFORMAT &ddpfPixelFormat, DWORD BPP) -{ - ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - if (BPP == DisplayPixelFormat.dwRGBBitCount) - { - ddpfPixelFormat = DisplayPixelFormat; - } - else - { - SetDisplayFormat(ddpfPixelFormat, BPP); - } -} - -HRESULT m_IDirectDrawX::CheckInterface(char *FunctionName, bool CheckD3DDevice) -{ - // Check for object, if not then create it - if (!d3d9Object) - { - // Create d3d9 object - if (FAILED(CreateD9Object())) - { - LOG_LIMIT(100, FunctionName << " Error: d3d9 object not setup!"); - return DDERR_GENERIC; - } +{ + ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + if (BPP == DisplayPixelFormat.dwRGBBitCount) + { + ddpfPixelFormat = DisplayPixelFormat; } - - // Check for device, if not then create it - if (CheckD3DDevice && !CheckD9Device(__FUNCTION__)) + else { - LOG_LIMIT(100, FunctionName << " Error: d3d9 device not setup!"); - return DDERR_GENERIC; + SetDisplayFormat(ddpfPixelFormat, BPP); } - - return DD_OK; } void m_IDirectDrawX::SetD3DDevice(m_IDirect3DDeviceX* lpD3DDevice) @@ -2995,6 +2814,14 @@ void m_IDirectDrawX::SetD3DDevice(m_IDirect3DDeviceX* lpD3DDevice) LOG_LIMIT(100, __FUNCTION__ << " Warning: Direct3D Device has already been created!"); } + for (const auto& entry : DDrawVector) + { + if (entry != this && entry->D3DDeviceInterface != nullptr) + { + LOG_LIMIT(100, __FUNCTION__ << " Warning: a Direct3D Device exists in another DirectDraw instance!"); + } + } + D3DDeviceInterface = lpD3DDevice; } @@ -3022,9 +2849,13 @@ bool m_IDirectDrawX::IsInScene() bool m_IDirectDrawX::CheckD9Device(char* FunctionName) { // Check for device, if not then create it - if (!d3d9Device && FAILED(CreateD9Device(FunctionName))) + if (!d3d9Device) { - return false; + ScopedDDCriticalSection ThreadLockDD; + if (FAILED(CreateD9Device(FunctionName))) + { + return false; + } } // Check for delay while resolution switching @@ -3100,7 +2931,8 @@ LPDIRECT3DVERTEXBUFFER9 m_IDirectDrawX::GetValidateDeviceVertexBuffer(DWORD& FVF if (!validateDeviceVertexBuffer) { - HRESULT hr = d3d9Device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_XYZ | D3DFVF_DIFFUSE, D3DPOOL_MANAGED, &validateDeviceVertexBuffer, NULL); + // Create in video memory and then use discard when locking to improve system performance + HRESULT hr = d3d9Device->CreateVertexBuffer(sizeof(vertices), D3DUSAGE_DYNAMIC, D3DFVF_XYZ | D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &validateDeviceVertexBuffer, NULL); if (FAILED(hr)) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to create vertex buffer: " << (DDERR)hr); @@ -3109,13 +2941,15 @@ LPDIRECT3DVERTEXBUFFER9 m_IDirectDrawX::GetValidateDeviceVertexBuffer(DWORD& FVF // Fill the vertex buffer with data void* pVertices = nullptr; - hr = validateDeviceVertexBuffer->Lock(0, sizeof(vertices), &pVertices, 0); + hr = validateDeviceVertexBuffer->Lock(0, sizeof(vertices), &pVertices, D3DLOCK_DISCARD); + if (FAILED(hr)) { LOG_LIMIT(100, __FUNCTION__ << " Error: Failed to Lock vertex buffer: " << (DDERR)hr); validateDeviceVertexBuffer->Release(); return nullptr; } + memcpy(pVertices, vertices, sizeof(vertices)); validateDeviceVertexBuffer->Unlock(); } @@ -3145,7 +2979,8 @@ LPDIRECT3DINDEXBUFFER9 m_IDirectDrawX::GetIndexBuffer(LPWORD lpwIndices, DWORD d if (!d3d9IndexBuffer || NewIndexSize > IndexBufferSize) { ReleaseD3D9IndexBuffer(); - hr = d3d9Device->CreateIndexBuffer(NewIndexSize, D3DUSAGE_DYNAMIC, D3DFMT_INDEX16, D3DPOOL_SYSTEMMEM, &d3d9IndexBuffer, nullptr); + // Create in video memory and then use discard when locking to improve system performance + hr = d3d9Device->CreateIndexBuffer(NewIndexSize, D3DUSAGE_DYNAMIC, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &d3d9IndexBuffer, nullptr); } if (FAILED(hr)) @@ -3160,11 +2995,7 @@ LPDIRECT3DINDEXBUFFER9 m_IDirectDrawX::GetIndexBuffer(LPWORD lpwIndices, DWORD d } void* pData = nullptr; - hr = d3d9IndexBuffer->Lock(0, NewIndexSize, &pData, D3DLOCK_NOSYSLOCK); - if (FAILED(hr)) - { - hr = d3d9IndexBuffer->Lock(0, NewIndexSize, &pData, 0); - } + hr = d3d9IndexBuffer->Lock(0, NewIndexSize, &pData, D3DLOCK_DISCARD); if (FAILED(hr)) { @@ -3184,7 +3015,6 @@ DWORD m_IDirectDrawX::GetHwndThreadID() return FocusWindowThreadID; } -// Get AntiAliasing type and quality D3DMULTISAMPLE_TYPE m_IDirectDrawX::GetMultiSampleTypeQuality(D3DFORMAT Format, DWORD MaxSampleType, DWORD& QualityLevels) { if (d3d9Object) @@ -3205,7 +3035,6 @@ D3DMULTISAMPLE_TYPE m_IDirectDrawX::GetMultiSampleTypeQuality(D3DFORMAT Format, return D3DMULTISAMPLE_NONE; } -// Resets the d3d9 device HRESULT m_IDirectDrawX::ResetD9Device() { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -3241,8 +3070,7 @@ HRESULT m_IDirectDrawX::ResetD9Device() return DDERR_WRONGMODE; } - SetCriticalSection(); - SetPTCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; // Reset device if current thread matches creation thread if (IsWindow(hFocusWindow) && FocusWindowThreadID == GetCurrentThreadId()) @@ -3287,16 +3115,14 @@ HRESULT m_IDirectDrawX::ResetD9Device() WndProc::SwitchingResolution = false; } - ReleasePTCriticalSection(); - ReleaseCriticalSection(); - // Return return hr; } -// Creates or resets the d3d9 device HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName) { + // To avoid threadlock, cannot have any critical sections in this function or any sub-functions + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; // Check for device interface @@ -3323,9 +3149,6 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName) return d3d9Device ? DD_OK : DDERR_GENERIC; } - SetCriticalSection(); - SetPTCriticalSection(); - HRESULT hr = DD_OK; do { // Last call variables @@ -3363,8 +3186,8 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName) // Use default desktop resolution if (ExclusiveMode || Config.FullscreenWindowMode || Config.ForceExclusiveFullscreen) { - BackBufferWidth = DefaultWidth; - BackBufferHeight = DefaultHeight; + BackBufferWidth = InitWidth; + BackBufferHeight = InitHeight; } else { @@ -3467,19 +3290,64 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName) break; } - Logging::Log() << __FUNCTION__ << " Recreate device! Last create: " << LasthWnd << "->" << hWnd << " " << - " Windowed: " << presParamsBackup.Windowed << "->" << presParams.Windowed << " " << - presParamsBackup.BackBufferWidth << "x" << presParamsBackup.BackBufferHeight << "->" << - presParams.BackBufferWidth << "x" << presParams.BackBufferHeight << " " << - Logging::hex(LastBehaviorFlags) << "->" << Logging::hex(BehaviorFlags); + // Check if device needs to be reset + hr = TestD3D9CooperativeLevel(); + if ((hr == D3D_OK || hr == DDERR_NOEXCLUSIVEMODE || hr == D3DERR_DEVICENOTRESET) && + presParamsBackup.Windowed == presParams.Windowed && + presParamsBackup.hDeviceWindow == presParams.hDeviceWindow && + LastBehaviorFlags == BehaviorFlags) + { + Logging::Log() << __FUNCTION__ << " Resetting device! Last create: " << LasthWnd << "->" << hWnd << " " << + " Windowed: " << presParamsBackup.Windowed << "->" << presParams.Windowed << " " << + presParamsBackup.BackBufferWidth << "x" << presParamsBackup.BackBufferHeight << "->" << + presParams.BackBufferWidth << "x" << presParams.BackBufferHeight << " " << + Logging::hex(LastBehaviorFlags) << "->" << Logging::hex(BehaviorFlags); + + ReleaseAllD9Resources(true, false); - ReleaseAllD9Resources(true, false); - ReleaseD9Device(); + // Prepare window and display size + if ((!presParams.Windowed || FullScreenWindowed) && !Config.EnableWindowMode) + { + Utils::SetDisplaySettings(hWnd, presParams.BackBufferWidth, presParams.BackBufferHeight); + + SetWindowPos(hWnd, ((GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP), + 0, 0, presParams.BackBufferWidth, presParams.BackBufferHeight, SWP_NOZORDER | SWP_NOMOVE); + } + + hr = d3d9Device->Reset(&presParams); + + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to reset Direct3D9 device! " << (DDERR)hr << " " << + presParams.BackBufferWidth << "x" << presParams.BackBufferHeight << " refresh: " << presParams.FullScreen_RefreshRateInHz << + " format: " << presParams.BackBufferFormat << " wnd: " << hWnd << " params: " << presParams << " flags: " << Logging::hex(BehaviorFlags)); - // Reset display mode after release when display mode is already setup and there is a primary surface - if (presParams.Windowed && (FullScreenWindowed || (PrimarySurface && DisplayMode.Width == CurrentWidth && DisplayMode.Height == CurrentHeight))) + ReleaseD9Device(); + } + + // Reset display mode after release when display mode is already setup and there is a primary surface + if (presParams.Windowed && (FullScreenWindowed || (PrimarySurface && DisplayMode.Width == CurrentWidth && DisplayMode.Height == CurrentHeight))) + { + Utils::SetDisplaySettings(hWnd, DisplayMode.Width, DisplayMode.Height); + } + } + // Just release device and recreate it + else { - Utils::SetDisplaySettings(hWnd, DisplayMode.Width, DisplayMode.Height); + Logging::Log() << __FUNCTION__ << " Recreate device! Last create: " << LasthWnd << "->" << hWnd << " " << + " Windowed: " << presParamsBackup.Windowed << "->" << presParams.Windowed << " " << + presParamsBackup.BackBufferWidth << "x" << presParamsBackup.BackBufferHeight << "->" << + presParams.BackBufferWidth << "x" << presParams.BackBufferHeight << " " << + Logging::hex(LastBehaviorFlags) << "->" << Logging::hex(BehaviorFlags); + + ReleaseAllD9Resources(true, false); + ReleaseD9Device(); + + // Reset display mode after release when display mode is already setup and there is a primary surface + if (presParams.Windowed && (FullScreenWindowed || (PrimarySurface && DisplayMode.Width == CurrentWidth && DisplayMode.Height == CurrentHeight))) + { + Utils::SetDisplaySettings(hWnd, DisplayMode.Width, DisplayMode.Height); + } } } @@ -3526,7 +3394,7 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName) FourCCsList.clear(); // Create dummy memory (2x larger) - dummySurface.resize(presParams.BackBufferWidth * presParams.BackBufferHeight * 4 * 2); + m_IDirectDrawSurfaceX::SizeDummySurface(presParams.BackBufferWidth * presParams.BackBufferHeight * 4 * 2); // Set render target ReSetRenderTarget(); @@ -3607,9 +3475,6 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName) } while (false); - ReleasePTCriticalSection(); - ReleaseCriticalSection(); - // Return result return hr; } @@ -3723,7 +3588,6 @@ void m_IDirectDrawX::UpdateVertices(DWORD Width, DWORD Height) IsDeviceVerticesSet = true; } -// Creates d3d9 object HRESULT m_IDirectDrawX::CreateD9Object() { // Create d3d9 object @@ -3761,30 +3625,30 @@ HRESULT m_IDirectDrawX::TestD3D9CooperativeLevel() return DD_OK; } -// Set backbuffer to render target void m_IDirectDrawX::ClearRenderTarget() { if (d3d9Device && UsingCustomRenderTarget) { - IDirect3DSurface9* pBackBuffer = nullptr; - if (SUCCEEDED(d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) + ComPtr pBackBuffer; + if (SUCCEEDED(d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, pBackBuffer.GetAddressOf()))) { UsingCustomRenderTarget = false; d3d9Device->SetRenderState(D3DRS_ZENABLE, FALSE); d3d9Device->SetDepthStencilSurface(nullptr); - d3d9Device->SetRenderTarget(0, pBackBuffer); - - pBackBuffer->Release(); + d3d9Device->SetRenderTarget(0, pBackBuffer.Get()); } } } void m_IDirectDrawX::ReSetRenderTarget() { + // To avoid threadlock, cannot have any critical sections in this function or any sub-functions + if (RenderTargetSurface && !UsingCustomRenderTarget) { - SetRenderTargetSurface(RenderTargetSurface); + // Don't check interface to prevent threads from getting thread locked (CreateD9Device can be called from a different thread) + SetRenderTargetSurface(RenderTargetSurface, false); } } @@ -3796,11 +3660,8 @@ void m_IDirectDrawX::SetCurrentRenderTarget() } } -HRESULT m_IDirectDrawX::SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface) +HRESULT m_IDirectDrawX::SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface, bool ShouldCheckInterface) { - SetCriticalSection(); - SetPTCriticalSection(); - HRESULT hr = D3D_OK; do { @@ -3833,7 +3694,7 @@ HRESULT m_IDirectDrawX::SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface) // Set new render target if (d3d9Device) { - LPDIRECT3DSURFACE9 pSurfaceD9 = RenderTargetSurface->GetD3d9Surface(); + LPDIRECT3DSURFACE9 pSurfaceD9 = RenderTargetSurface->GetD3d9Surface(ShouldCheckInterface); if (pSurfaceD9) { UsingCustomRenderTarget = true; @@ -3849,7 +3710,7 @@ HRESULT m_IDirectDrawX::SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface) } m_IDirectDrawSurfaceX* pSurfaceZBuffer = RenderTargetSurface->GetAttachedDepthStencil(); - hr = SetDepthStencilSurface(pSurfaceZBuffer); + hr = SetDepthStencilSurface(pSurfaceZBuffer, ShouldCheckInterface); if (FAILED(hr)) { @@ -3858,13 +3719,10 @@ HRESULT m_IDirectDrawX::SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface) } } while (false); - ReleasePTCriticalSection(); - ReleaseCriticalSection(); - return hr; } -HRESULT m_IDirectDrawX::SetDepthStencilSurface(m_IDirectDrawSurfaceX* lpSurface) +HRESULT m_IDirectDrawX::SetDepthStencilSurface(m_IDirectDrawSurfaceX* lpSurface, bool ShouldCheckInterface) { HRESULT hr = D3D_OK; @@ -3886,7 +3744,7 @@ HRESULT m_IDirectDrawX::SetDepthStencilSurface(m_IDirectDrawSurfaceX* lpSurface) if (d3d9Device) { - LPDIRECT3DSURFACE9 pSurfaceD9 = DepthStencilSurface->GetD3d9Surface(); + LPDIRECT3DSURFACE9 pSurfaceD9 = DepthStencilSurface->GetD3d9Surface(ShouldCheckInterface); if (pSurfaceD9) { d3d9Device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); @@ -3921,7 +3779,7 @@ void m_IDirectDrawX::Clear3DFlagForAllSurfaces() } } -inline void m_IDirectDrawX::ResetAllSurfaceDisplay() +void m_IDirectDrawX::ResetAllSurfaceDisplay() { for (const auto& pDDraw : DDrawVector) { @@ -3932,7 +3790,7 @@ inline void m_IDirectDrawX::ResetAllSurfaceDisplay() } } -inline void m_IDirectDrawX::ReleaseD3D9IndexBuffer() +void m_IDirectDrawX::ReleaseD3D9IndexBuffer() { // Release index buffer if (d3d9IndexBuffer) @@ -3947,11 +3805,9 @@ inline void m_IDirectDrawX::ReleaseD3D9IndexBuffer() } } -// Release all dd9 resources -inline void m_IDirectDrawX::ReleaseAllD9Resources(bool BackupData, bool ResetInterface) +void m_IDirectDrawX::ReleaseAllD9Resources(bool BackupData, bool ResetInterface) { - SetCriticalSection(); - SetPTCriticalSection(); + // To avoid threadlock, cannot have any critical sections in this function or any sub-functions // Remove render target and depth stencil surfaces if (d3d9Device && ResetInterface && (RenderTargetSurface || DepthStencilSurface)) @@ -3968,6 +3824,7 @@ inline void m_IDirectDrawX::ReleaseAllD9Resources(bool BackupData, bool ResetInt } for (const auto& pSurface : pDDraw->ReleasedSurfaceList) { + pSurface->ClearDdraw(); pSurface->DeleteMe(); } pDDraw->ReleasedSurfaceList.clear(); @@ -4081,18 +3938,13 @@ inline void m_IDirectDrawX::ReleaseAllD9Resources(bool BackupData, bool ResetInt } gammaPixelShader = nullptr; } - - ReleasePTCriticalSection(); - ReleaseCriticalSection(); } -// Release d3d9 device void m_IDirectDrawX::ReleaseD9Device() { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + // To avoid threadlock, cannot have any critical sections in this function or any sub-functions - SetCriticalSection(); - SetPTCriticalSection(); + Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; if (d3d9Device) { @@ -4104,12 +3956,8 @@ void m_IDirectDrawX::ReleaseD9Device() } d3d9Device = nullptr; } - - ReleasePTCriticalSection(); - ReleaseCriticalSection(); } -// Release d3d9 object void m_IDirectDrawX::ReleaseD9Object() { if (d3d9Object) @@ -4127,7 +3975,7 @@ HRESULT m_IDirectDrawX::CreateColorControl(m_IDirectDrawColorControl** lplpColor { if (lplpColorControl) { - *lplpColorControl = CreateDirectDrawColorControl(nullptr, this); + *lplpColorControl = m_IDirectDrawColorControl::CreateDirectDrawColorControl(nullptr, this); return DD_OK; } @@ -4163,7 +4011,7 @@ HRESULT m_IDirectDrawX::CreateGammaControl(m_IDirectDrawGammaControl** lplpGamma { if (lplpGammaControl) { - *lplpGammaControl = CreateDirectDrawGammaControl(nullptr, this); + *lplpGammaControl = m_IDirectDrawGammaControl::CreateDirectDrawGammaControl(nullptr, this); return DD_OK; } @@ -4195,7 +4043,63 @@ void m_IDirectDrawX::ClearGammaControl(m_IDirectDrawGammaControl* lpGammaControl GammaControlInterface = nullptr; } -// Add released surface wrapper +void m_IDirectDrawX::AddSurface(m_IDirectDrawSurfaceX* lpSurfaceX) +{ + if (!lpSurfaceX) + { + return; + } + + SurfaceList.push_back({ lpSurfaceX, 0, 0 }); +} + +void m_IDirectDrawX::ClearSurface(m_IDirectDrawSurfaceX* lpSurfaceX) +{ + // Remove attached surface from map + for (const auto& pDDraw : DDrawVector) + { + m_IDirect3DDeviceX* D3DDevice = pDDraw->D3DDeviceInterface; + if (D3DDevice) + { + D3DDevice->ClearSurface(lpSurfaceX); + } + if (lpSurfaceX == pDDraw->PrimarySurface) + { + pDDraw->PrimarySurface = nullptr; + ClipperHWnd = nullptr; + DisplayPixelFormat = {}; + } + if (lpSurfaceX == pDDraw->RenderTargetSurface) + { + pDDraw->SetRenderTargetSurface(nullptr); + } + if (lpSurfaceX == pDDraw->DepthStencilSurface) + { + pDDraw->SetDepthStencilSurface(nullptr); + } + + auto it = std::find_if(pDDraw->SurfaceList.begin(), pDDraw->SurfaceList.end(), + [lpSurfaceX](auto entry) { + return entry.Interface == lpSurfaceX; + }); + if (it != std::end(pDDraw->SurfaceList)) + { + DWORD RefCount = it->RefCount; + DWORD DxVersion = it->DxVersion; + pDDraw->SurfaceList.erase(it); // Erase from list before releasing + for (UINT x = 0; x < RefCount; x++) + { + Release(DxVersion); + } + } + + for (const auto& pSurface : pDDraw->SurfaceList) + { + pSurface.Interface->RemoveAttachedSurfaceFromMap(lpSurfaceX); + } + } +} + void m_IDirectDrawX::AddReleasedSurface(m_IDirectDrawSurfaceX* lpSurfaceX) { if (!lpSurfaceX) @@ -4206,7 +4110,6 @@ void m_IDirectDrawX::AddReleasedSurface(m_IDirectDrawSurfaceX* lpSurfaceX) ReleasedSurfaceList.push_back(lpSurfaceX); } -// Check if surface wrapper exists bool m_IDirectDrawX::DoesSurfaceExist(m_IDirectDrawSurfaceX* lpSurfaceX) { if (!lpSurfaceX) @@ -4222,7 +4125,73 @@ bool m_IDirectDrawX::DoesSurfaceExist(m_IDirectDrawSurfaceX* lpSurfaceX) return found; } -// Check if clipper wrapper exists +void m_IDirectDrawX::AddBaseClipper(m_IDirectDrawClipper* lpClipper) +{ + if (!lpClipper || DoesBaseClipperExist(lpClipper)) + { + return; + } + + ScopedDDCriticalSection ThreadLockDD; + + BaseClipperVector.push_back(lpClipper); +} + +void m_IDirectDrawX::ClearBaseClipper(m_IDirectDrawClipper* lpClipper) +{ + if (!lpClipper) + { + return; + } + + ScopedDDCriticalSection ThreadLockDD; + + BaseClipperVector.erase(std::remove(BaseClipperVector.begin(), BaseClipperVector.end(), lpClipper), BaseClipperVector.end()); +} + +bool m_IDirectDrawX::DoesBaseClipperExist(m_IDirectDrawClipper* lpClipper) +{ + if (!lpClipper) + { + return false; + } + + ScopedDDCriticalSection ThreadLockDD; + + const bool found = (std::find(BaseClipperVector.begin(), BaseClipperVector.end(), lpClipper) != std::end(BaseClipperVector)); + + return found; +} + +void m_IDirectDrawX::AddClipper(m_IDirectDrawClipper* lpClipper) +{ + if (!lpClipper) + { + return; + } + + ClipperList.push_back({ lpClipper, 0, 0 }); +} + +void m_IDirectDrawX::ClearClipper(m_IDirectDrawClipper* lpClipper) +{ + // Find and remove the clipper from the list + auto it = std::find_if(ClipperList.begin(), ClipperList.end(), + [lpClipper](auto entry) { + return entry.Interface == lpClipper; + }); + if (it != ClipperList.end()) + { + DWORD RefCount = it->RefCount; + DWORD DxVersion = it->DxVersion; + ClipperList.erase(it); // Erase from list before releasing + if (RefCount == 1) + { + Release(DxVersion); + } + } +} + bool m_IDirectDrawX::DoesClipperExist(m_IDirectDrawClipper* lpClipper) { if (!lpClipper) @@ -4244,7 +4213,59 @@ bool m_IDirectDrawX::DoesClipperExist(m_IDirectDrawClipper* lpClipper) return found; } -// Check if palette wrapper exists +HWND m_IDirectDrawX::GetClipperHWnd() +{ + return ClipperHWnd; +} + +HRESULT m_IDirectDrawX::SetClipperHWnd(HWND hWnd) +{ + if (Device.IsWindowed) + { + HWND OldClipperHWnd = ClipperHWnd; + if (!hWnd || IsWindow(hWnd)) + { + ClipperHWnd = hWnd; + } + if (!DisplayMode.hWnd && ClipperHWnd && ClipperHWnd != OldClipperHWnd) + { + ScopedDDCriticalSection ThreadLockDD; + + return CreateD9Device(__FUNCTION__); + } + } + return DD_OK; +} + +void m_IDirectDrawX::AddPalette(m_IDirectDrawPalette* lpPalette) +{ + if (!lpPalette) + { + return; + } + + PaletteList.push_back({ lpPalette, 0, 0 }); +} + +void m_IDirectDrawX::ClearPalette(m_IDirectDrawPalette* lpPalette) +{ + // Find and remove the palette from the list + auto it = std::find_if(PaletteList.begin(), PaletteList.end(), + [lpPalette](auto entry) { + return entry.Interface == lpPalette; + }); + if (it != PaletteList.end()) + { + DWORD RefCount = it->RefCount; + DWORD DxVersion = it->DxVersion; + PaletteList.erase(it); // Erase from list before releasing + if (RefCount == 1) + { + Release(DxVersion); + } + } +} + bool m_IDirectDrawX::DoesPaletteExist(m_IDirectDrawPalette* lpPalette) { if (!lpPalette) @@ -4294,28 +4315,6 @@ void m_IDirectDrawX::SetVsync() } } -HWND m_IDirectDrawX::GetClipperHWnd() -{ - return ClipperHWnd; -} - -HRESULT m_IDirectDrawX::SetClipperHWnd(HWND hWnd) -{ - if (Device.IsWindowed) - { - HWND OldClipperHWnd = ClipperHWnd; - if (!hWnd || IsWindow(hWnd)) - { - ClipperHWnd = hWnd; - } - if (!DisplayMode.hWnd && ClipperHWnd && ClipperHWnd != OldClipperHWnd) - { - return CreateD9Device(__FUNCTION__); - } - } - return DD_OK; -} - HRESULT m_IDirectDrawX::GetD9Gamma(DWORD dwFlags, LPDDGAMMARAMP lpRampData) { // Check for device interface @@ -4424,48 +4423,48 @@ HRESULT m_IDirectDrawX::SetD9Gamma(DWORD dwFlags, LPDDGAMMARAMP lpRampData) return DD_OK; } -static void BackupAndResetState(LPDIRECT3DDEVICE9 ProxyInterface, DRAWSTATEBACKUP& DrawStates, DWORD Width, DWORD Height) +void m_IDirectDrawX::BackupAndResetState(DRAWSTATEBACKUP& DrawStates, DWORD Width, DWORD Height) { // Sampler states - ProxyInterface->GetSamplerState(0, D3DSAMP_MAGFILTER, &DrawStates.ssMagFilter); - ProxyInterface->GetSamplerState(1, D3DSAMP_ADDRESSU, &DrawStates.ss1addressU); - ProxyInterface->GetSamplerState(1, D3DSAMP_ADDRESSV, &DrawStates.ss1addressV); - ProxyInterface->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + d3d9Device->GetSamplerState(0, D3DSAMP_MAGFILTER, &DrawStates.ssMagFilter); + d3d9Device->GetSamplerState(1, D3DSAMP_ADDRESSU, &DrawStates.ss1addressU); + d3d9Device->GetSamplerState(1, D3DSAMP_ADDRESSV, &DrawStates.ss1addressV); + d3d9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + d3d9Device->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + d3d9Device->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); // Texture states - ProxyInterface->GetTextureStageState(0, D3DTSS_COLOROP, &DrawStates.tsColorOP); - ProxyInterface->GetTextureStageState(0, D3DTSS_COLORARG1, &DrawStates.tsColorArg1); - ProxyInterface->GetTextureStageState(0, D3DTSS_COLORARG2, &DrawStates.tsColorArg2); - ProxyInterface->GetTextureStageState(0, D3DTSS_ALPHAOP, &DrawStates.tsAlphaOP); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - ProxyInterface->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + d3d9Device->GetTextureStageState(0, D3DTSS_COLOROP, &DrawStates.tsColorOP); + d3d9Device->GetTextureStageState(0, D3DTSS_COLORARG1, &DrawStates.tsColorArg1); + d3d9Device->GetTextureStageState(0, D3DTSS_COLORARG2, &DrawStates.tsColorArg2); + d3d9Device->GetTextureStageState(0, D3DTSS_ALPHAOP, &DrawStates.tsAlphaOP); + d3d9Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d9Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d9Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + d3d9Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); // Render states - ProxyInterface->GetRenderState(D3DRS_LIGHTING, &DrawStates.rsLighting); - ProxyInterface->GetRenderState(D3DRS_ALPHATESTENABLE, &DrawStates.rsAlphaTestEnable); - ProxyInterface->GetRenderState(D3DRS_ALPHABLENDENABLE, &DrawStates.rsAlphaBlendEnable); - ProxyInterface->GetRenderState(D3DRS_FOGENABLE, &DrawStates.rsFogEnable); - ProxyInterface->GetRenderState(D3DRS_ZENABLE, &DrawStates.rsZEnable); - ProxyInterface->GetRenderState(D3DRS_ZWRITEENABLE, &DrawStates.rsZWriteEnable); - ProxyInterface->GetRenderState(D3DRS_STENCILENABLE, &DrawStates.rsStencilEnable); - ProxyInterface->GetRenderState(D3DRS_CULLMODE, &DrawStates.rsCullMode); - ProxyInterface->GetRenderState(D3DRS_CLIPPING, &DrawStates.rsClipping); - ProxyInterface->SetRenderState(D3DRS_LIGHTING, FALSE); - ProxyInterface->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_FOGENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); - ProxyInterface->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_STENCILENABLE, FALSE); - ProxyInterface->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - ProxyInterface->SetRenderState(D3DRS_CLIPPING, FALSE); + d3d9Device->GetRenderState(D3DRS_LIGHTING, &DrawStates.rsLighting); + d3d9Device->GetRenderState(D3DRS_ALPHATESTENABLE, &DrawStates.rsAlphaTestEnable); + d3d9Device->GetRenderState(D3DRS_ALPHABLENDENABLE, &DrawStates.rsAlphaBlendEnable); + d3d9Device->GetRenderState(D3DRS_FOGENABLE, &DrawStates.rsFogEnable); + d3d9Device->GetRenderState(D3DRS_ZENABLE, &DrawStates.rsZEnable); + d3d9Device->GetRenderState(D3DRS_ZWRITEENABLE, &DrawStates.rsZWriteEnable); + d3d9Device->GetRenderState(D3DRS_STENCILENABLE, &DrawStates.rsStencilEnable); + d3d9Device->GetRenderState(D3DRS_CULLMODE, &DrawStates.rsCullMode); + d3d9Device->GetRenderState(D3DRS_CLIPPING, &DrawStates.rsClipping); + d3d9Device->SetRenderState(D3DRS_LIGHTING, FALSE); + d3d9Device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + d3d9Device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + d3d9Device->SetRenderState(D3DRS_FOGENABLE, FALSE); + d3d9Device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + d3d9Device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + d3d9Device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + d3d9Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + d3d9Device->SetRenderState(D3DRS_CLIPPING, FALSE); // Viewport - ProxyInterface->GetViewport(&DrawStates.ViewPort); + d3d9Device->GetViewport(&DrawStates.ViewPort); D3DVIEWPORT9 ViewPort = { 0, 0, presParams.BackBufferWidth, presParams.BackBufferHeight, 0.0f, 1.0f }; // Calculate width and height with original aspect ratio @@ -4507,54 +4506,54 @@ static void BackupAndResetState(LPDIRECT3DDEVICE9 ProxyInterface, DRAWSTATEBACKU } // Set the viewport with the calculated values - ProxyInterface->SetViewport(&ViewPort); + d3d9Device->SetViewport(&ViewPort); // Trasform - ProxyInterface->GetTransform(D3DTS_WORLD, &DrawStates.WorldMatrix); - ProxyInterface->GetTransform(D3DTS_VIEW, &DrawStates.ViewMatrix); - ProxyInterface->GetTransform(D3DTS_PROJECTION, &DrawStates.ProjectionMatrix); + d3d9Device->GetTransform(D3DTS_WORLD, &DrawStates.WorldMatrix); + d3d9Device->GetTransform(D3DTS_VIEW, &DrawStates.ViewMatrix); + d3d9Device->GetTransform(D3DTS_PROJECTION, &DrawStates.ProjectionMatrix); D3DMATRIX identityMatrix = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; - ProxyInterface->SetTransform(D3DTS_WORLD, &identityMatrix); - ProxyInterface->SetTransform(D3DTS_VIEW, &identityMatrix); - ProxyInterface->SetTransform(D3DTS_PROJECTION, &identityMatrix); + d3d9Device->SetTransform(D3DTS_WORLD, &identityMatrix); + d3d9Device->SetTransform(D3DTS_VIEW, &identityMatrix); + d3d9Device->SetTransform(D3DTS_PROJECTION, &identityMatrix); } -static void RestoreState(LPDIRECT3DDEVICE9 ProxyInterface, DRAWSTATEBACKUP& DrawStates) +void m_IDirectDrawX::RestoreState(DRAWSTATEBACKUP& DrawStates) { // Restore sampler states - ProxyInterface->SetSamplerState(0, D3DSAMP_MAGFILTER, DrawStates.ssMagFilter); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSU, DrawStates.ss1addressU); - ProxyInterface->SetSamplerState(1, D3DSAMP_ADDRESSV, DrawStates.ss1addressV); + d3d9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, DrawStates.ssMagFilter); + d3d9Device->SetSamplerState(1, D3DSAMP_ADDRESSU, DrawStates.ss1addressU); + d3d9Device->SetSamplerState(1, D3DSAMP_ADDRESSV, DrawStates.ss1addressV); // Restore texture states - ProxyInterface->SetTextureStageState(0, D3DTSS_COLOROP, DrawStates.tsColorOP); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG1, DrawStates.tsColorArg1); - ProxyInterface->SetTextureStageState(0, D3DTSS_COLORARG2, DrawStates.tsColorArg2); - ProxyInterface->SetTextureStageState(0, D3DTSS_ALPHAOP, DrawStates.tsAlphaOP); + d3d9Device->SetTextureStageState(0, D3DTSS_COLOROP, DrawStates.tsColorOP); + d3d9Device->SetTextureStageState(0, D3DTSS_COLORARG1, DrawStates.tsColorArg1); + d3d9Device->SetTextureStageState(0, D3DTSS_COLORARG2, DrawStates.tsColorArg2); + d3d9Device->SetTextureStageState(0, D3DTSS_ALPHAOP, DrawStates.tsAlphaOP); // Restore render states - ProxyInterface->SetRenderState(D3DRS_LIGHTING, DrawStates.rsLighting); - ProxyInterface->SetRenderState(D3DRS_ALPHATESTENABLE, DrawStates.rsAlphaTestEnable); - ProxyInterface->SetRenderState(D3DRS_ALPHABLENDENABLE, DrawStates.rsAlphaBlendEnable); - ProxyInterface->SetRenderState(D3DRS_FOGENABLE, DrawStates.rsFogEnable); - ProxyInterface->SetRenderState(D3DRS_ZENABLE, DrawStates.rsZEnable); - ProxyInterface->SetRenderState(D3DRS_ZWRITEENABLE, DrawStates.rsZWriteEnable); - ProxyInterface->SetRenderState(D3DRS_STENCILENABLE, DrawStates.rsStencilEnable); - ProxyInterface->SetRenderState(D3DRS_CULLMODE, DrawStates.rsCullMode); - ProxyInterface->SetRenderState(D3DRS_CLIPPING, DrawStates.rsClipping); + d3d9Device->SetRenderState(D3DRS_LIGHTING, DrawStates.rsLighting); + d3d9Device->SetRenderState(D3DRS_ALPHATESTENABLE, DrawStates.rsAlphaTestEnable); + d3d9Device->SetRenderState(D3DRS_ALPHABLENDENABLE, DrawStates.rsAlphaBlendEnable); + d3d9Device->SetRenderState(D3DRS_FOGENABLE, DrawStates.rsFogEnable); + d3d9Device->SetRenderState(D3DRS_ZENABLE, DrawStates.rsZEnable); + d3d9Device->SetRenderState(D3DRS_ZWRITEENABLE, DrawStates.rsZWriteEnable); + d3d9Device->SetRenderState(D3DRS_STENCILENABLE, DrawStates.rsStencilEnable); + d3d9Device->SetRenderState(D3DRS_CULLMODE, DrawStates.rsCullMode); + d3d9Device->SetRenderState(D3DRS_CLIPPING, DrawStates.rsClipping); // Reset viewport - ProxyInterface->SetViewport(&DrawStates.ViewPort); + d3d9Device->SetViewport(&DrawStates.ViewPort); // Reset trasform - ProxyInterface->SetTransform(D3DTS_WORLD, &DrawStates.WorldMatrix); - ProxyInterface->SetTransform(D3DTS_VIEW, &DrawStates.ViewMatrix); - ProxyInterface->SetTransform(D3DTS_PROJECTION, &DrawStates.ProjectionMatrix); + d3d9Device->SetTransform(D3DTS_WORLD, &DrawStates.WorldMatrix); + d3d9Device->SetTransform(D3DTS_VIEW, &DrawStates.ViewMatrix); + d3d9Device->SetTransform(D3DTS_PROJECTION, &DrawStates.ProjectionMatrix); } HRESULT m_IDirectDrawX::DrawPrimarySurface(LPDIRECT3DTEXTURE9 pDisplayTexture) @@ -4588,7 +4587,7 @@ HRESULT m_IDirectDrawX::DrawPrimarySurface(LPDIRECT3DTEXTURE9 pDisplayTexture) // Backup current states DRAWSTATEBACKUP DrawStates; - BackupAndResetState(d3d9Device, DrawStates, Desc.Width, Desc.Height); + BackupAndResetState(DrawStates, Desc.Width, Desc.Height); // Set texture d3d9Device->SetTexture(0, pDisplayTexture); @@ -4662,7 +4661,7 @@ HRESULT m_IDirectDrawX::DrawPrimarySurface(LPDIRECT3DTEXTURE9 pDisplayTexture) d3d9Device->SetPixelShader(nullptr); // Restore states - RestoreState(d3d9Device, DrawStates); + RestoreState(DrawStates); return hr; } @@ -4686,12 +4685,12 @@ HRESULT m_IDirectDrawX::CopyPrimarySurface(LPDIRECT3DSURFACE9 pDestBuffer) } // Copy render target to backbuffer - IDirect3DSurface9* pBackBuffer = nullptr; + ComPtr pBackBuffer; if (!pDestBuffer) { - if (SUCCEEDED(d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) + if (SUCCEEDED(d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, pBackBuffer.GetAddressOf()))) { - pDestBuffer = pBackBuffer; + pDestBuffer = pBackBuffer.Get(); } } @@ -4739,8 +4738,6 @@ HRESULT m_IDirectDrawX::CopyPrimarySurface(LPDIRECT3DSURFACE9 pDestBuffer) // If copying to back buffer if (pBackBuffer) { - pBackBuffer->Release(); - if (SUCCEEDED(hr)) { PrimarySurface->ClearDirtyFlags(); @@ -4752,6 +4749,8 @@ HRESULT m_IDirectDrawX::CopyPrimarySurface(LPDIRECT3DSURFACE9 pDestBuffer) HRESULT m_IDirectDrawX::PresentScene(RECT* pRect) { + ScopedDDCriticalSection ThreadLockDD; + HRESULT hr = DDERR_GENERIC; if (IsUsingThreadPresent()) @@ -4794,8 +4793,8 @@ HRESULT m_IDirectDrawX::PresentScene(RECT* pRect) { if (IsGammaSet && GammaControlInterface) { - IDirect3DSurface9* pBackBuffer = nullptr; - if (SUCCEEDED(d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) + ComPtr pBackBuffer; + if (SUCCEEDED(d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, pBackBuffer.GetAddressOf()))) { // Create intermediate texture for shader input if (!ScreenCopyTexture) @@ -4805,23 +4804,18 @@ HRESULT m_IDirectDrawX::PresentScene(RECT* pRect) if (FAILED(d3d9Device->CreateTexture(Desc.Width, Desc.Height, 1, D3DUSAGE_RENDERTARGET, Desc.Format, D3DPOOL_DEFAULT, &ScreenCopyTexture, nullptr))) { Logging::Log() << __FUNCTION__ << " Error: Failed to create screen copy texture!"; - pBackBuffer->Release(); } } // Copy back buffer to texture surface and draw surface to screen if (ScreenCopyTexture) { - IDirect3DSurface9* pCopySurface = nullptr; - if (SUCCEEDED(ScreenCopyTexture->GetSurfaceLevel(0, &pCopySurface))) + ComPtr pCopySurface; + if (SUCCEEDED(ScreenCopyTexture->GetSurfaceLevel(0, pCopySurface.GetAddressOf()))) { - hr = CopyPrimarySurface(pCopySurface); - pCopySurface->Release(); + hr = CopyPrimarySurface(pCopySurface.Get()); } - // Release back buffer - pBackBuffer->Release(); - // Draw surface hr = DrawPrimarySurface(ScreenCopyTexture); } @@ -4858,13 +4852,13 @@ bool m_IDirectDrawX::IsUsingThreadPresent() return (PresentThread.IsInitialized && ExclusiveMode && !RenderTargetSurface && !IsPrimaryRenderTarget()); } -// Present Thread: Wait for the event -DWORD WINAPI PresentThreadFunction(LPVOID) +DWORD WINAPI m_IDirectDrawX::PresentThreadFunction(LPVOID) { LOG_LIMIT(100, __FUNCTION__ << " Creating thread!"); - PresentThread.EnableThreadFlag = true; - while (PresentThread.EnableThreadFlag) + ScopedFlagSet AutoSet(PresentThread.IsInitialized); + + while (!PresentThread.ExitFlag) { // Check how long since the last successful present LARGE_INTEGER ClickTime = {}; @@ -4873,15 +4867,21 @@ DWORD WINAPI PresentThreadFunction(LPVOID) DWORD timeout = (DWORD)(Counter.PerFrameMS - DeltaPresentMS < 0.0 ? 0.0 : Counter.PerFrameMS - DeltaPresentMS); - WaitForSingleObject(PresentThread.workerEvent, timeout); - ResetEvent(PresentThread.workerEvent); - - if (!PresentThread.EnableThreadFlag) + // Wait for timeout or for event trigger (check exit flag before and after wait) + if (PresentThread.ExitFlag || WaitForSingleObject(PresentThread.exitEvent, timeout) == WAIT_OBJECT_0 || PresentThread.ExitFlag) { break; } - SetPTCriticalSection(); + // Attempt to get thread lock + while (!TryDDThreadLock()) + { + if (WaitForSingleObject(PresentThread.exitEvent, 0) == WAIT_OBJECT_0) + { + break; + } + Utils::BusyWaitYield((DWORD)-1); + } if (d3d9Device) { @@ -4898,9 +4898,6 @@ DWORD WINAPI PresentThreadFunction(LPVOID) } if (pDDraw && pDDraw->IsUsingThreadPresent() && pPrimarySurface && pPrimarySurface->GetD3d9Texture()) { - pPrimarySurface->SetLockCriticalSection(); - pPrimarySurface->SetSurfaceCriticalSection(); - // Begin scene d3d9Device->BeginScene(); @@ -4915,13 +4912,11 @@ DWORD WINAPI PresentThreadFunction(LPVOID) // Store last successful present time QueryPerformanceCounter(&PresentThread.LastPresentTime); - - pPrimarySurface->ReleaseSurfaceCriticalSection(); - pPrimarySurface->ReleaseLockCriticalSection(); } } - ReleasePTCriticalSection(); + // Make sure to release the thread lock at the end + dd_ReleaseDDThreadLock(); } LOG_LIMIT(100, __FUNCTION__ << " Closing thread!"); @@ -4929,7 +4924,6 @@ DWORD WINAPI PresentThreadFunction(LPVOID) return S_OK; } -// Do d3d9 Present HRESULT m_IDirectDrawX::Present(RECT* pSourceRect, RECT* pDestRect) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; @@ -4958,12 +4952,6 @@ HRESULT m_IDirectDrawX::Present(RECT* pSourceRect, RECT* pDestRect) } } - // Check for device interface - if (FAILED(CheckInterface(__FUNCTION__, true))) - { - return DDERR_GENERIC; - } - // Use WaitForVerticalBlank for wait timer if (EnableWaitVsync && !Config.EnableVSync && !Config.ForceVsyncMode) { @@ -5031,7 +5019,11 @@ HRESULT m_IDirectDrawX::Present(RECT* pSourceRect, RECT* pDestRect) return DD_OK; } -bool CheckDirectDrawXInterface(void* pInterface) +// ****************************** +// External static functions +// ****************************** + +bool m_IDirectDrawX::CheckDirectDrawXInterface(void* pInterface) { for (auto& entry : DDrawVector) { @@ -5043,7 +5035,7 @@ bool CheckDirectDrawXInterface(void* pInterface) return false; } -DWORD GetDDrawBitsPixel(HWND hWnd) +DWORD m_IDirectDrawX::GetDDrawBitsPixel(HWND hWnd) { if (hWnd) { @@ -5065,7 +5057,7 @@ DWORD GetDDrawBitsPixel(HWND hWnd) return 0; } -DWORD GetDDrawWidth() +DWORD m_IDirectDrawX::GetDDrawWidth() { if (DDrawVector.size() && DisplayMode.hWnd) { @@ -5074,7 +5066,7 @@ DWORD GetDDrawWidth() return 0; } -DWORD GetDDrawHeight() +DWORD m_IDirectDrawX::GetDDrawHeight() { if (DDrawVector.size() && DisplayMode.hWnd) { diff --git a/ddraw/IDirectDrawX.h b/ddraw/IDirectDrawX.h index b6014a80..1e51a696 100644 --- a/ddraw/IDirectDrawX.h +++ b/ddraw/IDirectDrawX.h @@ -11,6 +11,14 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject ULONG RefCount4 = 0; ULONG RefCount7 = 0; + // Store version wrappers + m_IDirectDraw* WrapperInterface = nullptr; + m_IDirectDraw2* WrapperInterface2 = nullptr; + m_IDirectDraw3* WrapperInterface3 = nullptr; + m_IDirectDraw4* WrapperInterface4 = nullptr; + m_IDirectDraw7* WrapperInterface7 = nullptr; + + // Cached DirectDraw flags const bool IsUsingEx = false; bool Using3D = false; @@ -18,13 +26,6 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject HHOOK g_hook = nullptr; HWND chWnd = nullptr; - // Store ddraw version wrappers - m_IDirectDraw *WrapperInterface = nullptr; - m_IDirectDraw2 *WrapperInterface2 = nullptr; - m_IDirectDraw3 *WrapperInterface3 = nullptr; - m_IDirectDraw4 *WrapperInterface4 = nullptr; - m_IDirectDraw7 *WrapperInterface7 = nullptr; - // Store primary surface m_IDirectDrawSurfaceX *PrimarySurface = nullptr; m_IDirectDrawSurfaceX *RenderTargetSurface = nullptr; @@ -68,6 +69,27 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject m_IDirect3DX *D3DInterface = nullptr; m_IDirect3DDeviceX *D3DDeviceInterface = nullptr; + // Helper functions + HRESULT CheckInterface(char* FunctionName, bool CheckD3DDevice); + HRESULT CreateD9Object(); + void BackupAndResetState(DRAWSTATEBACKUP& DrawStates, DWORD Width, DWORD Height); + void RestoreState(DRAWSTATEBACKUP& DrawStates); + HRESULT CopyPrimarySurface(LPDIRECT3DSURFACE9 pDestBuffer); + HRESULT DrawPrimarySurface(LPDIRECT3DTEXTURE9 pDisplayTexture); + static DWORD WINAPI PresentThreadFunction(LPVOID); + HRESULT Present(RECT* pSourceRect, RECT* pDestRect); + void RestoreD3DDeviceState(); + void Clear3DFlagForAllSurfaces(); + void ResetAllSurfaceDisplay(); + void ReleaseD3D9IndexBuffer(); + void ReleaseAllD9Resources(bool BackupData, bool ResetInterface); + void ReleaseD9Device(); + void ReleaseD9Object(); + + // Gamma functions + LPDIRECT3DPIXELSHADER9 GetGammaPixelShader(); + HRESULT SetBrightnessLevel(D3DGAMMARAMP& RampData); + // Wrapper interface functions inline REFIID GetWrapperType(DWORD DirectXVersion) { @@ -91,21 +113,6 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject inline IDirectDraw4 *GetProxyInterfaceV4() { return (IDirectDraw4 *)ProxyInterface; } inline IDirectDraw7 *GetProxyInterfaceV7() { return ProxyInterface; } - // Direct3D9 interface functions - HRESULT CheckInterface(char *FunctionName, bool CheckD3DDevice); - HRESULT CreateD9Object(); - void RestoreD3DDeviceState(); - void Clear3DFlagForAllSurfaces(); - void ResetAllSurfaceDisplay(); - void ReleaseD3D9IndexBuffer(); - void ReleaseAllD9Resources(bool BackupData, bool ResetInterface); - void ReleaseD9Device(); - void ReleaseD9Object(); - - // Gamma functions - LPDIRECT3DPIXELSHADER9 GetGammaPixelShader(); - HRESULT SetBrightnessLevel(D3DGAMMARAMP& RampData); - // Interface initialization functions void InitInterface(DWORD DirectXVersion); void ReleaseInterface(); @@ -113,7 +120,7 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject public: m_IDirectDrawX(IDirectDraw7 *aOriginal, DWORD DirectXVersion) : ProxyInterface(aOriginal) { - ProxyDirectXVersion = GetGUIDVersion(ConvertREFIID(GetWrapperType(DirectXVersion))); + ProxyDirectXVersion = GetGUIDVersion(GetWrapperType(DirectXVersion)); if (ProxyDirectXVersion != DirectXVersion) { @@ -198,14 +205,14 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject ULONG Release(DWORD DirectXVersion); // Direct3D interfaces - inline m_IDirect3DX** GetCurrentD3D() { return &D3DInterface; } + m_IDirect3DX** GetCurrentD3D() { return &D3DInterface; } void SetD3DDevice(m_IDirect3DDeviceX* lpD3DDevice); - inline m_IDirect3DDeviceX** GetCurrentD3DDevice() { return &D3DDeviceInterface; } + m_IDirect3DDeviceX** GetCurrentD3DDevice() { return &D3DDeviceInterface; } void ClearD3DDevice(m_IDirect3DDeviceX* lpD3DDevice); - inline bool IsCreatedEx() const { return IsUsingEx; } - inline void Enable3D() { Using3D = true; } - inline bool IsUsing3D() const { return Using3D; } - inline bool IsPrimaryRenderTarget() { return PrimarySurface ? PrimarySurface->IsRenderTarget() : false; } + bool IsCreatedEx() const { return IsUsingEx; } + void Enable3D() { Using3D = true; } + bool IsUsing3D() const { return Using3D; } + bool IsPrimaryRenderTarget() { return PrimarySurface ? PrimarySurface->IsRenderTarget() : false; } bool IsInScene(); // Direct3D9 interfaces @@ -223,6 +230,7 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject HRESULT TestD3D9CooperativeLevel(); // Device information functions + static m_IDirectDrawX* GetDirectDrawInterface(); HWND GetHwnd(); DWORD GetHwndThreadID(); HDC GetDC(); @@ -241,14 +249,19 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject void ClearRenderTarget(); void ReSetRenderTarget(); void SetCurrentRenderTarget(); - HRESULT SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface); + HRESULT SetRenderTargetSurface(m_IDirectDrawSurfaceX* lpSurface, bool ShouldCheckInterface = true); m_IDirectDrawSurfaceX *GetDepthStencilSurface() { return DepthStencilSurface; } - HRESULT SetDepthStencilSurface(m_IDirectDrawSurfaceX* lpSurface); + HRESULT SetDepthStencilSurface(m_IDirectDrawSurfaceX* lpSurface, bool ShouldCheckInterface = true); - // Clipper vector functions + // Clipper functions + static void AddBaseClipper(m_IDirectDrawClipper* lpClipper); + static void ClearBaseClipper(m_IDirectDrawClipper* lpClipper); + static bool DoesBaseClipperExist(m_IDirectDrawClipper* lpClipper); void AddClipper(m_IDirectDrawClipper* lpClipper); void ClearClipper(m_IDirectDrawClipper* lpClipper); bool DoesClipperExist(m_IDirectDrawClipper* lpClipper); + HWND GetClipperHWnd(); + HRESULT SetClipperHWnd(HWND hWnd); // Palette vector functions void AddPalette(m_IDirectDrawPalette* lpPalette); @@ -260,24 +273,25 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject void ClearVertexBuffer(m_IDirect3DVertexBufferX* lpVertexBuffer); // Color and gamma control - inline m_IDirectDrawColorControl* GetColorControlInterface() { return ColorControlInterface; } + m_IDirectDrawColorControl* GetColorControlInterface() { return ColorControlInterface; } HRESULT CreateColorControl(m_IDirectDrawColorControl** lplpColorControl); void SetColorControl(m_IDirectDrawColorControl* lpColorControl); void ClearColorControl(m_IDirectDrawColorControl* lpColorControl); - inline m_IDirectDrawGammaControl* GetGammaControlInterface() { return GammaControlInterface; } + m_IDirectDrawGammaControl* GetGammaControlInterface() { return GammaControlInterface; } HRESULT CreateGammaControl(m_IDirectDrawGammaControl** lplpGammaControl); void SetGammaControl(m_IDirectDrawGammaControl* lpGammaControl); void ClearGammaControl(m_IDirectDrawGammaControl* lpGammaControl); // Begin & end scene void SetVsync(); - HWND GetClipperHWnd(); - HRESULT SetClipperHWnd(HWND hWnd); HRESULT GetD9Gamma(DWORD dwFlags, LPDDGAMMARAMP lpRampData); HRESULT SetD9Gamma(DWORD dwFlags, LPDDGAMMARAMP lpRampData); - HRESULT CopyPrimarySurface(LPDIRECT3DSURFACE9 pDestBuffer); - HRESULT DrawPrimarySurface(LPDIRECT3DTEXTURE9 pDisplayTexture); bool IsUsingThreadPresent(); HRESULT PresentScene(RECT* pRect); - HRESULT Present(RECT* pSourceRect, RECT* pDestRect); + + // External static functions + static bool CheckDirectDrawXInterface(void* pInterface); + static DWORD GetDDrawBitsPixel(HWND hWnd); + static DWORD GetDDrawWidth(); + static DWORD GetDDrawHeight(); }; diff --git a/ddraw/InterfaceQuery.cpp b/ddraw/InterfaceQuery.cpp index a410a9ef..d2738d00 100644 --- a/ddraw/InterfaceQuery.cpp +++ b/ddraw/InterfaceQuery.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -38,60 +38,6 @@ REFIID DdrawWrapper::ReplaceIIDUnknown(REFIID riid, REFIID guid) return (riid == IID_IUnknown) ? guid : riid; } -REFCLSID DdrawWrapper::ConvertREFCLSID(REFCLSID rclsid) -{ - if (Config.ConvertToDirectDraw7 && rclsid == CLSID_DirectDraw) - { - return CLSID_DirectDraw7; - } - - return rclsid; -} - -REFIID DdrawWrapper::ConvertREFIID(REFIID riid) -{ - if (Config.ConvertToDirectDraw7) - { - if (riid == IID_IDirectDraw || riid == IID_IDirectDraw2 || riid == IID_IDirectDraw3 || riid == IID_IDirectDraw4) - { - return IID_IDirectDraw7; - } - else if (riid == IID_IDirectDrawSurface || riid == IID_IDirectDrawSurface2 || riid == IID_IDirectDrawSurface3 || riid == IID_IDirectDrawSurface4) - { - return IID_IDirectDrawSurface7; - } - } - if (Config.ConvertToDirect3D7) - { - if (riid == IID_IDirect3D || riid == IID_IDirect3D2 || riid == IID_IDirect3D3) - { - return IID_IDirect3D7; - } - else if (riid == IID_IDirect3DDevice || riid == IID_IDirect3DDevice2 || riid == IID_IDirect3DDevice3) - { - return IID_IDirect3DDevice7; - } - else if (riid == IID_IDirect3DMaterial || riid == IID_IDirect3DMaterial2) - { - return IID_IDirect3DMaterial3; - } - else if (riid == IID_IDirect3DTexture) - { - return IID_IDirect3DTexture2; - } - else if (riid == IID_IDirect3DViewport || riid == IID_IDirect3DViewport2) - { - return IID_IDirect3DViewport3; - } - else if (riid == IID_IDirect3DVertexBuffer) - { - return IID_IDirect3DVertexBuffer7; - } - } - - return riid; -} - HRESULT DdrawWrapper::ProxyQueryInterface(LPVOID ProxyInterface, REFIID riid, LPVOID * ppvObj, REFIID WrapperID) { Logging::LogDebug() << __FUNCTION__ << " Query for " << riid << " from " << WrapperID; @@ -116,7 +62,7 @@ HRESULT DdrawWrapper::ProxyQueryInterface(LPVOID ProxyInterface, REFIID riid, LP return E_NOINTERFACE; } - HRESULT hr = ((IUnknown*)ProxyInterface)->QueryInterface(ConvertREFIID(riid), ppvObj); + HRESULT hr = ((IUnknown*)ProxyInterface)->QueryInterface(riid, ppvObj); if (SUCCEEDED(hr)) { diff --git a/ddraw/License.txt b/ddraw/License.txt index 53f73bd0..9cdb9d78 100644 --- a/ddraw/License.txt +++ b/ddraw/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3D.cpp b/ddraw/Versions/IDirect3D.cpp index ce5a96e7..ae71cab7 100644 --- a/ddraw/Versions/IDirect3D.cpp +++ b/ddraw/Versions/IDirect3D.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3D2.cpp b/ddraw/Versions/IDirect3D2.cpp index 7a85abd7..06fdcc15 100644 --- a/ddraw/Versions/IDirect3D2.cpp +++ b/ddraw/Versions/IDirect3D2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3D3.cpp b/ddraw/Versions/IDirect3D3.cpp index 015a0150..26bf850e 100644 --- a/ddraw/Versions/IDirect3D3.cpp +++ b/ddraw/Versions/IDirect3D3.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3D7.cpp b/ddraw/Versions/IDirect3D7.cpp index 5e8ce89d..7368b88b 100644 --- a/ddraw/Versions/IDirect3D7.cpp +++ b/ddraw/Versions/IDirect3D7.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DDevice.cpp b/ddraw/Versions/IDirect3DDevice.cpp index c471f61b..6a01a65f 100644 --- a/ddraw/Versions/IDirect3DDevice.cpp +++ b/ddraw/Versions/IDirect3DDevice.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -93,7 +93,7 @@ HRESULT m_IDirect3DDevice::GetStats(LPD3DSTATS a) { return DDERR_INVALIDOBJECT; } - return ProxyInterface->GetStats(a, DirectXVersion); + return ProxyInterface->GetStats(a); } HRESULT m_IDirect3DDevice::Execute(LPDIRECT3DEXECUTEBUFFER a, LPDIRECT3DVIEWPORT b, DWORD c) diff --git a/ddraw/Versions/IDirect3DDevice2.cpp b/ddraw/Versions/IDirect3DDevice2.cpp index 24bc63c3..13056af8 100644 --- a/ddraw/Versions/IDirect3DDevice2.cpp +++ b/ddraw/Versions/IDirect3DDevice2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -71,7 +71,7 @@ HRESULT m_IDirect3DDevice2::GetStats(LPD3DSTATS a) { return DDERR_INVALIDOBJECT; } - return ProxyInterface->GetStats(a, DirectXVersion); + return ProxyInterface->GetStats(a); } HRESULT m_IDirect3DDevice2::AddViewport(LPDIRECT3DVIEWPORT2 a) diff --git a/ddraw/Versions/IDirect3DDevice3.cpp b/ddraw/Versions/IDirect3DDevice3.cpp index 41aa128a..138dde0e 100644 --- a/ddraw/Versions/IDirect3DDevice3.cpp +++ b/ddraw/Versions/IDirect3DDevice3.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -62,7 +62,7 @@ HRESULT m_IDirect3DDevice3::GetStats(LPD3DSTATS a) { return DDERR_INVALIDOBJECT; } - return ProxyInterface->GetStats(a, DirectXVersion); + return ProxyInterface->GetStats(a); } HRESULT m_IDirect3DDevice3::AddViewport(LPDIRECT3DVIEWPORT3 a) diff --git a/ddraw/Versions/IDirect3DDevice7.cpp b/ddraw/Versions/IDirect3DDevice7.cpp index 7c4fcb5f..81f5745c 100644 --- a/ddraw/Versions/IDirect3DDevice7.cpp +++ b/ddraw/Versions/IDirect3DDevice7.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DMaterial.cpp b/ddraw/Versions/IDirect3DMaterial.cpp index 95736a29..7133e89a 100644 --- a/ddraw/Versions/IDirect3DMaterial.cpp +++ b/ddraw/Versions/IDirect3DMaterial.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DMaterial2.cpp b/ddraw/Versions/IDirect3DMaterial2.cpp index a9c00d3e..86b115e2 100644 --- a/ddraw/Versions/IDirect3DMaterial2.cpp +++ b/ddraw/Versions/IDirect3DMaterial2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DMaterial3.cpp b/ddraw/Versions/IDirect3DMaterial3.cpp index 1ecfdcab..887dc183 100644 --- a/ddraw/Versions/IDirect3DMaterial3.cpp +++ b/ddraw/Versions/IDirect3DMaterial3.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DTexture.cpp b/ddraw/Versions/IDirect3DTexture.cpp index 0cc28827..3d0659ff 100644 --- a/ddraw/Versions/IDirect3DTexture.cpp +++ b/ddraw/Versions/IDirect3DTexture.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DTexture2.cpp b/ddraw/Versions/IDirect3DTexture2.cpp index 5f2428d1..1a3bb34c 100644 --- a/ddraw/Versions/IDirect3DTexture2.cpp +++ b/ddraw/Versions/IDirect3DTexture2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DVertexBuffer.cpp b/ddraw/Versions/IDirect3DVertexBuffer.cpp index 71fdeca4..24105405 100644 --- a/ddraw/Versions/IDirect3DVertexBuffer.cpp +++ b/ddraw/Versions/IDirect3DVertexBuffer.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DVertexBuffer7.cpp b/ddraw/Versions/IDirect3DVertexBuffer7.cpp index 10805b0c..6f298968 100644 --- a/ddraw/Versions/IDirect3DVertexBuffer7.cpp +++ b/ddraw/Versions/IDirect3DVertexBuffer7.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DViewport.cpp b/ddraw/Versions/IDirect3DViewport.cpp index dd3df59f..740cf051 100644 --- a/ddraw/Versions/IDirect3DViewport.cpp +++ b/ddraw/Versions/IDirect3DViewport.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DViewport2.cpp b/ddraw/Versions/IDirect3DViewport2.cpp index 187df307..1156a85c 100644 --- a/ddraw/Versions/IDirect3DViewport2.cpp +++ b/ddraw/Versions/IDirect3DViewport2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirect3DViewport3.cpp b/ddraw/Versions/IDirect3DViewport3.cpp index f68cf7a5..e6dc7199 100644 --- a/ddraw/Versions/IDirect3DViewport3.cpp +++ b/ddraw/Versions/IDirect3DViewport3.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDraw.cpp b/ddraw/Versions/IDirectDraw.cpp index b5c7915b..9f49c35f 100644 --- a/ddraw/Versions/IDirectDraw.cpp +++ b/ddraw/Versions/IDirectDraw.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDraw2.cpp b/ddraw/Versions/IDirectDraw2.cpp index b5efb37f..458cd9c0 100644 --- a/ddraw/Versions/IDirectDraw2.cpp +++ b/ddraw/Versions/IDirectDraw2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDraw3.cpp b/ddraw/Versions/IDirectDraw3.cpp index ff95e0b9..f3833fe0 100644 --- a/ddraw/Versions/IDirectDraw3.cpp +++ b/ddraw/Versions/IDirectDraw3.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDraw4.cpp b/ddraw/Versions/IDirectDraw4.cpp index 602005ae..1c0c6379 100644 --- a/ddraw/Versions/IDirectDraw4.cpp +++ b/ddraw/Versions/IDirectDraw4.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDraw7.cpp b/ddraw/Versions/IDirectDraw7.cpp index acf6c9e5..4a1284ca 100644 --- a/ddraw/Versions/IDirectDraw7.cpp +++ b/ddraw/Versions/IDirectDraw7.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDrawSurface.cpp b/ddraw/Versions/IDirectDrawSurface.cpp index 20f86ee8..07a6383f 100644 --- a/ddraw/Versions/IDirectDrawSurface.cpp +++ b/ddraw/Versions/IDirectDrawSurface.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDrawSurface2.cpp b/ddraw/Versions/IDirectDrawSurface2.cpp index 51359f09..d2fc77a0 100644 --- a/ddraw/Versions/IDirectDrawSurface2.cpp +++ b/ddraw/Versions/IDirectDrawSurface2.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDrawSurface3.cpp b/ddraw/Versions/IDirectDrawSurface3.cpp index d8614224..9e38049b 100644 --- a/ddraw/Versions/IDirectDrawSurface3.cpp +++ b/ddraw/Versions/IDirectDrawSurface3.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDrawSurface4.cpp b/ddraw/Versions/IDirectDrawSurface4.cpp index 2969acff..2b8dc0db 100644 --- a/ddraw/Versions/IDirectDrawSurface4.cpp +++ b/ddraw/Versions/IDirectDrawSurface4.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/IDirectDrawSurface7.cpp b/ddraw/Versions/IDirectDrawSurface7.cpp index b31150fb..90402050 100644 --- a/ddraw/Versions/IDirectDrawSurface7.cpp +++ b/ddraw/Versions/IDirectDrawSurface7.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/Versions/License.txt b/ddraw/Versions/License.txt index 53f73bd0..9cdb9d78 100644 --- a/ddraw/Versions/License.txt +++ b/ddraw/Versions/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/ddraw/ddraw.cpp b/ddraw/ddraw.cpp index ff99a9bf..1d60f1b9 100644 --- a/ddraw/ddraw.cpp +++ b/ddraw/ddraw.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. @@ -21,7 +21,6 @@ */ #include "ddraw.h" -#include "ddrawExternal.h" #include "Dllmain\Dllmain.h" #include "IClassFactory\IClassFactory.h" #include "d3d9\d3d9External.h" @@ -31,18 +30,6 @@ AddressLookupTableDdraw ProxyAddressLookupTable = AddressLookupTableDdraw(); -// Store a list of clipper -std::vector BaseClipperVector; - -CRITICAL_SECTION ddcs; -bool IsInitialized = false; - -struct ENUMMONITORS -{ - LPSTR lpName; - HMONITOR hm; -}; - namespace DdrawWrapper { VISIT_PROCS_DDRAW(INITIALIZE_OUT_WRAPPED_PROC); @@ -52,95 +39,23 @@ namespace DdrawWrapper using namespace DdrawWrapper; -void InitDDraw() -{ - if (!IsInitialized) - { - InitializeCriticalSection(&ddcs); - IsInitialized = true; - } +namespace { + bool IsInitialized = false; + CRITICAL_SECTION ddcs; - // Hook other gdi32 and user32 APIs - static bool RunOnce = true; - if (RunOnce) + struct ENUMMONITORS { - Logging::Log() << "Installing GDI & User32 hooks"; - using namespace GdiWrapper; - if (!GetModuleHandleA("gdi32.dll")) LoadLibrary("gdi32.dll"); - if (!GetModuleHandleA("user32.dll")) LoadLibrary("user32.dll"); - HMODULE gdi32 = GetModuleHandleA("gdi32.dll"); - HMODULE user32 = GetModuleHandleA("user32.dll"); - HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); - if (gdi32) - { - GetDeviceCaps_out = (FARPROC)Hook::HotPatch(GetProcAddress(gdi32, "GetDeviceCaps"), "GetDeviceCaps", gdi_GetDeviceCaps); - } - if (user32) - { - CreateWindowExA_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "CreateWindowExA"), "CreateWindowExA", user_CreateWindowExA); - CreateWindowExW_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "CreateWindowExW"), "CreateWindowExW", user_CreateWindowExW); - DestroyWindow_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "DestroyWindow"), "DestroyWindow", user_DestroyWindow); - GetSystemMetrics_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "GetSystemMetrics"), "GetSystemMetrics", user_GetSystemMetrics); - //GetWindowLongA_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "GetWindowLongA"), "GetWindowLongA", user_GetWindowLongA); - //GetWindowLongW_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "GetWindowLongW"), "GetWindowLongW", user_GetWindowLongW); - //SetWindowLongA_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "SetWindowLongA"), "SetWindowLongA", user_SetWindowLongA); - //SetWindowLongW_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "SetWindowLongW"), "SetWindowLongW", user_SetWindowLongW); - } - if (kernel32) - { - Logging::Log() << "Installing Kernel32 hooks"; - Utils::GetDiskFreeSpaceA_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "GetDiskFreeSpaceA"), "GetDiskFreeSpaceA", Utils::kernel_GetDiskFreeSpaceA); - Utils::CreateThread_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "CreateThread"), "CreateThread", Utils::kernel_CreateThread); - Utils::VirtualAlloc_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "VirtualAlloc"), "VirtualAlloc", Utils::kernel_VirtualAlloc); - //Utils::HeapAlloc_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "HeapAlloc"), "HeapAlloc", Utils::kernel_HeapAlloc); - Utils::HeapSize_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "HeapSize"), "HeapSize", Utils::kernel_HeapSize); - } - RunOnce = false; - } + LPSTR lpName; + HMONITOR hm; + }; } -void ExitDDraw() -{ - if (IsInitialized) - { - IsInitialized = false; - DeleteCriticalSection(&ddcs); - } -} +static void SetAllAppCompatData(); +static HRESULT DirectDrawEnumerateHandler(LPVOID lpCallback, LPVOID lpContext, DWORD dwFlags, DirectDrawEnumerateTypes DDETType); -// Sets Application Compatibility Toolkit options for DXPrimaryEmulation using SetAppCompatData API -// http://web.archive.org/web/20170418171908/http://www.blitzbasic.com/Community/posts.php?topic=99477 -static void SetAllAppCompatData() -{ - DEFINE_STATIC_PROC_ADDRESS(SetAppCompatDataProc, SetAppCompatData, SetAppCompatData_out); - - if (!SetAppCompatData) - { - Logging::Log() << __FUNCTION__ << " Error: Failed to get `SetAppCompatData` address!"; - return; - } - - // Set AppCompatData - for (DWORD x = 1; x <= 12; x++) - { - if (Config.DXPrimaryEmulation[x]) - { - Logging::Log() << __FUNCTION__ << " SetAppCompatData: " << x << " " << (DWORD)((x == AppCompatDataType.LockColorkey) ? AppCompatDataType.LockColorkey : 0); - - // For LockColorkey, this one uses the second parameter - if (x == AppCompatDataType.LockColorkey) - { - SetAppCompatData(x, Config.LockColorkey); - } - // For all the other items - else - { - SetAppCompatData(x, 0); - } - } - } - return; -} +// ****************************** +// ddraw.dll export functions +// ****************************** HRESULT WINAPI dd_AcquireDDThreadLock() { @@ -148,7 +63,12 @@ HRESULT WINAPI dd_AcquireDDThreadLock() if (Config.Dd7to9) { - return SetCriticalSection(); + if (IsInitialized) + { + EnterCriticalSection(&ddcs); + return DD_OK; + } + return DDERR_UNSUPPORTED; } DEFINE_STATIC_PROC_ADDRESS(AcquireDDThreadLockProc, AcquireDDThreadLock, AcquireDDThreadLock_out); @@ -321,7 +241,7 @@ HRESULT WINAPI dd_DirectDrawCreate(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, I { LOG_LIMIT(1, __FUNCTION__); - if (Config.Dd7to9 || (Config.ConvertToDirect3D7 && Config.ConvertToDirectDraw7)) + if (Config.Dd7to9) { LOG_LIMIT(3, "Redirecting 'DirectDrawCreate' to --> 'Direct3DCreate9'"); @@ -330,14 +250,10 @@ HRESULT WINAPI dd_DirectDrawCreate(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, I Direct3D9SetSwapEffectUpgradeShim(Config.SetSwapEffectShim); } - SetCriticalSection(); - m_IDirectDrawX* p_IDirectDrawX = new m_IDirectDrawX(1, false); *lplpDD = reinterpret_cast(p_IDirectDrawX->GetWrapperInterfaceX(1)); - ReleaseCriticalSection(); - // Success return DD_OK; } @@ -361,28 +277,9 @@ HRESULT WINAPI dd_DirectDrawCreate(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, I if (SUCCEEDED(hr) && lplpDD && *lplpDD) { - // Convert to new DirectDraw version - if (Config.ConvertToDirectDraw7) - { - LPDIRECTDRAW lpDD = (LPDIRECTDRAW)*lplpDD; - - hr = lpDD->QueryInterface(ConvertREFIID(IID_IDirectDraw7), (LPVOID*)lplpDD); - - if (SUCCEEDED(hr)) - { - m_IDirectDrawX *Interface = new m_IDirectDrawX((IDirectDraw7*)*lplpDD, 7); - - *lplpDD = (LPDIRECTDRAW)Interface->GetWrapperInterfaceX(1); + m_IDirectDrawX* Interface = new m_IDirectDrawX((IDirectDraw7*)*lplpDD, 1); - lpDD->Release(); - } - } - else - { - m_IDirectDrawX *Interface = new m_IDirectDrawX((IDirectDraw7*)*lplpDD, 1); - - *lplpDD = (LPDIRECTDRAW)Interface->GetWrapperInterfaceX(1); - } + *lplpDD = (LPDIRECTDRAW)Interface->GetWrapperInterfaceX(1); } return hr; @@ -399,16 +296,14 @@ HRESULT WINAPI dd_DirectDrawCreateClipper(DWORD dwFlags, LPDIRECTDRAWCLIPPER *lp return DDERR_INVALIDPARAMS; } - SetCriticalSection(); + ScopedDDCriticalSection ThreadLockDD; - m_IDirectDrawClipper* ClipperX = CreateDirectDrawClipper(nullptr, nullptr, dwFlags); + m_IDirectDrawClipper* ClipperX = m_IDirectDrawClipper::CreateDirectDrawClipper(nullptr, nullptr, dwFlags); - AddBaseClipper(ClipperX); + m_IDirectDrawX::AddBaseClipper(ClipperX); *lplpDDClipper = ClipperX; - ReleaseCriticalSection(); - return DD_OK; } @@ -423,7 +318,7 @@ HRESULT WINAPI dd_DirectDrawCreateClipper(DWORD dwFlags, LPDIRECTDRAWCLIPPER *lp if (SUCCEEDED(hr) && lplpDDClipper) { - *lplpDDClipper = CreateDirectDrawClipper(*lplpDDClipper, nullptr, dwFlags); + *lplpDDClipper = m_IDirectDrawClipper::CreateDirectDrawClipper(*lplpDDClipper, nullptr, dwFlags); } return hr; @@ -453,14 +348,10 @@ HRESULT WINAPI dd_DirectDrawCreateEx(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID ri Direct3D9SetSwapEffectUpgradeShim(Config.SetSwapEffectShim); } - SetCriticalSection(); - m_IDirectDrawX *p_IDirectDrawX = new m_IDirectDrawX(7, true); *lplpDD = p_IDirectDrawX->GetWrapperInterfaceX(7); - ReleaseCriticalSection(); - // Success return DD_OK; } @@ -494,142 +385,6 @@ HRESULT WINAPI dd_DirectDrawCreateEx(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID ri return hr; } -static BOOL CALLBACK DispayEnumeratorProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - UNREFERENCED_PARAMETER(hdcMonitor); - UNREFERENCED_PARAMETER(lprcMonitor); - - ENUMMONITORS *lpMonitors = (ENUMMONITORS *)dwData; - if (!dwData || !lpMonitors->lpName) - { - return DDENUMRET_CANCEL; - } - - MONITORINFOEX monitorInfo; - ZeroMemory(&monitorInfo, sizeof(monitorInfo)); - monitorInfo.cbSize = sizeof(monitorInfo); - - if (!GetMonitorInfo(hMonitor, &monitorInfo)) - { - return DDENUMRET_OK; - } - - if (strcmp(monitorInfo.szDevice, lpMonitors->lpName) == 0) - { - lpMonitors->hm = hMonitor; - return DDENUMRET_CANCEL; - } - - return DDENUMRET_OK; -} - -static HRESULT DirectDrawEnumerateHandler(LPVOID lpCallback, LPVOID lpContext, DWORD dwFlags, DirectDrawEnumerateTypes DDETType) -{ - UNREFERENCED_PARAMETER(dwFlags); - - if (!lpCallback) - { - return DDERR_INVALIDPARAMS; - } - - // Declare Direct3DCreate9 - DEFINE_STATIC_PROC_ADDRESS(Direct3DCreate9Proc, Direct3DCreate9, Direct3DCreate9_out); - - if (!Direct3DCreate9) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get 'Direct3DCreate9' ProcAddress of d3d9.dll!"); - return DDERR_UNSUPPORTED; - } - - // Create Direct3D9 device - LPDIRECT3D9 d3d9Object = Direct3DCreate9(D3D_SDK_VERSION); - - // Error creating Direct3D9 - if (!d3d9Object) - { - LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create Direct3D9 object"); - return DDERR_UNSUPPORTED; - } - D3DADAPTER_IDENTIFIER9 Identifier = {}; - int AdapterCount = (!dwFlags) ? 0 : (int)d3d9Object->GetAdapterCount(); - - GUID* lpGUID; - LPSTR lpDesc, lpName; - wchar_t lpwName[32] = { '\0' }; - wchar_t lpwDesc[128] = { '\0' }; - HMONITOR hm = nullptr; - HRESULT hr = DD_OK; - for (int x = -1; x < AdapterCount; x++) - { - if (x == -1) - { - lpGUID = nullptr; - lpDesc = "Primary Display Driver"; - lpName = "display"; - hm = nullptr; - } - else - { - if (FAILED(d3d9Object->GetAdapterIdentifier(x, 0, &Identifier))) - { - hr = DDERR_UNSUPPORTED; - break; - } - lpGUID = &Identifier.DeviceIdentifier; - lpDesc = Identifier.Description; - lpName = Identifier.DeviceName; - - if (DDETType == DDET_ENUMCALLBACKEXA || DDETType == DDET_ENUMCALLBACKEXW) - { - ENUMMONITORS Monitors = {}; - Monitors.lpName = lpName; - Monitors.hm = nullptr; - EnumDisplayMonitors(nullptr, nullptr, DispayEnumeratorProc, (LPARAM)&Monitors); - hm = Monitors.hm; - } - } - - if (DDETType == DDET_ENUMCALLBACKEXW || DDETType == DDET_ENUMCALLBACKW) - { - size_t nReturn; - mbstowcs_s(&nReturn, lpwName, lpName, 32); - mbstowcs_s(&nReturn, lpwDesc, lpDesc, 128); - } - - BOOL hr_Callback = DDENUMRET_OK; - switch (DDETType) - { - case DDET_ENUMCALLBACKA: - hr_Callback = LPDDENUMCALLBACKA(lpCallback)(lpGUID, lpDesc, lpName, lpContext); - break; - case DDET_ENUMCALLBACKEXA: - hr_Callback = LPDDENUMCALLBACKEXA(lpCallback)(lpGUID, lpDesc, lpName, lpContext, hm); - break; - case DDET_ENUMCALLBACKEXW: - hr_Callback = LPDDENUMCALLBACKEXW(lpCallback)(lpGUID, lpwDesc, lpwName, lpContext, hm); - break; - case DDET_ENUMCALLBACKW: - hr_Callback = LPDDENUMCALLBACKW(lpCallback)(lpGUID, lpwDesc, lpwName, lpContext); - break; - default: - hr_Callback = DDENUMRET_CANCEL; - hr = DDERR_UNSUPPORTED; - } - - if (hr_Callback == DDENUMRET_CANCEL) - { - break; - } - } - - ULONG ref = d3d9Object->Release(); - if (ref) - { - Logging::Log() << __FUNCTION__ << " Error: there is still a reference to 'd3d9Object' " << ref; - } - return hr; -} - HRESULT WINAPI dd_DirectDrawEnumerateA(LPDDENUMCALLBACKA lpCallback, LPVOID lpContext) { LOG_LIMIT(1, __FUNCTION__); @@ -758,7 +513,7 @@ HRESULT WINAPI dd_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) return DDERR_UNSUPPORTED; } - HRESULT hr = DllGetClassObject(ConvertREFCLSID(rclsid), ConvertREFIID(riid), ppv); + HRESULT hr = DllGetClassObject(rclsid, riid, ppv); if (SUCCEEDED(hr) && ppv) { @@ -803,20 +558,20 @@ DWORD WINAPI dd_GetOLEThunkData(DWORD index) if (Config.Dd7to9) { + // switch(index) + // { + // case 1: return _dwLastFrameRate; + // case 2: return _lpDriverObjectList; + // case 3: return _lpAttachedProcesses; + // case 4: return 0; // does nothing? + // case 5: return _CheckExclusiveMode; + // case 6: return 0; // ReleaseExclusiveModeMutex + // } + LOG_LIMIT(100, __FUNCTION__ << " Not Implemented"); return NULL; } - // switch(index) - // { - // case 1: return _dwLastFrameRate; - // case 2: return _lpDriverObjectList; - // case 3: return _lpAttachedProcesses; - // case 4: return 0; // does nothing? - // case 5: return _CheckExclusiveMode; - // case 6: return 0; // ReleaseExclusiveModeMutex - // } - DEFINE_STATIC_PROC_ADDRESS(GetOLEThunkDataProc, GetOLEThunkData, GetOLEThunkData_out); if (!GetOLEThunkData) @@ -873,7 +628,12 @@ HRESULT WINAPI dd_ReleaseDDThreadLock() if (Config.Dd7to9) { - return ReleaseCriticalSection(); + if (IsInitialized) + { + LeaveCriticalSection(&ddcs); + return DD_OK; + } + return DDERR_UNSUPPORTED; } DEFINE_STATIC_PROC_ADDRESS(ReleaseDDThreadLockProc, ReleaseDDThreadLock, ReleaseDDThreadLock_out); @@ -906,66 +666,238 @@ HRESULT WINAPI dd_SetAppCompatData(DWORD Type, DWORD Value) return SetAppCompatData(Type, Value); } -void AddBaseClipper(m_IDirectDrawClipper* lpClipper) +// ****************************** +// Helper functions +// ****************************** + +void InitDDraw() { - if (!lpClipper || DoesBaseClipperExist(lpClipper)) + if (!IsInitialized) { - return; + InitializeCriticalSection(&ddcs); + IsInitialized = true; } - SetCriticalSection(); + // Hook other gdi32 and user32 APIs + static bool RunOnce = true; + if (RunOnce) + { + Logging::Log() << "Installing GDI & User32 hooks"; + using namespace GdiWrapper; + if (!GetModuleHandleA("gdi32.dll")) LoadLibrary("gdi32.dll"); + if (!GetModuleHandleA("user32.dll")) LoadLibrary("user32.dll"); + HMODULE gdi32 = GetModuleHandleA("gdi32.dll"); + HMODULE user32 = GetModuleHandleA("user32.dll"); + HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); + if (gdi32) + { + GetDeviceCaps_out = (FARPROC)Hook::HotPatch(GetProcAddress(gdi32, "GetDeviceCaps"), "GetDeviceCaps", gdi_GetDeviceCaps); + } + if (user32) + { + CreateWindowExA_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "CreateWindowExA"), "CreateWindowExA", user_CreateWindowExA); + CreateWindowExW_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "CreateWindowExW"), "CreateWindowExW", user_CreateWindowExW); + DestroyWindow_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "DestroyWindow"), "DestroyWindow", user_DestroyWindow); + GetSystemMetrics_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "GetSystemMetrics"), "GetSystemMetrics", user_GetSystemMetrics); + //GetWindowLongA_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "GetWindowLongA"), "GetWindowLongA", user_GetWindowLongA); + //GetWindowLongW_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "GetWindowLongW"), "GetWindowLongW", user_GetWindowLongW); + //SetWindowLongA_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "SetWindowLongA"), "SetWindowLongA", user_SetWindowLongA); + //SetWindowLongW_out = (FARPROC)Hook::HotPatch(GetProcAddress(user32, "SetWindowLongW"), "SetWindowLongW", user_SetWindowLongW); + } + if (kernel32) + { + Logging::Log() << "Installing Kernel32 hooks"; + Utils::GetDiskFreeSpaceA_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "GetDiskFreeSpaceA"), "GetDiskFreeSpaceA", Utils::kernel_GetDiskFreeSpaceA); + if (!Utils::CreateThread_out) + { + Utils::CreateThread_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "CreateThread"), "CreateThread", Utils::kernel_CreateThread); + } + Utils::VirtualAlloc_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "VirtualAlloc"), "VirtualAlloc", Utils::kernel_VirtualAlloc); + //Utils::HeapAlloc_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "HeapAlloc"), "HeapAlloc", Utils::kernel_HeapAlloc); + Utils::HeapSize_out = (FARPROC)Hook::HotPatch(GetProcAddress(kernel32, "HeapSize"), "HeapSize", Utils::kernel_HeapSize); + } + RunOnce = false; + } +} - BaseClipperVector.push_back(lpClipper); +void ExitDDraw() +{ + if (IsInitialized) + { + IsInitialized = false; + DeleteCriticalSection(&ddcs); + } +} - ReleaseCriticalSection(); +bool TryDDThreadLock() +{ + if (IsInitialized) + { + return TryEnterCriticalSection(&ddcs) != FALSE; + } + return true; } -void ClearBaseClipper(m_IDirectDrawClipper* lpClipper) +// Sets Application Compatibility Toolkit options for DXPrimaryEmulation using SetAppCompatData API +static void SetAllAppCompatData() { - if (!lpClipper) + DEFINE_STATIC_PROC_ADDRESS(SetAppCompatDataProc, SetAppCompatData, SetAppCompatData_out); + + if (!SetAppCompatData) { + Logging::Log() << __FUNCTION__ << " Error: Failed to get `SetAppCompatData` address!"; return; } - SetCriticalSection(); - - BaseClipperVector.erase(std::remove(BaseClipperVector.begin(), BaseClipperVector.end(), lpClipper), BaseClipperVector.end()); + // Set AppCompatData + for (DWORD x = 1; x <= 12; x++) + { + if (Config.DXPrimaryEmulation[x]) + { + Logging::Log() << __FUNCTION__ << " SetAppCompatData: " << x << " " << (DWORD)((x == AppCompatDataType.LockColorkey) ? AppCompatDataType.LockColorkey : 0); - ReleaseCriticalSection(); + // For LockColorkey, this one uses the second parameter + if (x == AppCompatDataType.LockColorkey) + { + SetAppCompatData(x, Config.LockColorkey); + } + // For all the other items + else + { + SetAppCompatData(x, 0); + } + } + } + return; } -bool DoesBaseClipperExist(m_IDirectDrawClipper* lpClipper) +static BOOL CALLBACK DispayEnumeratorProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { - if (!lpClipper) + UNREFERENCED_PARAMETER(hdcMonitor); + UNREFERENCED_PARAMETER(lprcMonitor); + + ENUMMONITORS* lpMonitors = (ENUMMONITORS*)dwData; + if (!dwData || !lpMonitors->lpName) { - return false; + return DDENUMRET_CANCEL; } - SetCriticalSection(); + MONITORINFOEX monitorInfo; + ZeroMemory(&monitorInfo, sizeof(monitorInfo)); + monitorInfo.cbSize = sizeof(monitorInfo); - const bool found = (std::find(BaseClipperVector.begin(), BaseClipperVector.end(), lpClipper) != std::end(BaseClipperVector)); + if (!GetMonitorInfo(hMonitor, &monitorInfo)) + { + return DDENUMRET_OK; + } - ReleaseCriticalSection(); + if (strcmp(monitorInfo.szDevice, lpMonitors->lpName) == 0) + { + lpMonitors->hm = hMonitor; + return DDENUMRET_CANCEL; + } - return found; + return DDENUMRET_OK; } -HRESULT DdrawWrapper::SetCriticalSection() +static HRESULT DirectDrawEnumerateHandler(LPVOID lpCallback, LPVOID lpContext, DWORD dwFlags, DirectDrawEnumerateTypes DDETType) { - if (IsInitialized) + UNREFERENCED_PARAMETER(dwFlags); + + if (!lpCallback) { - EnterCriticalSection(&ddcs); - return DD_OK; + return DDERR_INVALIDPARAMS; } - return DDERR_UNSUPPORTED; -} -HRESULT DdrawWrapper::ReleaseCriticalSection() -{ - if (IsInitialized) + // Declare Direct3DCreate9 + DEFINE_STATIC_PROC_ADDRESS(Direct3DCreate9Proc, Direct3DCreate9, Direct3DCreate9_out); + + if (!Direct3DCreate9) { - LeaveCriticalSection(&ddcs); - return DD_OK; + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get 'Direct3DCreate9' ProcAddress of d3d9.dll!"); + return DDERR_UNSUPPORTED; + } + + // Create Direct3D9 object + ComPtr d3d9Object(Direct3DCreate9(D3D_SDK_VERSION)); + + // Error handling + if (!d3d9Object) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create Direct3D9 object"); + return DDERR_UNSUPPORTED; + } + D3DADAPTER_IDENTIFIER9 Identifier = {}; + int AdapterCount = (!dwFlags) ? 0 : (int)d3d9Object->GetAdapterCount(); + + GUID* lpGUID; + LPSTR lpDesc, lpName; + wchar_t lpwName[32] = { '\0' }; + wchar_t lpwDesc[128] = { '\0' }; + HMONITOR hm = nullptr; + HRESULT hr = DD_OK; + for (int x = -1; x < AdapterCount; x++) + { + if (x == -1) + { + lpGUID = nullptr; + lpDesc = "Primary Display Driver"; + lpName = "display"; + hm = nullptr; + } + else + { + if (FAILED(d3d9Object->GetAdapterIdentifier(x, 0, &Identifier))) + { + hr = DDERR_UNSUPPORTED; + break; + } + lpGUID = &Identifier.DeviceIdentifier; + lpDesc = Identifier.Description; + lpName = Identifier.DeviceName; + + if (DDETType == DDET_ENUMCALLBACKEXA || DDETType == DDET_ENUMCALLBACKEXW) + { + ENUMMONITORS Monitors = {}; + Monitors.lpName = lpName; + Monitors.hm = nullptr; + EnumDisplayMonitors(nullptr, nullptr, DispayEnumeratorProc, (LPARAM)&Monitors); + hm = Monitors.hm; + } + } + + if (DDETType == DDET_ENUMCALLBACKEXW || DDETType == DDET_ENUMCALLBACKW) + { + size_t nReturn; + mbstowcs_s(&nReturn, lpwName, lpName, 32); + mbstowcs_s(&nReturn, lpwDesc, lpDesc, 128); + } + + BOOL hr_Callback = DDENUMRET_OK; + switch (DDETType) + { + case DDET_ENUMCALLBACKA: + hr_Callback = LPDDENUMCALLBACKA(lpCallback)(lpGUID, lpDesc, lpName, lpContext); + break; + case DDET_ENUMCALLBACKEXA: + hr_Callback = LPDDENUMCALLBACKEXA(lpCallback)(lpGUID, lpDesc, lpName, lpContext, hm); + break; + case DDET_ENUMCALLBACKEXW: + hr_Callback = LPDDENUMCALLBACKEXW(lpCallback)(lpGUID, lpwDesc, lpwName, lpContext, hm); + break; + case DDET_ENUMCALLBACKW: + hr_Callback = LPDDENUMCALLBACKW(lpCallback)(lpGUID, lpwDesc, lpwName, lpContext); + break; + default: + hr_Callback = DDENUMRET_CANCEL; + hr = DDERR_UNSUPPORTED; + } + + if (hr_Callback == DDENUMRET_CANCEL) + { + break; + } } - return DDERR_UNSUPPORTED; + + return hr; } diff --git a/ddraw/ddraw.h b/ddraw/ddraw.h index 6ba67cb9..6dbbc4ff 100644 --- a/ddraw/ddraw.h +++ b/ddraw/ddraw.h @@ -8,6 +8,12 @@ #include #include #include +#include +#include +#include + +// Enable for testing +//#define ENABLE_PROFILING class m_IDirect3D; class m_IDirect3D2; @@ -52,6 +58,9 @@ class m_IDirectDrawPalette; class m_IDirectDrawColorControl; class m_IDirectDrawGammaControl; +#include "d3dx9.h" +#include "External\DirectXMath\Inc\DirectXMath.h" +#include "ddraw\ddrawExternal.h" #include "AddressLookupTable.h" #include "IClassFactory\IClassFactory.h" #include "Settings\Settings.h" @@ -61,8 +70,8 @@ class m_IDirectDrawGammaControl; // Indicates surface was created using CreateSurface() #define DDSCAPS4_CREATESURFACE 0x0001 -// Indicates surface is a primary surface or a backbuffer of a primary surface -#define DDSCAPS4_PRIMARYSURFACE 0x0200 +// Indicates surface is a child of a complex surface +#define DDSCAPS4_COMPLEXCHILD 0x0002 // ddraw proc typedefs typedef HRESULT(WINAPI *AcquireDDThreadLockProc)(); @@ -94,29 +103,24 @@ HRESULT WINAPI dd_DirectDrawCreateEx(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID ri HRESULT WINAPI dd_DirectDrawEnumerateA(LPDDENUMCALLBACKA lpCallback, LPVOID lpContext); HRESULT WINAPI dd_DirectDrawEnumerateW(LPDDENUMCALLBACKW lpCallback, LPVOID lpContext); -void AddBaseClipper(m_IDirectDrawClipper* lpClipper); -void ClearBaseClipper(m_IDirectDrawClipper* lpClipper); -bool DoesBaseClipperExist(m_IDirectDrawClipper* lpClipper); +bool TryDDThreadLock(); // Function and variable forward declarations namespace DdrawWrapper { DWORD GetGUIDVersion(REFIID CalledID); REFIID ReplaceIIDUnknown(REFIID riid, REFIID guid); - REFCLSID ConvertREFCLSID(REFCLSID rclsid); - REFIID ConvertREFIID(REFIID riid); - HRESULT SetCriticalSection(); - HRESULT ReleaseCriticalSection(); HRESULT ProxyQueryInterface(LPVOID ProxyInterface, REFIID CalledID, LPVOID * ppvObj, REFIID CallerID); void WINAPI genericQueryInterface(REFIID riid, LPVOID *ppvObj); -} -extern const D3DFORMAT D9DisplayFormat; + struct ScopedDDCriticalSection { + ScopedDDCriticalSection() { dd_AcquireDDThreadLock(); } + ~ScopedDDCriticalSection() { dd_ReleaseDDThreadLock(); } + }; +} extern AddressLookupTableDdraw ProxyAddressLookupTable; -extern std::vector DDrawVector; - enum DirectDrawEnumerateTypes { DDET_ENUMCALLBACKA, @@ -125,12 +129,8 @@ enum DirectDrawEnumerateTypes DDET_ENUMCALLBACKW, }; -extern float ScaleDDWidthRatio; -extern float ScaleDDHeightRatio; -extern DWORD ScaleDDCurrentWidth; -extern DWORD ScaleDDCurrentHeight; -extern DWORD ScaleDDPadX; -extern DWORD ScaleDDPadY; +#include "ComPtr.h" +#include "ScopeGuard.h" using namespace DdrawWrapper; diff --git a/ddraw/ddrawExternal.h b/ddraw/ddrawExternal.h index 222f5c09..f35e5c57 100644 --- a/ddraw/ddrawExternal.h +++ b/ddraw/ddrawExternal.h @@ -30,14 +30,8 @@ HRESULT WINAPI dd_RegisterSpecialCase(DWORD arg1, DWORD arg2, DWORD arg3, DWORD HRESULT WINAPI dd_ReleaseDDThreadLock(); HRESULT WINAPI dd_SetAppCompatData(DWORD Type, DWORD Value); -bool CheckDirectDrawXInterface(void* pInterface); - class m_IDirectDrawClipper; -DWORD GetDDrawBitsPixel(HWND hWnd); -DWORD GetDDrawWidth(); -DWORD GetDDrawHeight(); - void InitDDraw(); void ExitDDraw(); diff --git a/dinput/License.txt b/dinput/License.txt index 53f73bd0..9cdb9d78 100644 --- a/dinput/License.txt +++ b/dinput/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput/dinput.cpp b/dinput/dinput.cpp index 618d3d1b..1ffe3e59 100644 --- a/dinput/dinput.cpp +++ b/dinput/dinput.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput8/IDirectInput8.cpp b/dinput8/IDirectInput8.cpp index d8b303a8..bb3656fa 100644 --- a/dinput8/IDirectInput8.cpp +++ b/dinput8/IDirectInput8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput8/IDirectInputDevice8.cpp b/dinput8/IDirectInputDevice8.cpp index fde85b10..0d1de323 100644 --- a/dinput8/IDirectInputDevice8.cpp +++ b/dinput8/IDirectInputDevice8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput8/IDirectInputEffect8.cpp b/dinput8/IDirectInputEffect8.cpp index d415f3e6..1439c7bc 100644 --- a/dinput8/IDirectInputEffect8.cpp +++ b/dinput8/IDirectInputEffect8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput8/InterfaceQuery.cpp b/dinput8/InterfaceQuery.cpp index e7fb1696..8ae71e4e 100644 --- a/dinput8/InterfaceQuery.cpp +++ b/dinput8/InterfaceQuery.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput8/License.txt b/dinput8/License.txt index 53f73bd0..9cdb9d78 100644 --- a/dinput8/License.txt +++ b/dinput8/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dinput8/dinput8.cpp b/dinput8/dinput8.cpp index 0798c687..7c3372b1 100644 --- a/dinput8/dinput8.cpp +++ b/dinput8/dinput8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSound3DBuffer8.cpp b/dsound/IDirectSound3DBuffer8.cpp index 670be67c..26977450 100644 --- a/dsound/IDirectSound3DBuffer8.cpp +++ b/dsound/IDirectSound3DBuffer8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSound3DListener8.cpp b/dsound/IDirectSound3DListener8.cpp index 772ae7ee..a3c2442e 100644 --- a/dsound/IDirectSound3DListener8.cpp +++ b/dsound/IDirectSound3DListener8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSound8.cpp b/dsound/IDirectSound8.cpp index 2986a48b..9ae6ec31 100644 --- a/dsound/IDirectSound8.cpp +++ b/dsound/IDirectSound8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundBuffer8.cpp b/dsound/IDirectSoundBuffer8.cpp index 829c4c81..0c4c4dbc 100644 --- a/dsound/IDirectSoundBuffer8.cpp +++ b/dsound/IDirectSoundBuffer8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundCapture8.cpp b/dsound/IDirectSoundCapture8.cpp index 94376cf1..27f9ffe3 100644 --- a/dsound/IDirectSoundCapture8.cpp +++ b/dsound/IDirectSoundCapture8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundCaptureBuffer8.cpp b/dsound/IDirectSoundCaptureBuffer8.cpp index dd5e0d20..1008d515 100644 --- a/dsound/IDirectSoundCaptureBuffer8.cpp +++ b/dsound/IDirectSoundCaptureBuffer8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundCaptureFXAec8.cpp b/dsound/IDirectSoundCaptureFXAec8.cpp index ec3f66b8..6e2a4bb2 100644 --- a/dsound/IDirectSoundCaptureFXAec8.cpp +++ b/dsound/IDirectSoundCaptureFXAec8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundCaptureFXNoiseSuppress8.cpp b/dsound/IDirectSoundCaptureFXNoiseSuppress8.cpp index c0be5b52..fbaf59c0 100644 --- a/dsound/IDirectSoundCaptureFXNoiseSuppress8.cpp +++ b/dsound/IDirectSoundCaptureFXNoiseSuppress8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXChorus8.cpp b/dsound/IDirectSoundFXChorus8.cpp index 0b813c5c..6a89bd58 100644 --- a/dsound/IDirectSoundFXChorus8.cpp +++ b/dsound/IDirectSoundFXChorus8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXCompressor8.cpp b/dsound/IDirectSoundFXCompressor8.cpp index bf75f7ed..ce595d04 100644 --- a/dsound/IDirectSoundFXCompressor8.cpp +++ b/dsound/IDirectSoundFXCompressor8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXDistortion8.cpp b/dsound/IDirectSoundFXDistortion8.cpp index fec6f786..50d34066 100644 --- a/dsound/IDirectSoundFXDistortion8.cpp +++ b/dsound/IDirectSoundFXDistortion8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXEcho8.cpp b/dsound/IDirectSoundFXEcho8.cpp index 374db596..b5c5ad27 100644 --- a/dsound/IDirectSoundFXEcho8.cpp +++ b/dsound/IDirectSoundFXEcho8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXFlanger8.cpp b/dsound/IDirectSoundFXFlanger8.cpp index 4c18f218..4b3cd409 100644 --- a/dsound/IDirectSoundFXFlanger8.cpp +++ b/dsound/IDirectSoundFXFlanger8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXGargle8.cpp b/dsound/IDirectSoundFXGargle8.cpp index f0259e4b..08ed58d8 100644 --- a/dsound/IDirectSoundFXGargle8.cpp +++ b/dsound/IDirectSoundFXGargle8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXI3DL2Reverb8.cpp b/dsound/IDirectSoundFXI3DL2Reverb8.cpp index e5d24bea..25e1837b 100644 --- a/dsound/IDirectSoundFXI3DL2Reverb8.cpp +++ b/dsound/IDirectSoundFXI3DL2Reverb8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXParamEq8.cpp b/dsound/IDirectSoundFXParamEq8.cpp index a6720ca4..0ac126e1 100644 --- a/dsound/IDirectSoundFXParamEq8.cpp +++ b/dsound/IDirectSoundFXParamEq8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFXWavesReverb8.cpp b/dsound/IDirectSoundFXWavesReverb8.cpp index c9d7c6a2..6f1614e2 100644 --- a/dsound/IDirectSoundFXWavesReverb8.cpp +++ b/dsound/IDirectSoundFXWavesReverb8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundFullDuplex8.cpp b/dsound/IDirectSoundFullDuplex8.cpp index 5e184815..5399310c 100644 --- a/dsound/IDirectSoundFullDuplex8.cpp +++ b/dsound/IDirectSoundFullDuplex8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IDirectSoundNotify8.cpp b/dsound/IDirectSoundNotify8.cpp index 9c90df3f..b8666a2f 100644 --- a/dsound/IDirectSoundNotify8.cpp +++ b/dsound/IDirectSoundNotify8.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/IKsPropertySet.cpp b/dsound/IKsPropertySet.cpp index 5c6e60a0..6864257d 100644 --- a/dsound/IKsPropertySet.cpp +++ b/dsound/IKsPropertySet.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/InterfaceQuery.cpp b/dsound/InterfaceQuery.cpp index 6729309d..681e7827 100644 --- a/dsound/InterfaceQuery.cpp +++ b/dsound/InterfaceQuery.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/License.txt b/dsound/License.txt index 53f73bd0..9cdb9d78 100644 --- a/dsound/License.txt +++ b/dsound/License.txt @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dsound/dsound.cpp b/dsound/dsound.cpp index 870737c6..12f1a387 100644 --- a/dsound/dsound.cpp +++ b/dsound/dsound.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2024 Elisha Riedlinger +* Copyright (C) 2025 Elisha Riedlinger * * This software is provided 'as-is', without any express or implied warranty. In no event will the * authors be held liable for any damages arising from the use of this software. diff --git a/dxwrapper.vcxproj b/dxwrapper.vcxproj index 96ecc4da..55a45485 100644 --- a/dxwrapper.vcxproj +++ b/dxwrapper.vcxproj @@ -650,6 +650,7 @@ copy /Y "$(ProjectDir)Settings\Settings.ini" "$(TargetDir)Build\dxwrapper.ini" & + @@ -1277,6 +1278,8 @@ copy /Y "$(ProjectDir)Settings\Settings.ini" "$(TargetDir)Build\dxwrapper.ini" & + + diff --git a/dxwrapper.vcxproj.filters b/dxwrapper.vcxproj.filters index c4cd2826..7d1c74f1 100644 --- a/dxwrapper.vcxproj.filters +++ b/dxwrapper.vcxproj.filters @@ -895,6 +895,9 @@ GDI + + Utils + @@ -1895,6 +1898,12 @@ ddraw\Shaders + + Libraries + + + Libraries + From 9864712657237a782080b1db30e6fdc44ce6c48f Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Mon, 31 Mar 2025 15:32:07 -0700 Subject: [PATCH 23/25] Fix build merge issues --- ddraw/IDirect3DDeviceX.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 1534d17c..f46bbbed 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -5113,6 +5113,7 @@ void m_IDirect3DDeviceX::CopyConvertExecuteVertex(BYTE*& DestVertex, DWORD& Dest DestVertex += sizeof(D3DTLVERTEX); return; } +} HRESULT m_IDirect3DDeviceX::DrawExecutePoint(D3DPOINT* point, WORD pointCount, DWORD vertexIndexCount, BYTE* vertexBuffer, DWORD VertexTypeDesc) { From 7c890df84fc009f9945bbadfd50f009c79b597d6 Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Tue, 10 Jun 2025 18:25:21 -0700 Subject: [PATCH 24/25] Fix build issue --- ddraw/IDirect3DDeviceX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 85a4ddaa..276f2773 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -2955,7 +2955,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy SetDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); // Draw indexed primitive UP - HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride); + HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpwIndices, D3DFMT_INDEX16, lpVertices, targetStride); // Handle dwFlags RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); From e34127fb780a5762c3c2089f7fbd79c2d1f4f76a Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Mon, 29 Sep 2025 16:29:53 -0700 Subject: [PATCH 25/25] Fix build issue --- ddraw/IDirect3DDeviceX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddraw/IDirect3DDeviceX.cpp b/ddraw/IDirect3DDeviceX.cpp index 0ee5140a..9f1d9ee5 100644 --- a/ddraw/IDirect3DDeviceX.cpp +++ b/ddraw/IDirect3DDeviceX.cpp @@ -3019,7 +3019,7 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpwIndices, D3DFMT_INDEX16, lpVertices, targetStride); // Handle dwFlags - RestoreDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion); + RestoreDrawStates(newVertexTypeDesc, dwFlags); // Restore transform D3DMATRIX identityMatrix = {};