From d5558f67407491acba08d156c7f2b80d4d6bdf7a Mon Sep 17 00:00:00 2001 From: Elisha Riedlinger Date: Fri, 7 Feb 2025 07:22:39 -0800 Subject: [PATCH] Detect environment cube map shotgun approach #136 --- Dllmain/BuildNo.rc | 2 +- Settings/AllSettings.ini | 1 + Settings/Settings.cpp | 2 + Settings/Settings.h | 2 + d3d9/IDirect3DDevice9Ex.cpp | 325 +++++++++++++++++++++++++++++++--- d3d9/IDirect3DDevice9Ex.h | 46 +++-- d3d9/IDirect3DPixelShader9.h | 5 +- d3d9/IDirect3DVertexShader9.h | 5 +- 8 files changed, 352 insertions(+), 36 deletions(-) diff --git a/Dllmain/BuildNo.rc b/Dllmain/BuildNo.rc index 9c1fa387..34ed2fa8 100644 --- a/Dllmain/BuildNo.rc +++ b/Dllmain/BuildNo.rc @@ -1 +1 @@ -#define BUILD_NUMBER 7502 +#define BUILD_NUMBER 7503 diff --git a/Settings/AllSettings.ini b/Settings/AllSettings.ini index cfa92aa4..56214c64 100644 --- a/Settings/AllSettings.ini +++ b/Settings/AllSettings.ini @@ -89,6 +89,7 @@ DdrawMaintainAspectRatio = 0 AnisotropicFiltering = 0 AntiAliasing = 0 CacheClipPlane = 0 +EnvironmentMapCubeFix = 0 EnableVSync = 0 ForceVsyncMode = 0 OverrideRefreshRate = 0 diff --git a/Settings/Settings.cpp b/Settings/Settings.cpp index be321821..125ddebe 100644 --- a/Settings/Settings.cpp +++ b/Settings/Settings.cpp @@ -468,6 +468,7 @@ void Settings::SetDefaultConfigSettings() Config.DsoundHookSystem32 = NOT_EXIST; Config.DdrawResolutionHack = NOT_EXIST; Config.CacheClipPlane = NOT_EXIST; + Config.EnvironmentMapCubeFix = NOT_EXIST; // Other values that may not exist in ini file Config.DisableMaxWindowedModeNotSet = true; @@ -771,4 +772,5 @@ void CONFIG::SetConfig() // Set unset options DdrawResolutionHack = (DdrawResolutionHack != 0); CacheClipPlane = (CacheClipPlane != 0); + EnvironmentMapCubeFix = (EnvironmentMapCubeFix != 0); } diff --git a/Settings/Settings.h b/Settings/Settings.h index 9f27eb26..53639333 100644 --- a/Settings/Settings.h +++ b/Settings/Settings.h @@ -64,6 +64,7 @@ visit(DisableLogging) \ visit(DirectShowEmulation) \ visit(CacheClipPlane) \ + visit(EnvironmentMapCubeFix) \ visit(ConvertToDirectDraw7) \ visit(ConvertToDirect3D7) \ visit(EnableDdrawWrapper) \ @@ -258,6 +259,7 @@ struct CONFIG bool DisableLogging = false; // Disables the logging file 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 bool EnableDdrawWrapper = false; // Enables the ddraw wrapper diff --git a/d3d9/IDirect3DDevice9Ex.cpp b/d3d9/IDirect3DDevice9Ex.cpp index 5b374352..55a0da25 100644 --- a/d3d9/IDirect3DDevice9Ex.cpp +++ b/d3d9/IDirect3DDevice9Ex.cpp @@ -136,7 +136,7 @@ ULONG m_IDirect3DDevice9Ex::Release() return ref; } -void m_IDirect3DDevice9Ex::ClearVars(D3DPRESENT_PARAMETERS* pPresentationParameters) +inline void m_IDirect3DDevice9Ex::ClearVars(D3DPRESENT_PARAMETERS* pPresentationParameters) const { UNREFERENCED_PARAMETER(pPresentationParameters); @@ -150,7 +150,7 @@ void m_IDirect3DDevice9Ex::ClearVars(D3DPRESENT_PARAMETERS* pPresentationParamet } template -HRESULT m_IDirect3DDevice9Ex::ResetT(T func, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) +inline HRESULT m_IDirect3DDevice9Ex::ResetT(T func, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) { if (!pPresentationParameters) { @@ -684,12 +684,23 @@ HRESULT m_IDirect3DDevice9Ex::SetRenderTarget(THIS_ DWORD RenderTargetIndex, IDi HRESULT m_IDirect3DDevice9Ex::SetTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX *pMatrix) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ") State: " << State; + + HRESULT hr = ProxyInterface->SetTransform(State, pMatrix); - return ProxyInterface->SetTransform(State, pMatrix); + if (SUCCEEDED(hr)) + { + // Check if this is a texture stage transform + if (Config.EnvironmentMapCubeFix) + { + CheckTransformForCubeMap(State, pMatrix); + } + } + + return hr; } -HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) +inline HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) { Logging::LogDebug() << __FUNCTION__; @@ -739,7 +750,7 @@ HRESULT m_IDirect3DDevice9Ex::SetBrightnessLevel(D3DGAMMARAMP& Ramp) return D3D_OK; } -LPDIRECT3DPIXELSHADER9 m_IDirect3DDevice9Ex::GetGammaPixelShader() const +inline LPDIRECT3DPIXELSHADER9 m_IDirect3DDevice9Ex::GetGammaPixelShader() const { // Create pixel shaders if (!SHARED.gammaPixelShader) @@ -749,7 +760,7 @@ LPDIRECT3DPIXELSHADER9 m_IDirect3DDevice9Ex::GetGammaPixelShader() const return SHARED.gammaPixelShader; } -void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() +inline void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() { if (!SHARED.GammaLUTTexture) { @@ -891,7 +902,7 @@ void m_IDirect3DDevice9Ex::ApplyBrightnessLevel() ProxyInterface->SetTextureStageState(0, D3DTSS_ALPHAOP, tsAlphaOP); } -void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) const +inline void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) const { if (SHARED.GammaLUTTexture) { @@ -923,12 +934,33 @@ void m_IDirect3DDevice9Ex::ReleaseResources(bool isReset) const SHARED.gammaPixelShader = nullptr; } + if (SHARED.BlankTexture) + { + ULONG ref = SHARED.BlankTexture->Release(); + if (ref) + { + Logging::Log() << __FUNCTION__ << " Error: there is still a reference to 'BlankTexture' " << ref; + } + SHARED.BlankTexture = nullptr; + } + if (isReset) { // Anisotropic Filtering SHARED.isAnisotropySet = false; SHARED.AnisotropyDisabledFlag = false; + // For environment map cube + SHARED.isPixelShaderMapCube = false; + SHARED.isVertexShaderMapCube = false; + std::fill(std::begin(SHARED.isTextureMapCube), std::end(SHARED.isTextureMapCube), false); + std::fill(std::begin(SHARED.isEnvironmentMapCube), std::end(SHARED.isEnvironmentMapCube), false); + std::fill(std::begin(SHARED.isTransformMapCube), std::end(SHARED.isTransformMapCube), false); + std::fill(std::begin(SHARED.texCoordIndex), std::end(SHARED.texCoordIndex), 0); + std::fill(std::begin(SHARED.texTransformFlags), std::end(SHARED.texTransformFlags), 0); + std::fill(std::begin(SHARED.isBlankTextureUsed), std::end(SHARED.isBlankTextureUsed), false); + std::fill(std::begin(SHARED.pCurrentTexture), std::end(SHARED.pCurrentTexture), nullptr); + // For CacheClipPlane SHARED.isClipPlaneSet = false; SHARED.m_clipPlaneRenderState = 0; @@ -1205,12 +1237,25 @@ HRESULT m_IDirect3DDevice9Ex::SetPixelShader(THIS_ IDirect3DPixelShader9* pShade { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + m_IDirect3DPixelShader9* pShaderX = reinterpret_cast(pShader); + if (pShader) { pShader = static_cast(pShader)->GetProxyInterface(); } - return ProxyInterface->SetPixelShader(pShader); + HRESULT hr = ProxyInterface->SetPixelShader(pShader); + + if (SUCCEEDED(hr)) + { + // Check if shader requires cube map + if (Config.EnvironmentMapCubeFix) + { + SHARED.isPixelShaderMapCube = pShaderX ? pShaderX->RequiresCubeMap() : false; + } + } + + return hr; } HRESULT m_IDirect3DDevice9Ex::Present(CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion) @@ -1260,6 +1305,24 @@ inline void m_IDirect3DDevice9Ex::ApplyDrawFixes() { ReeableAnisotropicSamplerState(); } + + // Fix environment map cubes + if (Config.EnvironmentMapCubeFix) + { + SetEnvironmentMapCubeTexture(); + } +} + +inline void m_IDirect3DDevice9Ex::RestoreDrawFixes() +{ + for (DWORD i = 0; i < MAX_TEXTURE_STAGES; i++) + { + if (SHARED.isBlankTextureUsed[i]) + { + SHARED.isBlankTextureUsed[i] = false; + ProxyInterface->SetTexture(i, nullptr); + } + } } HRESULT m_IDirect3DDevice9Ex::DrawIndexedPrimitive(THIS_ D3DPRIMITIVETYPE Type, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) @@ -1268,7 +1331,11 @@ HRESULT m_IDirect3DDevice9Ex::DrawIndexedPrimitive(THIS_ D3DPRIMITIVETYPE Type, ApplyDrawFixes(); - return ProxyInterface->DrawIndexedPrimitive(Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); + HRESULT hr = ProxyInterface->DrawIndexedPrimitive(Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); + + RestoreDrawFixes(); + + return hr; } HRESULT m_IDirect3DDevice9Ex::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinIndex, UINT NumVertices, UINT PrimitiveCount, CONST void *pIndexData, D3DFORMAT IndexDataFormat, CONST void *pVertexStreamZeroData, UINT VertexStreamZeroStride) @@ -1277,7 +1344,11 @@ HRESULT m_IDirect3DDevice9Ex::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveT ApplyDrawFixes(); - return ProxyInterface->DrawIndexedPrimitiveUP(PrimitiveType, MinIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); + HRESULT hr = ProxyInterface->DrawIndexedPrimitiveUP(PrimitiveType, MinIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); + + RestoreDrawFixes(); + + return hr; } HRESULT m_IDirect3DDevice9Ex::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) @@ -1286,7 +1357,11 @@ HRESULT m_IDirect3DDevice9Ex::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT ApplyDrawFixes(); - return ProxyInterface->DrawPrimitive(PrimitiveType, StartVertex, PrimitiveCount); + HRESULT hr = ProxyInterface->DrawPrimitive(PrimitiveType, StartVertex, PrimitiveCount); + + RestoreDrawFixes(); + + return hr; } HRESULT m_IDirect3DDevice9Ex::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void *pVertexStreamZeroData, UINT VertexStreamZeroStride) @@ -1295,7 +1370,11 @@ HRESULT m_IDirect3DDevice9Ex::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UI ApplyDrawFixes(); - return ProxyInterface->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); + HRESULT hr = ProxyInterface->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); + + RestoreDrawFixes(); + + return hr; } HRESULT m_IDirect3DDevice9Ex::BeginScene() @@ -1435,10 +1514,172 @@ HRESULT m_IDirect3DDevice9Ex::GetTextureStageState(DWORD Stage, D3DTEXTURESTAGES return ProxyInterface->GetTextureStageState(Stage, Type, pValue); } +// Check if shader requires cube map +template +inline bool ShaderRequiresCubeMap(T* pShader) +{ + if (!Config.EnvironmentMapCubeFix) return false; + + if (!pShader) return false; + + UINT size = 0; + pShader->GetFunction(nullptr, &size); + if (size == 0) return false; + + std::vector shaderCode(size / sizeof(DWORD)); + if (FAILED(pShader->GetFunction(shaderCode.data(), &size))) return false; + + const DWORD* pCode = shaderCode.data(); + const DWORD* pEnd = pCode + (size / sizeof(DWORD)); + + while (pCode < pEnd) + { + DWORD opcode = pCode[0] & D3DSI_OPCODE_MASK; + + if (opcode == D3DSIO_TEX || + (std::is_same_v && (opcode == D3DSIO_TEXLDD || opcode == D3DSIO_TEXLDL))) + { + DWORD srcReg = pCode[1]; + DWORD regType = (srcReg & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT; + + if (regType == D3DSPR_SAMPLER) + { + return true; // Shader needs a cube map + } + } + + pCode += ((*pCode) & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT; + } + + return false; +} + +// Check if this is a texture stage transform +inline void m_IDirect3DDevice9Ex::CheckTransformForCubeMap(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) const +{ + if (State >= D3DTS_TEXTURE0 && State <= D3DTS_TEXTURE7) + { + DWORD stage = State - D3DTS_TEXTURE0; + + // Detect if the transformation is likely for cube mapping + if (pMatrix) + { + bool isCubeMap = false; + + const D3DMATRIX& m = *pMatrix; + + // Check if matrix is different from the identity matrix + static const 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 + }; + + if (memcmp(&m, &identityMatrix, sizeof(D3DMATRIX)) != 0) + { + // Cube mapping typically involves a transformation that modifies + // a 3D reflection vector or normal vector without translation. + if (m._41 == 0.0f && m._42 == 0.0f && m._43 == 0.0f && m._44 == 1.0f) + { + // Additionally, ensure it's not a typical 2D texture transform + if (m._14 == 0.0f && m._24 == 0.0f && m._34 == 0.0f) // No perspective projection + { + isCubeMap = true; + } + } + } + + // Store cube map detection result + SHARED.isTransformMapCube[stage] = isCubeMap; + } + } +} + +// Check if an environment cube map is being used +inline void m_IDirect3DDevice9Ex::CheckTextureStageForCubeMap() const +{ + bool isUsingEnvCubeMap[MAX_TEXTURE_STAGES] = {}; + for (DWORD i = 0; i < MAX_TEXTURE_STAGES; i++) + { + if ((SHARED.texCoordIndex[i] == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR || SHARED.texCoordIndex[i] == D3DTSS_TCI_CAMERASPACENORMAL) && + ((SHARED.texTransformFlags[i] & D3DTTFF_COUNT3) || (SHARED.texTransformFlags[i] & D3DTTFF_COUNT4))) + { + isUsingEnvCubeMap[i] = true; + break; + } + } + + for (DWORD i = 0; i < MAX_TEXTURE_STAGES; i++) + { + SHARED.isEnvironmentMapCube[i] = isUsingEnvCubeMap[i]; + } +} + +inline void m_IDirect3DDevice9Ex::SetEnvironmentMapCubeTexture() +{ + CheckTextureStageForCubeMap(); + + const bool isCubeMap = SHARED.isPixelShaderMapCube || SHARED.isVertexShaderMapCube || + [&]() { + for (int i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + if (SHARED.isTextureMapCube[i] || SHARED.isEnvironmentMapCube[i] || SHARED.isTransformMapCube[i]) + { + return true; + } + } + return false; + }(); + + for (DWORD i = 0; i < MAX_TEXTURE_STAGES; i++) + { + if ((SHARED.isEnvironmentMapCube[i] || SHARED.isTransformMapCube[i] || (i == 0 && isCubeMap)) && !SHARED.pCurrentTexture[i]) + { + if (!SHARED.BlankTexture) + { + const UINT CubeSize = 64; + HRESULT hr = ProxyInterface->CreateCubeTexture(CubeSize, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &SHARED.BlankTexture, nullptr); + if (FAILED(hr)) + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create BlankCubeTexture for environment map!"); + return; + } + + D3DLOCKED_RECT lockedRect; + for (UINT face = 0; face < 6; ++face) + { + if (SUCCEEDED(SHARED.BlankTexture->LockRect((D3DCUBEMAP_FACES)face, 0, &lockedRect, nullptr, 0))) + { + DWORD* pixels = static_cast(lockedRect.pBits); + for (UINT y = 0; y < CubeSize; ++y) + { + for (UINT x = 0; x < CubeSize; ++x) + { + pixels[x] = D3DCOLOR_ARGB(255, 255, 255, 255); // White with full alpha + } + pixels += lockedRect.Pitch / sizeof(DWORD); + } + SHARED.BlankTexture->UnlockRect((D3DCUBEMAP_FACES)face, 0); + } + else + { + LOG_LIMIT(100, __FUNCTION__ << " Error: failed to lock BlankCubeTexture face: " << face); + } + } + } + + SHARED.isBlankTextureUsed[i] = true; + ProxyInterface->SetTexture(i, SHARED.BlankTexture); + } + } +} + HRESULT m_IDirect3DDevice9Ex::SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture) { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + bool isTexCube = false; if (pTexture) { switch (pTexture->GetType()) @@ -1459,6 +1700,7 @@ HRESULT m_IDirect3DDevice9Ex::SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTe break; case D3DRTYPE_CUBETEXTURE: pTexture = static_cast(pTexture)->GetProxyInterface(); + isTexCube = true; if (SHARED.MaxAnisotropy && Stage > 0) { DisableAnisotropicSamplerState((SHARED.Caps.CubeTextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC), (SHARED.Caps.CubeTextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC)); @@ -1469,14 +1711,42 @@ HRESULT m_IDirect3DDevice9Ex::SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTe } } - return ProxyInterface->SetTexture(Stage, pTexture); + HRESULT hr = ProxyInterface->SetTexture(Stage, pTexture); + + if (SUCCEEDED(hr)) + { + if (Stage < MAX_TEXTURE_STAGES) + { + SHARED.isTextureMapCube[Stage] = isTexCube; + SHARED.pCurrentTexture[Stage] = pTexture; + } + } + + return hr; } HRESULT m_IDirect3DDevice9Ex::SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) { - Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + Logging::LogDebug() << __FUNCTION__ << " (" << this << ") Stage: " << Stage << " Type: " << Type << " Value: " << Value; + + HRESULT hr = ProxyInterface->SetTextureStageState(Stage, Type, Value); + + if (SUCCEEDED(hr)) + { + if (Stage < MAX_TEXTURE_STAGES) + { + if (Type == D3DTSS_TEXCOORDINDEX) + { + SHARED.texCoordIndex[Stage] = Value; + } + else if (Type == D3DTSS_TEXTURETRANSFORMFLAGS) + { + SHARED.texTransformFlags[Stage] = Value; + } + } + } - return ProxyInterface->SetTextureStageState(Stage, Type, Value); + return hr; } HRESULT m_IDirect3DDevice9Ex::UpdateTexture(IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture) @@ -1646,12 +1916,25 @@ HRESULT m_IDirect3DDevice9Ex::SetVertexShader(THIS_ IDirect3DVertexShader9* pSha { Logging::LogDebug() << __FUNCTION__ << " (" << this << ")"; + m_IDirect3DVertexShader9* pShaderX = reinterpret_cast(pShader); + if (pShader) { pShader = static_cast(pShader)->GetProxyInterface(); } - return ProxyInterface->SetVertexShader(pShader); + HRESULT hr = ProxyInterface->SetVertexShader(pShader); + + if (SUCCEEDED(hr)) + { + // Check if shader requires cube map + if (Config.EnvironmentMapCubeFix) + { + SHARED.isVertexShaderMapCube = pShaderX ? pShaderX->RequiresCubeMap() : false; + } + } + + return hr; } HRESULT m_IDirect3DDevice9Ex::CreateQuery(THIS_ D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) @@ -1945,7 +2228,7 @@ HRESULT m_IDirect3DDevice9Ex::SetSamplerState(THIS_ DWORD Sampler, D3DSAMPLERSTA return ProxyInterface->SetSamplerState(Sampler, Type, Value); } -void m_IDirect3DDevice9Ex::DisableAnisotropicSamplerState(bool AnisotropyMin, bool AnisotropyMag) +inline void m_IDirect3DDevice9Ex::DisableAnisotropicSamplerState(bool AnisotropyMin, bool AnisotropyMag) { DWORD Value = 0; for (int x = 0; x < 4; x++) @@ -2669,7 +2952,7 @@ HRESULT m_IDirect3DDevice9Ex::GetDisplayModeEx(THIS_ UINT iSwapChain, D3DDISPLAY } // Runs when device is created and on every successful Reset() -void m_IDirect3DDevice9Ex::ReInitInterface() +inline void m_IDirect3DDevice9Ex::ReInitInterface() const { Utils::GetScreenSize(SHARED.DeviceWindow, SHARED.screenWidth, SHARED.screenHeight); @@ -2686,7 +2969,7 @@ void m_IDirect3DDevice9Ex::ReInitInterface() } } -void m_IDirect3DDevice9Ex::LimitFrameRate() +inline void m_IDirect3DDevice9Ex::LimitFrameRate() const { // Count the number of frames SHARED.Counter.FrameCounter++; @@ -2738,7 +3021,7 @@ void m_IDirect3DDevice9Ex::LimitFrameRate() SHARED.Counter.LastPresentTime.QuadPart = TargetEndTicks; } -void m_IDirect3DDevice9Ex::CalculateFPS() +inline void m_IDirect3DDevice9Ex::CalculateFPS() const { // Calculate frame time auto endTime = std::chrono::steady_clock::now(); diff --git a/d3d9/IDirect3DDevice9Ex.h b/d3d9/IDirect3DDevice9Ex.h index 011474f7..8bf443cf 100644 --- a/d3d9/IDirect3DDevice9Ex.h +++ b/d3d9/IDirect3DDevice9Ex.h @@ -1,8 +1,13 @@ #pragma once static constexpr size_t MAX_CLIP_PLANES = 6; +static constexpr size_t MAX_TEXTURE_STAGES = 8; const std::chrono::seconds FPS_CALCULATION_WINDOW(1); // Define a constant for the desired duration of FPS calculation +// For environment map cube +template +bool ShaderRequiresCubeMap(T* pShader); + struct DEVICEDETAILS { // Window handle and size @@ -25,7 +30,7 @@ struct DEVICEDETAILS // Frame counter double AverageFPSCounter = 0.0; 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 + std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); // Store start time for PFS counter // For AntiAliasing bool DeviceMultiSampleFlag = false; @@ -38,6 +43,18 @@ struct DEVICEDETAILS bool isAnisotropySet = false; bool AnisotropyDisabledFlag = false; // Tracks when Anisotropic Fintering was disabled becasue lack of multi-stage texture support + // For environment map cube + bool isPixelShaderMapCube = false; + bool isVertexShaderMapCube = false; + bool isTextureMapCube[MAX_TEXTURE_STAGES] = {}; + bool isEnvironmentMapCube[MAX_TEXTURE_STAGES] = {}; + bool isTransformMapCube[MAX_TEXTURE_STAGES] = {}; + DWORD texCoordIndex[MAX_TEXTURE_STAGES] = {}; + DWORD texTransformFlags[MAX_TEXTURE_STAGES] = {}; + bool isBlankTextureUsed[MAX_TEXTURE_STAGES] = {}; + IDirect3DBaseTexture9* pCurrentTexture[MAX_TEXTURE_STAGES] = {}; + IDirect3DCubeTexture9* BlankTexture = nullptr; + // For CacheClipPlane bool isClipPlaneSet = false; DWORD m_clipPlaneRenderState = 0; @@ -46,8 +63,8 @@ struct DEVICEDETAILS // For gamma bool IsGammaSet = false; bool UsingShader32f = true; - D3DGAMMARAMP RampData; - D3DGAMMARAMP DefaultRampData; + D3DGAMMARAMP RampData = {}; + D3DGAMMARAMP DefaultRampData = {}; LPDIRECT3DTEXTURE9 GammaLUTTexture = nullptr; LPDIRECT3DTEXTURE9 ScreenCopyTexture = nullptr; LPDIRECT3DPIXELSHADER9 gammaPixelShader = nullptr; @@ -70,12 +87,13 @@ class m_IDirect3DDevice9Ex : public IDirect3DDevice9Ex, public AddressLookupTabl UINT DDKey; void ApplyDrawFixes(); + void RestoreDrawFixes(); // Limit frame rate - void LimitFrameRate(); + void LimitFrameRate() const; // Frame counter - void CalculateFPS(); + void CalculateFPS() const; // Anisotropic Filtering void DisableAnisotropicSamplerState(bool AnisotropyMin, bool AnisotropyMag); @@ -87,16 +105,21 @@ class m_IDirect3DDevice9Ex : public IDirect3DDevice9Ex, public AddressLookupTabl void ApplyBrightnessLevel(); void ReleaseResources(bool isReset) const; + // For environment map cube + void CheckTransformForCubeMap(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) const; + void CheckTextureStageForCubeMap() const; + void SetEnvironmentMapCubeTexture(); + // For Reset & ResetEx - void ReInitInterface(); - void ClearVars(D3DPRESENT_PARAMETERS* pPresentationParameters); + void ReInitInterface() const; + void ClearVars(D3DPRESENT_PARAMETERS* pPresentationParameters) const; typedef HRESULT(WINAPI* fReset)(D3DPRESENT_PARAMETERS* pPresentationParameters); typedef HRESULT(WINAPI* fResetEx)(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode); template HRESULT ResetT(T, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode = nullptr); - HRESULT ResetT(fReset, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX*) + inline HRESULT ResetT(fReset, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX*) { return ProxyInterface->Reset(pPresentationParameters); } - HRESULT ResetT(fResetEx, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) + inline HRESULT ResetT(fResetEx, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) { return (ProxyInterfaceEx) ? ProxyInterfaceEx->ResetEx(pPresentationParameters, pFullscreenDisplayMode) : D3DERR_INVALIDCALL; } public: @@ -271,9 +294,8 @@ class m_IDirect3DDevice9Ex : public IDirect3DDevice9Ex, public AddressLookupTabl STDMETHOD(GetDisplayModeEx)(THIS_ UINT iSwapChain, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation); // Helper functions - inline LPDIRECT3DDEVICE9 GetProxyInterface() { return ProxyInterface; } - inline AddressLookupTableD3d9* GetLookupTable() { return &SHARED.ProxyAddressLookupTable9; } - inline D3DMULTISAMPLE_TYPE GetMultiSampleType() { return SHARED.DeviceMultiSampleType; } + inline LPDIRECT3DDEVICE9 GetProxyInterface() const { return ProxyInterface; } + inline AddressLookupTableD3d9* GetLookupTable() const { return &SHARED.ProxyAddressLookupTable9; } REFIID GetIID() { return WrapperID; } }; #undef SHARED diff --git a/d3d9/IDirect3DPixelShader9.h b/d3d9/IDirect3DPixelShader9.h index 2de48ad0..a5ed955b 100644 --- a/d3d9/IDirect3DPixelShader9.h +++ b/d3d9/IDirect3DPixelShader9.h @@ -6,9 +6,11 @@ class m_IDirect3DPixelShader9 : public IDirect3DPixelShader9, public AddressLook LPDIRECT3DPIXELSHADER9 ProxyInterface; m_IDirect3DDevice9Ex* m_pDeviceEx; REFIID WrapperID = IID_IDirect3DPixelShader9; + const bool bRequiresCubeMap; public: - m_IDirect3DPixelShader9(LPDIRECT3DPIXELSHADER9 pShader9, m_IDirect3DDevice9Ex* pDevice) : ProxyInterface(pShader9), m_pDeviceEx(pDevice) + m_IDirect3DPixelShader9(LPDIRECT3DPIXELSHADER9 pShader9, m_IDirect3DDevice9Ex* pDevice) : + ProxyInterface(pShader9), m_pDeviceEx(pDevice), bRequiresCubeMap(ShaderRequiresCubeMap(pShader9)) { LOG_LIMIT(3, "Creating interface " << __FUNCTION__ << " (" << this << ")"); @@ -30,4 +32,5 @@ class m_IDirect3DPixelShader9 : public IDirect3DPixelShader9, public AddressLook // Helper functions LPDIRECT3DPIXELSHADER9 GetProxyInterface() { return ProxyInterface; } + inline bool RequiresCubeMap() const { return bRequiresCubeMap; } }; diff --git a/d3d9/IDirect3DVertexShader9.h b/d3d9/IDirect3DVertexShader9.h index 904ef7e6..eb022d14 100644 --- a/d3d9/IDirect3DVertexShader9.h +++ b/d3d9/IDirect3DVertexShader9.h @@ -6,9 +6,11 @@ class m_IDirect3DVertexShader9 : public IDirect3DVertexShader9, public AddressLo LPDIRECT3DVERTEXSHADER9 ProxyInterface; m_IDirect3DDevice9Ex* m_pDeviceEx; REFIID WrapperID = IID_IDirect3DVertexShader9; + const bool bRequiresCubeMap; public: - m_IDirect3DVertexShader9(LPDIRECT3DVERTEXSHADER9 pShader9, m_IDirect3DDevice9Ex* pDevice) : ProxyInterface(pShader9), m_pDeviceEx(pDevice) + m_IDirect3DVertexShader9(LPDIRECT3DVERTEXSHADER9 pShader9, m_IDirect3DDevice9Ex* pDevice) : + ProxyInterface(pShader9), m_pDeviceEx(pDevice), bRequiresCubeMap(ShaderRequiresCubeMap(pShader9)) { LOG_LIMIT(3, "Creating interface " << __FUNCTION__ << " (" << this << ")"); @@ -30,4 +32,5 @@ class m_IDirect3DVertexShader9 : public IDirect3DVertexShader9, public AddressLo // Helper functions LPDIRECT3DVERTEXSHADER9 GetProxyInterface() { return ProxyInterface; } + inline bool RequiresCubeMap() const { return bRequiresCubeMap; } };