From 79d60b8d6967db6d8eea07a237c6b0ea37f2ded4 Mon Sep 17 00:00:00 2001 From: FileEX Date: Mon, 10 Nov 2025 11:08:45 +0100 Subject: [PATCH] dxDrawModel3D doubleSided argument --- Client/game_sa/CRendererSA.cpp | 12 +- Client/game_sa/CRendererSA.h | 2 +- .../mods/deathmatch/logic/CModelRenderer.cpp | 8 +- Client/mods/deathmatch/logic/CModelRenderer.h | 12 +- .../logic/luadefs/CLuaDrawingDefs.cpp | 4 +- .../logic/luadefs/CLuaDrawingDefs.h | 2 +- Client/sdk/game/CRenderer.h | 2 +- Client/sdk/game/RenderWare.h | 186 +++++++++++++++++- 8 files changed, 211 insertions(+), 17 deletions(-) diff --git a/Client/game_sa/CRendererSA.cpp b/Client/game_sa/CRendererSA.cpp index e576e82729e..e1198c15e4a 100644 --- a/Client/game_sa/CRendererSA.cpp +++ b/Client/game_sa/CRendererSA.cpp @@ -26,7 +26,7 @@ CRendererSA::~CRendererSA() { } -void CRendererSA::RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting) +void CRendererSA::RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting, bool doubleSided) { CBaseModelInfoSAInterface* pModelInfoSAInterface = pModelInfo->GetInterface(); if (!pModelInfoSAInterface) @@ -48,6 +48,13 @@ void CRendererSA::RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, flo // Setup ambient light multiplier SetLightColoursForPedsCarsAndObjects(lighting); + RwCullMode currentCullMode; + if (doubleSided) + { + RwRenderStateGet(rwRENDERSTATECULLMODE, ¤tCullMode); + RwRenderStateSet(rwRENDERSTATECULLMODE, RWRSTATE(rwCULLMODECULLNONE)); + } + if (pRwObject->type == RP_TYPE_ATOMIC) { RpAtomic* pRpAtomic = reinterpret_cast(pRwObject); @@ -59,6 +66,9 @@ void CRendererSA::RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, flo RpClumpRender(pClump); } + if (doubleSided) + RwRenderStateSet(rwRENDERSTATECULLMODE, RWRSTATE(currentCullMode)); + // Restore ambient light SetAmbientColours(); } diff --git a/Client/game_sa/CRendererSA.h b/Client/game_sa/CRendererSA.h index e055241deab..c89825568af 100644 --- a/Client/game_sa/CRendererSA.h +++ b/Client/game_sa/CRendererSA.h @@ -19,5 +19,5 @@ class CRendererSA : public CRenderer CRendererSA(); ~CRendererSA(); - void RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting) override; + void RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting, bool doubleSided) override; }; diff --git a/Client/mods/deathmatch/logic/CModelRenderer.cpp b/Client/mods/deathmatch/logic/CModelRenderer.cpp index 8983197e75e..2772a7b01af 100644 --- a/Client/mods/deathmatch/logic/CModelRenderer.cpp +++ b/Client/mods/deathmatch/logic/CModelRenderer.cpp @@ -13,14 +13,14 @@ #include "game\CRenderer.h" #include "game\CVisibilityPlugins.h" -bool CModelRenderer::EnqueueModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting) +bool CModelRenderer::EnqueueModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting, bool doubleSided) { if (g_pCore->IsWindowMinimized()) return false; if (pModelInfo && pModelInfo->IsLoaded()) { - m_Queue.emplace_back(pModelInfo, matrix, lighting); + m_Queue.emplace_back(pModelInfo, matrix, lighting, doubleSided); return true; } @@ -54,7 +54,7 @@ void CModelRenderer::Render() for (auto& modelDesc : m_Queue) { if (modelDesc.pModelInfo->IsLoaded() && !modelDesc.pModelInfo->GetIdeFlag(eModelIdeFlag::DRAW_LAST)) - pRenderer->RenderModel(modelDesc.pModelInfo, modelDesc.matrix, modelDesc.lighting); + pRenderer->RenderModel(modelDesc.pModelInfo, modelDesc.matrix, modelDesc.lighting, modelDesc.doubleSided); } m_Queue.clear(); @@ -68,5 +68,5 @@ void CModelRenderer::RenderEntity(SModelToRender* modelDesc, float distance) CRenderer* pRenderer = g_pGame->GetRenderer(); assert(pRenderer); - pRenderer->RenderModel(modelDesc->pModelInfo, modelDesc->matrix, modelDesc->lighting); + pRenderer->RenderModel(modelDesc->pModelInfo, modelDesc->matrix, modelDesc->lighting, modelDesc->doubleSided); } diff --git a/Client/mods/deathmatch/logic/CModelRenderer.h b/Client/mods/deathmatch/logic/CModelRenderer.h index 8272fcf34ce..9dcbcd6ef74 100644 --- a/Client/mods/deathmatch/logic/CModelRenderer.h +++ b/Client/mods/deathmatch/logic/CModelRenderer.h @@ -17,18 +17,20 @@ class CModelRenderer final struct SModelToRender final { CModelInfo* pModelInfo; - CMatrix matrix; - float lighting; + CMatrix matrix; + float lighting; + bool doubleSided; - SModelToRender(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting = 0.0f) : + SModelToRender(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting = 0.0f, bool doubleSided = false) : pModelInfo(pModelInfo), matrix(matrix), - lighting(lighting) + lighting(lighting), + doubleSided(doubleSided) { } }; - bool EnqueueModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting); + bool EnqueueModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting, bool doubleSided); void Update(); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp index dffc55fda11..88e28880807 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp @@ -2123,7 +2123,7 @@ bool CLuaDrawingDefs::DxDrawWiredSphere(lua_State* const luaVM, const CVector po return true; } -bool CLuaDrawingDefs::DxDrawModel3D(std::uint32_t modelID, CVector position, CVector rotation, const std::optional scale, const std::optional lighting) +bool CLuaDrawingDefs::DxDrawModel3D(std::uint32_t modelID, CVector position, CVector rotation, const std::optional scale, const std::optional lighting, std::optional doubleSided) { CModelInfo* pModelInfo = g_pGame->GetModelInfo(modelID); if (!pModelInfo) @@ -2138,5 +2138,5 @@ bool CLuaDrawingDefs::DxDrawModel3D(std::uint32_t modelID, CVector position, CVe ConvertDegreesToRadians(rotation); return g_pClientGame->GetModelRenderer()->EnqueueModel(pModelInfo, - CMatrix{position, rotation, scale.value_or(CVector{1.0f, 1.0f, 1.0f})}, lighting.value_or(0.0f)); + CMatrix{position, rotation, scale.value_or(CVector{1.0f, 1.0f, 1.0f})}, lighting.value_or(0.0f), doubleSided.value_or(false)); } diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h index 89278accd11..4b82c07d1cd 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h @@ -82,7 +82,7 @@ class CLuaDrawingDefs : public CLuaDefs static bool DxDrawWiredSphere(lua_State* const luaVM, const CVector position, const float radius, const std::optional color, const std::optional lineWidth, const std::optional iterations); - static bool DxDrawModel3D(std::uint32_t modelID, CVector position, CVector rotation, const std::optional scale, const std::optional lighting); + static bool DxDrawModel3D(std::uint32_t modelID, CVector position, CVector rotation, const std::optional scale, const std::optional lighting, std::optional doubleSided); private: static void AddDxMaterialClass(lua_State* luaVM); diff --git a/Client/sdk/game/CRenderer.h b/Client/sdk/game/CRenderer.h index 22c12c85400..da275b0410b 100644 --- a/Client/sdk/game/CRenderer.h +++ b/Client/sdk/game/CRenderer.h @@ -19,5 +19,5 @@ class CRenderer public: virtual ~CRenderer() {} - virtual void RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting) = 0; + virtual void RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix, float lighting, bool doubleSided) = 0; }; diff --git a/Client/sdk/game/RenderWare.h b/Client/sdk/game/RenderWare.h index d43099d0cc2..88eb610f72f 100644 --- a/Client/sdk/game/RenderWare.h +++ b/Client/sdk/game/RenderWare.h @@ -22,11 +22,19 @@ #define RWFORCEENUMSIZEINT ((std::int32_t)((~((std::uint32_t)0)) >> 1)) #endif #define RWPLUGINOFFSET(_type, _base, _offset) ((_type*)((std::uint8_t*)(_base) + (_offset))) +#define RWSRCGLOBAL(variable) ((*(RwGlobals**)0xC97B24)->variable) // 0xC97B24 = RwEngineInstance pointer +#define RWRSTATE(a) (reinterpret_cast(a)) #define RW_STRUCT_ALIGN ((int)((~((unsigned int)0))>>1)) #define RW_TEXTURE_NAME_LENGTH 32 #define RW_FRAME_NAME_LENGTH 23 #define RW_MAX_TEXTURE_COORDS 8 +#define RwRenderStateGet(_state, _value) RwRenderStateGetMacro(_state, _value) +#define RwRenderStateSet(_state, _value) RwRenderStateSetMacro(_state, _value) + +#define RwRenderStateGetMacro(_state, _value) (RWSRCGLOBAL(dOpenDevice).fpRenderStateGet(_state, _value)) +#define RwRenderStateSetMacro(_state, _value) (RWSRCGLOBAL(dOpenDevice).fpRenderStateSet(_state, _value)) + /* Type IDs */ #define RP_TYPE_ATOMIC 1 @@ -487,6 +495,177 @@ enum RwStreamMode STREAM_MODE_LAST = RW_STRUCT_ALIGN }; +enum RwRenderState +{ + rwRENDERSTATENARENDERSTATE = 0, + + rwRENDERSTATETEXTURERASTER, + /** Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: FALSE. + */ + rwRENDERSTATESTENCILFAIL, + /**<\ref RwStencilOperation used when the stencil test passes. + * Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: rwSTENCILOPERATIONKEEP. + */ + rwRENDERSTATESTENCILZFAIL, + /**<\ref RwStencilOperation used when the stencil test passes and + * the depth test (z-test) fails. + * Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: rwSTENCILOPERATIONKEEP. + */ + rwRENDERSTATESTENCILPASS, + /**<\ref RwStencilOperation used when both the stencil and the depth + * (z) tests pass. + * Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: rwSTENCILOPERATIONKEEP. + */ + rwRENDERSTATESTENCILFUNCTION, + /**<\ref RwStencilFunction for the stencil test. + * Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: rwSTENCILFUNCTIONALWAYS. + */ + rwRENDERSTATESTENCILFUNCTIONREF, + /** Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: 0. + */ + rwRENDERSTATESTENCILFUNCTIONMASK, + /** Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: 0xffffffff. + */ + rwRENDERSTATESTENCILFUNCTIONWRITEMASK, + /** Supported on Xbox, D3D8, D3D9, and OpenGL only. + * Default: 0xffffffff. + */ + rwRENDERSTATEALPHATESTFUNCTION, + /**<\ref RwAlphaTestFunction for the alpha test. When a pixel fails, + * neither the frame buffer nor the Z-buffer are updated. + * Default: rwALPHATESTFUNCTIONGREATER (GameCube, Xbox, D3D8, D3D9 + * and OpenGL). The default PS2 behaviour is to always update the + * frame buffer and update the Z-buffer only if a greater than or + * equal test passes. + */ + rwRENDERSTATEALPHATESTFUNCTIONREF, + /** Range is 0 to 255, mapped to the platform's actual range + * Default: 128 (PS2) 0 (GameCube, Xbox, D3D8, D3D9 and OpenGL). + */ + + rwRENDERSTATEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT +}; + +enum RwCullMode +{ + rwCULLMODENACULLMODE = 0, + + rwCULLMODECULLNONE, + /**