diff --git a/LEGO1/lego/legoomni/include/police.h b/LEGO1/lego/legoomni/include/police.h index 39294cb1..8d8d7840 100644 --- a/LEGO1/lego/legoomni/include/police.h +++ b/LEGO1/lego/legoomni/include/police.h @@ -16,6 +16,11 @@ class MxDSAction; // SIZE 0x10 class PoliceState : public LegoState { public: + enum { + e_noAnimation = 0, + e_playingAnimation = 1, + }; + PoliceState(); ~PoliceState() override {} @@ -38,15 +43,15 @@ class PoliceState : public LegoState { // SYNTHETIC: LEGO1 0x1005e920 // PoliceState::`scalar deleting destructor' - undefined4 GetUnknown0x0c() { return m_unk0x0c; } - void SetUnknown0x0c(undefined4 p_unk0x0c) { m_unk0x0c = p_unk0x0c; } + MxS32 GetState() { return m_state; } + void SetState(MxS32 p_state) { m_state = p_state; } - void FUN_1005ea40(); + void StartAnimation(); // TODO: Most likely getters/setters are not used according to BETA. PoliceScript::Script m_policeScript; // 0x08 - undefined4 m_unk0x0c; // 0x0c + MxS32 m_state; // 0x0c }; // VTABLE: LEGO1 0x100d8a80 diff --git a/LEGO1/lego/legoomni/src/worlds/police.cpp b/LEGO1/lego/legoomni/src/worlds/police.cpp index 82a948e1..64992771 100644 --- a/LEGO1/lego/legoomni/src/worlds/police.cpp +++ b/LEGO1/lego/legoomni/src/worlds/police.cpp @@ -105,7 +105,7 @@ MxLong Police::HandleControl(LegoControlManagerNotificationParam& p_param) switch (p_param.m_clickedObjectId) { case PoliceScript::c_LeftArrow_Ctl: case PoliceScript::c_RightArrow_Ctl: - if (m_policeState->GetUnknown0x0c() == 1) { + if (m_policeState->GetState() == PoliceState::e_playingAnimation) { DeleteObjects(&m_atomId, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); } @@ -114,7 +114,7 @@ MxLong Police::HandleControl(LegoControlManagerNotificationParam& p_param) TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); break; case PoliceScript::c_Info_Ctl: - if (m_policeState->GetUnknown0x0c() == 1) { + if (m_policeState->GetState() == PoliceState::e_playingAnimation) { DeleteObjects(&m_atomId, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); } @@ -123,7 +123,7 @@ MxLong Police::HandleControl(LegoControlManagerNotificationParam& p_param) TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); break; case PoliceScript::c_Door_Ctl: - if (m_policeState->GetUnknown0x0c() == 1) { + if (m_policeState->GetState() == PoliceState::e_playingAnimation) { DeleteObjects(&m_atomId, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); } @@ -132,7 +132,7 @@ MxLong Police::HandleControl(LegoControlManagerNotificationParam& p_param) TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); break; case PoliceScript::c_Donut_Ctl: - m_policeState->FUN_1005ea40(); + m_policeState->StartAnimation(); } } @@ -145,8 +145,8 @@ MxLong Police::HandleEndAction(MxEndActionNotificationParam& p_param) MxDSAction* action = p_param.GetAction(); if (m_radio.Notify(p_param) == 0 && m_atomId == action->GetAtomId()) { - if (m_policeState->GetUnknown0x0c() == 1) { - m_policeState->SetUnknown0x0c(0); + if (m_policeState->GetState() == PoliceState::e_playingAnimation) { + m_policeState->SetState(PoliceState::e_noAnimation); return 1; } @@ -161,9 +161,9 @@ MxLong Police::HandleKeyPress(LegoEventNotificationParam& p_param) { MxLong result = 0; - if (p_param.GetKey() == SDLK_SPACE && m_policeState->GetUnknown0x0c() == 1) { + if (p_param.GetKey() == SDLK_SPACE && m_policeState->GetState() == PoliceState::e_playingAnimation) { DeleteObjects(&m_atomId, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); - m_policeState->SetUnknown0x0c(0); + m_policeState->SetState(PoliceState::e_noAnimation); return 1; } @@ -197,7 +197,7 @@ MxBool Police::Escape() // FUNCTION: LEGO1 0x1005e7c0 PoliceState::PoliceState() { - m_unk0x0c = 0; + m_state = PoliceState::e_noAnimation; m_policeScript = (SDL_rand(2) == 0) ? PoliceScript::c_nps002la_RunAnim : PoliceScript::c_nps001ni_RunAnim; } @@ -218,11 +218,11 @@ MxResult PoliceState::Serialize(LegoStorage* p_storage) } // FUNCTION: LEGO1 0x1005ea40 -void PoliceState::FUN_1005ea40() +void PoliceState::StartAnimation() { PoliceScript::Script policeScript; - if (m_unk0x0c == 1) { + if (m_state == PoliceState::e_playingAnimation) { return; } @@ -248,5 +248,5 @@ void PoliceState::FUN_1005ea40() Start(&action); } - m_unk0x0c = 1; + m_state = PoliceState::e_playingAnimation; } diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index ad5021ce..e702a244 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -439,6 +439,11 @@ HRESULT OpenGL1Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix) return DD_OK; } +void OpenGL1Renderer::EnableTransparency() +{ + glDepthMask(GL_FALSE); +} + void OpenGL1Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, @@ -524,6 +529,7 @@ void OpenGL1Renderer::SubmitDraw( HRESULT OpenGL1Renderer::FinalizeFrame() { + glDepthMask(GL_TRUE); glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); glBindFramebuffer(GL_FRAMEBUFFER, 0); diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index a363e997..1459028f 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -735,6 +735,11 @@ HRESULT Direct3DRMSDL3GPURenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix) return DD_OK; } +void Direct3DRMSDL3GPURenderer::EnableTransparency() +{ + SDL_BindGPUGraphicsPipeline(m_renderPass, m_transparentPipeline); +} + void Direct3DRMSDL3GPURenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, @@ -742,9 +747,6 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw( const Appearance& appearance ) { - // TODO only switch piplinen after all opaque's have been rendered - SDL_BindGPUGraphicsPipeline(m_renderPass, appearance.color.a == 255 ? m_opaquePipeline : m_transparentPipeline); - D3DRMMATRIX4D worldViewMatrix; MultiplyMatrix(worldViewMatrix, worldMatrix, m_viewMatrix); memcpy(&m_uniforms.worldViewMatrix, worldViewMatrix, sizeof(D3DRMMATRIX4D)); diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index f7b76ea3..80ed06ab 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -554,6 +554,10 @@ HRESULT Direct3DRMSoftwareRenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix) return DD_OK; } +void Direct3DRMSoftwareRenderer::EnableTransparency() +{ +} + void Direct3DRMSoftwareRenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, diff --git a/miniwin/src/d3drm/d3drmviewport.cpp b/miniwin/src/d3drm/d3drmviewport.cpp index d9546d74..065ea0ff 100644 --- a/miniwin/src/d3drm/d3drmviewport.cpp +++ b/miniwin/src/d3drm/d3drmviewport.cpp @@ -216,6 +216,23 @@ bool IsMeshInFrustum(Direct3DRMMeshImpl* mesh, const D3DRMMATRIX4D& worldMatrix) return true; } +inline D3DRMVECTOR4D TransformPoint4(const D3DRMVECTOR4D& p, const D3DRMMATRIX4D& m) +{ + return { + p.x * m[0][0] + p.y * m[1][0] + p.z * m[2][0] + p.w * m[3][0], + p.x * m[0][1] + p.y * m[1][1] + p.z * m[2][1] + p.w * m[3][1], + p.x * m[0][2] + p.y * m[1][2] + p.z * m[2][2] + p.w * m[3][2], + p.x * m[0][3] + p.y * m[1][3] + p.z * m[2][3] + p.w * m[3][3] + }; +} + +float CalculateDepth(const D3DRMMATRIX4D& viewProj, const D3DRMMATRIX4D& worldMatrix) +{ + D3DRMVECTOR4D position = {worldMatrix[3][0], worldMatrix[3][1], worldMatrix[3][2], 1.0f}; + D3DRMVECTOR4D clipPos = TransformPoint4(position, viewProj); + return (clipPos.z / clipPos.w + 1.0f) * 0.5f; +} + void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix) { Direct3DRMFrameImpl* frameImpl = static_cast(frame); @@ -251,15 +268,33 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3D DWORD groupCount = mesh->GetGroupCount(); for (DWORD gi = 0; gi < groupCount; ++gi) { const MeshGroup& meshGroup = mesh->GetGroup(gi); - m_renderer->SubmitDraw( - m_renderer->GetMeshId(mesh, &meshGroup), - worldMatrix, - worldMatrixInvert, - {meshGroup.color, - meshGroup.material ? meshGroup.material->GetPower() : 0.0f, - meshGroup.texture ? m_renderer->GetTextureId(meshGroup.texture) : NO_TEXTURE_ID, - meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT} - ); + + Appearance appearance = { + meshGroup.color, + meshGroup.material ? meshGroup.material->GetPower() : 0.0f, + meshGroup.texture ? m_renderer->GetTextureId(meshGroup.texture) : NO_TEXTURE_ID, + meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT + }; + + if (appearance.color.a != 255) { + m_deferredDraws.push_back( + {m_renderer->GetMeshId(mesh, &meshGroup), + {}, + {}, + appearance, + CalculateDepth(m_viewProjectionwMatrix, worldMatrix)} + ); + memcpy(m_deferredDraws.back().worldMatrix, worldMatrix, sizeof(D3DRMMATRIX4D)); + memcpy(m_deferredDraws.back().normalMatrix, worldMatrixInvert, sizeof(Matrix3x3)); + } + else { + m_renderer->SubmitDraw( + m_renderer->GetMeshId(mesh, &meshGroup), + worldMatrix, + worldMatrixInvert, + appearance + ); + } } } mesh->Release(); @@ -274,10 +309,10 @@ HRESULT Direct3DRMViewportImpl::RenderScene() m_backgroundColor = static_cast(m_rootFrame)->m_backgroundColor; // Compute view-projection matrix - D3DRMMATRIX4D cameraWorld, viewProj; + D3DRMMATRIX4D cameraWorld; ComputeFrameWorldMatrix(m_camera, cameraWorld); D3DRMMatrixInvertOrthogonal(m_viewMatrix, cameraWorld); - D3DRMMatrixMultiply(viewProj, m_viewMatrix, m_projectionMatrix); + D3DRMMatrixMultiply(m_viewProjectionwMatrix, m_viewMatrix, m_projectionMatrix); D3DRMMATRIX4D identity = {{1.f, 0.f, 0.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}}; @@ -289,8 +324,20 @@ HRESULT Direct3DRMViewportImpl::RenderScene() return status; } - ExtractFrustumPlanes(viewProj); + ExtractFrustumPlanes(m_viewProjectionwMatrix); CollectMeshesFromFrame(m_rootFrame, identity); + + std::sort( + m_deferredDraws.begin(), + m_deferredDraws.end(), + [](const DeferredDrawCommand& a, const DeferredDrawCommand& b) { return a.depth > b.depth; } + ); + m_renderer->EnableTransparency(); + for (const DeferredDrawCommand& cmd : m_deferredDraws) { + m_renderer->SubmitDraw(cmd.meshId, cmd.worldMatrix, cmd.normalMatrix, cmd.appearance); + } + m_deferredDraws.clear(); + return m_renderer->FinalizeFrame(); } diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index 924860f5..4b4d5f7f 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -42,6 +42,7 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0; virtual const char* GetName() = 0; virtual HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) = 0; + virtual void EnableTransparency() = 0; virtual void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index 98be09af..580eb498 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -48,6 +48,7 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override; + void EnableTransparency() override; void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index 5fe92573..37ba4353 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -55,6 +55,7 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override; + void EnableTransparency() override; void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 5293d2d1..574d052d 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -36,6 +36,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override; + void EnableTransparency() override; void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& worldMatrix, diff --git a/miniwin/src/internal/d3drmviewport_impl.h b/miniwin/src/internal/d3drmviewport_impl.h index 1d996d0d..53e18717 100644 --- a/miniwin/src/internal/d3drmviewport_impl.h +++ b/miniwin/src/internal/d3drmviewport_impl.h @@ -5,6 +5,15 @@ #include "miniwin/d3drm.h" #include +#include + +struct DeferredDrawCommand { + DWORD meshId; + D3DRMMATRIX4D worldMatrix; + Matrix3x3 normalMatrix; + Appearance appearance; + float depth; +}; class Direct3DRMDeviceImpl; class Direct3DRMFrameImpl; @@ -40,9 +49,11 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl m_deferredDraws; D3DCOLOR m_backgroundColor = 0xFF000000; DWORD m_width; DWORD m_height; + D3DRMMATRIX4D m_viewProjectionwMatrix; D3DRMMATRIX4D m_viewMatrix; D3DRMMATRIX4D m_projectionMatrix; D3DRMMATRIX4D m_inverseProjectionMatrix;