diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 6acdedd9a..2a4750c2e 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -1728,7 +1728,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; if (unlikely(ShouldRecord())) { - Logger::warn("D3D9DeviceEx::SetLight: State block not implemented."); + m_recorder->SetLight(Index, pLight); return D3D_OK; } @@ -1762,6 +1762,11 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D9DeviceEx::LightEnable(DWORD Index, BOOL Enable) { D3D9DeviceLock lock = LockDevice(); + if (unlikely(ShouldRecord())) { + m_recorder->LightEnable(Index, Enable); + return D3D_OK; + } + if (unlikely(Index >= m_state.lights.size())) m_state.lights.resize(Index + 1); diff --git a/src/d3d9/d3d9_stateblock.cpp b/src/d3d9/d3d9_stateblock.cpp index 6deca2246..aec477127 100644 --- a/src/d3d9/d3d9_stateblock.cpp +++ b/src/d3d9/d3d9_stateblock.cpp @@ -157,6 +157,46 @@ namespace dxvk { } + HRESULT D3D9StateBlock::SetLight(DWORD Index, const D3DLIGHT9* pLight) { + if (Index >= m_state.lights.size()) + m_state.lights.resize(Index + 1); + + m_state.lights[Index] = *pLight; + + m_captures.flags.set(D3D9CapturedStateFlag::Lights); + return D3D_OK; + } + + + HRESULT D3D9StateBlock::LightEnable(DWORD Index, BOOL Enable) { + if (unlikely(Index >= m_state.lights.size())) + m_state.lights.resize(Index + 1); + + if (unlikely(!m_state.lights[Index])) + m_state.lights[Index] = DefaultLight; + + if (m_state.IsLightEnabled(Index) == !!Enable) + return D3D_OK; + + uint32_t searchIndex = UINT32_MAX; + uint32_t setIndex = Index; + + if (!Enable) + std::swap(searchIndex, setIndex); + + for (auto& idx : m_state.enabledLightIndices) { + if (idx == searchIndex) { + idx = setIndex; + break; + } + } + + m_captures.lightEnabledChanges.set(Index, true); + m_captures.flags.set(D3D9CapturedStateFlag::Lights); + return D3D_OK; + } + + HRESULT D3D9StateBlock::SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix) { m_state.transforms[idx] = ConvertMatrix(pMatrix); @@ -495,6 +535,8 @@ namespace dxvk { m_captures.flags.set(D3D9CapturedStateFlag::VertexDecl); m_captures.flags.set(D3D9CapturedStateFlag::StreamFreq); + m_captures.flags.set(D3D9CapturedStateFlag::Lights); + m_captures.lightEnabledChanges.setN(m_deviceState->lights.size()); for (uint32_t i = 0; i < caps::MaxStreams; i++) m_captures.streamFreq.set(i, true); diff --git a/src/d3d9/d3d9_stateblock.h b/src/d3d9/d3d9_stateblock.h index 43a712ad6..a098b54fa 100644 --- a/src/d3d9/d3d9_stateblock.h +++ b/src/d3d9/d3d9_stateblock.h @@ -25,7 +25,8 @@ namespace dxvk { StreamFreq, Transforms, TextureStages, - Material + Material, + Lights }; using D3D9CapturedStateFlags = Flags; @@ -61,6 +62,8 @@ namespace dxvk { bit::bitset iConsts; bit::bitset bConsts; } psConsts; + + bit::bitvector lightEnabledChanges; }; enum class D3D9StateBlockType :uint32_t { @@ -120,6 +123,10 @@ namespace dxvk { HRESULT SetMaterial(const D3DMATERIAL9* pMaterial); + HRESULT SetLight(DWORD Index, const D3DLIGHT9* pLight); + + HRESULT LightEnable(DWORD Index, BOOL Enable); + HRESULT SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix); HRESULT SetStateTextureStageState( @@ -297,6 +304,22 @@ namespace dxvk { dst->SetPixelBoolBitfield(i, m_captures.psConsts.bConsts.dword(i), src->psConsts.bConsts[i]); } } + + if (m_captures.flags.test(D3D9CapturedStateFlag::Lights)) { + for (uint32_t i = 0; i < m_state.lights.size(); i++) { + if (!m_state.lights[i].has_value()) + continue; + + dst->SetLight(i, &m_state.lights[i].value()); + } + for (uint32_t i = 0; i < m_captures.lightEnabledChanges.dwordCount(); i++) { + for (uint32_t consts : bit::BitMask(m_captures.lightEnabledChanges.dword(i))) { + uint32_t idx = i * 32 + consts; + + dst->LightEnable(idx, m_state.IsLightEnabled(idx)); + } + } + } } template