diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 5d4a830099..07ac611c09 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -145,6 +145,8 @@ CGameSA::CGameSA() m_pPlantManager = new CPlantManagerSA(); m_pBuildingRemoval = new CBuildingRemovalSA(); + m_pRenderer = std::make_unique(); + // Normal weapon types (WEAPONSKILL_STD) for (int i = 0; i < NUM_WeaponInfosStdSkill; i++) { diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index 976c1d5db0..cf4788d953 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -17,6 +17,7 @@ #include "CStreamingSA.h" #include "CCoverManagerSA.h" #include "CPlantManagerSA.h" +#include "CRendererSA.h" class CAnimBlendClumpDataSAInterface; class CObjectGroupPhysicalPropertiesSA; @@ -172,7 +173,8 @@ class CGameSA : public CGame CCoverManagerSA* GetCoverManager() const noexcept { return m_pCoverManager; }; CPlantManagerSA* GetPlantManager() const noexcept { return m_pPlantManager; }; CBuildingRemoval* GetBuildingRemoval() { return m_pBuildingRemoval; } - + CRenderer* GetRenderer() const noexcept override { return m_pRenderer.get(); } + CWeaponInfo* GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill = WEAPONSKILL_STD); CModelInfo* GetModelInfo(DWORD dwModelID, bool bCanBeInvalid = false); CObjectGroupPhysicalProperties* GetObjectGroupPhysicalProperties(unsigned char ucObjectGroup); @@ -346,6 +348,8 @@ class CGameSA : public CGame CPlantManagerSA* m_pPlantManager; CBuildingRemoval* m_pBuildingRemoval; + std::unique_ptr m_pRenderer; + CPad* m_pPad; CAERadioTrackManager* m_pCAERadioTrackManager; CAudioEngine* m_pAudioEngine; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index 483615d3e1..2db97a5245 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -2028,7 +2028,10 @@ void CModelInfoSA::RestoreAllObjectsPropertiesGroups() eModelInfoType CModelInfoSA::GetModelType() { - return ((eModelInfoType(*)())m_pInterface->VFTBL->GetModelType)(); + if (auto pInterface = GetInterface()) + return ((eModelInfoType(*)())pInterface->VFTBL->GetModelType)(); + + return eModelInfoType::UNKNOWN; } bool CModelInfoSA::IsTowableBy(CModelInfo* towingModel) diff --git a/Client/game_sa/CRendererSA.cpp b/Client/game_sa/CRendererSA.cpp new file mode 100644 index 0000000000..bad607d5ba --- /dev/null +++ b/Client/game_sa/CRendererSA.cpp @@ -0,0 +1,55 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CRendererSA.cpp + * PURPOSE: Game renderer class + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CRendererSA.h" +#include "CModelInfoSA.h" +#include "CMatrix.h" +#include "gamesa_renderware.h" + +CRendererSA::CRendererSA() +{ +} + +CRendererSA::~CRendererSA() +{ +} + +void CRendererSA::RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix) +{ + CBaseModelInfoSAInterface* pModelInfoSAInterface = pModelInfo->GetInterface(); + if (!pModelInfoSAInterface) + return; + + RwObject* pRwObject = pModelInfoSAInterface->pRwObject; + if (!pRwObject) + return; + + RwFrame* pFrame = RpGetFrame(pRwObject); + + static RwMatrix rwMatrix; + rwMatrix.right = (RwV3d&)matrix.vRight; + rwMatrix.up = (RwV3d&)matrix.vFront; + rwMatrix.at = (RwV3d&)matrix.vUp; + rwMatrix.pos = (RwV3d&)matrix.vPos; + RwFrameTransform(pFrame, &rwMatrix, rwCOMBINEREPLACE); + + if (pRwObject->type == RP_TYPE_ATOMIC) + { + RpAtomic* pRpAtomic = reinterpret_cast(pRwObject); + pRpAtomic->renderCallback(reinterpret_cast(pRwObject)); + } + else + { + RpClump* pClump = reinterpret_cast(pRwObject); + RpClumpRender(pClump); + } +} diff --git a/Client/game_sa/CRendererSA.h b/Client/game_sa/CRendererSA.h new file mode 100644 index 0000000000..e71a83665e --- /dev/null +++ b/Client/game_sa/CRendererSA.h @@ -0,0 +1,23 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CRendererSA.h + * PURPOSE: Game renderer class + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include + +class CRendererSA : public CRenderer +{ +public: + CRendererSA(); + ~CRendererSA(); + + void RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix) override; +}; diff --git a/Client/game_sa/CVisibilityPluginsSA.cpp b/Client/game_sa/CVisibilityPluginsSA.cpp index d7cf9849bc..b5fe2d92c6 100644 --- a/Client/game_sa/CVisibilityPluginsSA.cpp +++ b/Client/game_sa/CVisibilityPluginsSA.cpp @@ -12,6 +12,8 @@ #include "StdInc.h" #include "CVisibilityPluginsSA.h" +#define FUNC_CVisibilityPlugins_InsertEntityIntoEntityList 0x733DD0 + void CVisibilityPluginsSA::SetClumpAlpha(RpClump* pClump, int iAlpha) { DWORD dwFunc = FUNC_CVisiblityPlugins_SetClumpAlpha; @@ -51,3 +53,8 @@ int CVisibilityPluginsSA::GetAtomicId(RwObject* pAtomic) } return iResult; } + +bool CVisibilityPluginsSA::InsertEntityIntoEntityList(void* entity, float distance, void* callback) +{ + return ((bool(_cdecl*)(void*, float, void*))FUNC_CVisibilityPlugins_InsertEntityIntoEntityList)(entity, distance, callback); +} diff --git a/Client/game_sa/CVisibilityPluginsSA.h b/Client/game_sa/CVisibilityPluginsSA.h index 57cab620c0..f4a583bcf2 100644 --- a/Client/game_sa/CVisibilityPluginsSA.h +++ b/Client/game_sa/CVisibilityPluginsSA.h @@ -21,4 +21,6 @@ class CVisibilityPluginsSA : public CVisibilityPlugins public: void SetClumpAlpha(RpClump* pClump, int iAlpha); int GetAtomicId(RwObject* pAtomic); + + bool InsertEntityIntoEntityList(void* entity, float distance, void* callback); }; diff --git a/Client/game_sa/gamesa_renderware.h b/Client/game_sa/gamesa_renderware.h index e2f2d9a472..594c203b59 100644 --- a/Client/game_sa/gamesa_renderware.h +++ b/Client/game_sa/gamesa_renderware.h @@ -38,6 +38,7 @@ typedef RwFrame*(__cdecl* RwFrameAddChild_t)(RwFrame* parent, RwFrame* child); typedef RwFrame*(__cdecl* RwFrameRemoveChild_t)(RwFrame* child); typedef RwFrame*(__cdecl* RwFrameForAllObjects_t)(RwFrame* frame, void* callback, void* data); typedef RwFrame*(__cdecl* RwFrameTranslate_t)(RwFrame* frame, const RwV3d* v, RwTransformOrder order); +typedef RwFrame*(__cdecl* RwFrameTransform_t)(RwFrame* frame, const RwMatrix* m, RwOpCombineType combine); typedef RwFrame*(__cdecl* RwFrameScale_t)(RwFrame* frame, const RwV3d* v, RwTransformOrder order); typedef RwFrame*(__cdecl* RwFrameUpdateObjects_t)(RwFrame*); typedef RwFrame*(__cdecl* RwFrameCreate_t)(); @@ -69,6 +70,7 @@ typedef RwTexture*(__cdecl* RwTexDictionaryAddTexture_t)(RwTexDictionary* dict, typedef RwTexDictionary*(__cdecl* RwTexDictionaryGetCurrent_t)(); typedef RwTexture*(__cdecl* RwTexDictionaryFindNamedTexture_t)(RwTexDictionary* dict, const char* name); typedef void(__cdecl* RpPrtStdGlobalDataSetStreamEmbedded_t)(void* value); +typedef RpClump*(__cdecl* RpClumpRender_t)(RpClump* clump); typedef RpWorld*(__cdecl* RpWorldAddAtomic_t)(RpWorld* world, RpAtomic* atomic); typedef RpWorld*(__cdecl* RpWorldAddClump_t)(RpWorld* world, RpClump* clump); typedef RpWorld*(__cdecl* RpWorldAddLight_t)(RpWorld* world, RpLight* light); @@ -125,6 +127,7 @@ RWFUNC(RwStreamSkip_t RwStreamSkip, (RwStreamSkip_t)0xDEAD) RWFUNC(RpClumpDestroy_t RpClumpDestroy, (RpClumpDestroy_t)0xDEAD) RWFUNC(RpClumpGetNumAtomics_t RpClumpGetNumAtomics, (RpClumpGetNumAtomics_t)0xDEAD) RWFUNC(RwFrameTranslate_t RwFrameTranslate, (RwFrameTranslate_t)0xDEAD) +RWFUNC(RwFrameTransform_t RwFrameTransform, (RwFrameTransform_t)0xDEAD) RWFUNC(RpClumpForAllAtomics_t RpClumpForAllAtomics, (RpClumpForAllAtomics_t)0xDEAD) RWFUNC(RwFrameAddChild_t RwFrameAddChild, (RwFrameAddChild_t)0xDEAD) RWFUNC(RpClumpAddAtomic_t RpClumpAddAtomic, (RpClumpAddAtomic_t)0xDEAD) @@ -138,6 +141,7 @@ RWFUNC(RwTexDictionaryAddTexture_t RwTexDictionaryAddTexture, (RwTexDictionaryAd RWFUNC(RwTexDictionaryStreamWrite_t RwTexDictionaryStreamWrite, (RwTexDictionaryStreamWrite_t)0xDEAD) RWFUNC(rwD3D9NativeTextureRead_t rwD3D9NativeTextureRead, (rwD3D9NativeTextureRead_t)0xDEAD) RWFUNC(RpPrtStdGlobalDataSetStreamEmbedded_t RpPrtStdGlobalDataSetStreamEmbedded, (RpPrtStdGlobalDataSetStreamEmbedded_t)0xDEAD) +RWFUNC(RpClumpRender_t RpClumpRender, (RpClumpRender_t)0xDEAD) RWFUNC(RpClumpRemoveAtomic_t RpClumpRemoveAtomic, (RpClumpRemoveAtomic_t)0xDEAD) RWFUNC(RpAtomicClone_t RpAtomicClone, (RpAtomicClone_t)0xDEAD) RWFUNC(RwTexDictionaryFindNamedTexture_t RwTexDictionaryFindNamedTexture, (RwTexDictionaryFindNamedTexture_t)0xDEAD) diff --git a/Client/game_sa/gamesa_renderware.hpp b/Client/game_sa/gamesa_renderware.hpp index 804040c802..a638cfede0 100644 --- a/Client/game_sa/gamesa_renderware.hpp +++ b/Client/game_sa/gamesa_renderware.hpp @@ -20,6 +20,7 @@ void InitRwFunctions() RwStreamSkip = (RwStreamSkip_t)0x007ECD00; RpClumpDestroy = (RpClumpDestroy_t)0x0074A310; RpClumpGetNumAtomics = (RpClumpGetNumAtomics_t)0x007498E0; + RwFrameTransform = (RwFrameTransform_t)0x007F0F70; RwFrameTranslate = (RwFrameTranslate_t)0x007F0E30; RpClumpForAllAtomics = (RpClumpForAllAtomics_t)0x00749B70; RwFrameAddChild = (RwFrameAddChild_t)0x007F0B00; @@ -34,6 +35,7 @@ void InitRwFunctions() RwTexDictionaryStreamWrite = (RwTexDictionaryStreamWrite_t)0x008049F0; rwD3D9NativeTextureRead = (rwD3D9NativeTextureRead_t)0x004CD820; RpPrtStdGlobalDataSetStreamEmbedded = (RpPrtStdGlobalDataSetStreamEmbedded_t)0x0041B350; + RpClumpRender = (RpClumpRender_t)0x00749B20; RpClumpRemoveAtomic = (RpClumpRemoveAtomic_t)0x0074A4C0; RpAtomicClone = (RpAtomicClone_t)0x00749E60; RwTexDictionaryFindNamedTexture = (RwTexDictionaryFindNamedTexture_t)0x007F39F0; diff --git a/Client/mods/deathmatch/StdInc.h b/Client/mods/deathmatch/StdInc.h index 68b18a6ab5..465478454f 100644 --- a/Client/mods/deathmatch/StdInc.h +++ b/Client/mods/deathmatch/StdInc.h @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 7b57fe13e1..df20bf6eaa 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -251,6 +251,9 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) // Singular file download manager m_pSingularFileDownloadManager = new CSingularFileDownloadManager(); + // 3D model renderer + m_pModelRenderer = std::make_unique(); + // Register the message and the net packet handler g_pMultiplayer->SetPreWeaponFireHandler(CClientGame::PreWeaponFire); g_pMultiplayer->SetPostWeaponFireHandler(CClientGame::PostWeaponFire); @@ -267,6 +270,7 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) g_pMultiplayer->SetRender3DStuffHandler(CClientGame::StaticRender3DStuffHandler); g_pMultiplayer->SetPreRenderSkyHandler(CClientGame::StaticPreRenderSkyHandler); g_pMultiplayer->SetRenderHeliLightHandler(CClientGame::StaticRenderHeliLightHandler); + g_pMultiplayer->SetRenderEverythingBarRoadsHandler(CClientGame::StaticRenderEverythingBarRoadsHandler); g_pMultiplayer->SetChokingHandler(CClientGame::StaticChokingHandler); g_pMultiplayer->SetPreWorldProcessHandler(CClientGame::StaticPreWorldProcessHandler); g_pMultiplayer->SetPostWorldProcessHandler(CClientGame::StaticPostWorldProcessHandler); @@ -470,6 +474,7 @@ CClientGame::~CClientGame() g_pMultiplayer->SetRender3DStuffHandler(NULL); g_pMultiplayer->SetPreRenderSkyHandler(NULL); g_pMultiplayer->SetRenderHeliLightHandler(nullptr); + g_pMultiplayer->SetRenderEverythingBarRoadsHandler(nullptr); g_pMultiplayer->SetChokingHandler(NULL); g_pMultiplayer->SetPreWorldProcessHandler(NULL); g_pMultiplayer->SetPostWorldProcessHandler(NULL); @@ -3546,6 +3551,11 @@ void CClientGame::StaticRenderHeliLightHandler() g_pClientGame->GetManager()->GetPointLightsManager()->RenderHeliLightHandler(); } +void CClientGame::StaticRenderEverythingBarRoadsHandler() +{ + g_pClientGame->GetModelRenderer()->Render(); +} + bool CClientGame::StaticChokingHandler(unsigned char ucWeaponType) { return g_pClientGame->ChokingHandler(ucWeaponType); @@ -3853,6 +3863,8 @@ void CClientGame::PostWorldProcessPedsAfterPreRenderHandler() { CLuaArguments Arguments; m_pRootEntity->CallEvent("onClientPedsProcessed", Arguments, false); + + g_pClientGame->GetModelRenderer()->Update(); } void CClientGame::IdleHandler() diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index f2c290d94c..97f7e08dab 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -308,6 +308,8 @@ class CClientGame CRemoteCalls* GetRemoteCalls() { return m_pRemoteCalls; } CResourceFileDownloadManager* GetResourceFileDownloadManager() { return m_pResourceFileDownloadManager; } + CModelRenderer* GetModelRenderer() const noexcept { return m_pModelRenderer.get(); } + SharedUtil::CAsyncTaskScheduler* GetAsyncTaskScheduler() { return m_pAsyncTaskScheduler; } // Status toggles @@ -504,6 +506,7 @@ class CClientGame static void StaticRender3DStuffHandler(); static void StaticPreRenderSkyHandler(); static void StaticRenderHeliLightHandler(); + static void StaticRenderEverythingBarRoadsHandler(); static bool StaticChokingHandler(unsigned char ucWeaponType); static void StaticPreWorldProcessHandler(); static void StaticPostWorldProcessHandler(); @@ -698,6 +701,8 @@ class CClientGame CRemoteCalls* m_pRemoteCalls; CResourceFileDownloadManager* m_pResourceFileDownloadManager; + std::unique_ptr m_pModelRenderer; + // Revised facilities CServer m_Server; diff --git a/Client/mods/deathmatch/logic/CModelRenderer.cpp b/Client/mods/deathmatch/logic/CModelRenderer.cpp new file mode 100644 index 0000000000..2f06c836ec --- /dev/null +++ b/Client/mods/deathmatch/logic/CModelRenderer.cpp @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: mods/deathmatch/logic/CModelRenderer.cpp + * PURPOSE: 3D models renderer + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "game\CRenderer.h" +#include "game\CVisibilityPlugins.h" + +bool CModelRenderer::EnqueueModel(CModelInfo* pModelInfo, const CMatrix& matrix) +{ + if (g_pCore->IsWindowMinimized()) + return false; + + if (pModelInfo && pModelInfo->IsLoaded()) + { + m_Queue.emplace_back(pModelInfo, matrix); + return true; + } + + return false; +} + +void CModelRenderer::Update() +{ + CVisibilityPlugins* pVisibilityPlugins = g_pGame->GetVisibilityPlugins(); + assert(pVisibilityPlugins); + + for (auto& modelDesc : m_Queue) + { + // Insert transparent entities into a sorted list + if (modelDesc.pModelInfo->GetIdeFlag(eModelIdeFlag::DRAW_LAST)) + { + const CVector& vecCameraPosition = *(CVector*)0xB76870; // CRenderer::ms_vecCameraPosition + const float fDistance = (modelDesc.matrix.GetPosition() - vecCameraPosition).Length(); + + pVisibilityPlugins->InsertEntityIntoEntityList(&modelDesc, fDistance, RenderEntity); + } + } +} + +void CModelRenderer::Render() +{ + CRenderer* pRenderer = g_pGame->GetRenderer(); + assert(pRenderer); + + // Draw opaque entities + for (auto& modelDesc : m_Queue) + { + if (modelDesc.pModelInfo->IsLoaded() && !modelDesc.pModelInfo->GetIdeFlag(eModelIdeFlag::DRAW_LAST)) + pRenderer->RenderModel(modelDesc.pModelInfo, modelDesc.matrix); + } + + m_Queue.clear(); +} + +void CModelRenderer::RenderEntity(SModelToRender* modelDesc, float distance) +{ + if (!modelDesc->pModelInfo->IsLoaded()) + return; + + CRenderer* pRenderer = g_pGame->GetRenderer(); + assert(pRenderer); + + pRenderer->RenderModel(modelDesc->pModelInfo, modelDesc->matrix); +} diff --git a/Client/mods/deathmatch/logic/CModelRenderer.h b/Client/mods/deathmatch/logic/CModelRenderer.h new file mode 100644 index 0000000000..d923db6c7f --- /dev/null +++ b/Client/mods/deathmatch/logic/CModelRenderer.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: mods/deathmatch/logic/CModelRenderer.h + * PURPOSE: 3D models renderer + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +class CModelRenderer final +{ +public: + struct SModelToRender final + { + CModelInfo* pModelInfo; + CMatrix matrix; + + SModelToRender(CModelInfo* pModelInfo, const CMatrix& matrix) : + pModelInfo(pModelInfo), + matrix(matrix) + { + } + }; + + bool EnqueueModel(CModelInfo* pModelInfo, const CMatrix& matrix); + + void Update(); + + void Render(); + + static void RenderEntity(SModelToRender* entity, float distance); + +private: + + std::vector m_Queue; +}; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp index e30b7f3ba2..f54378944d 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp @@ -36,6 +36,7 @@ void CLuaDrawingDefs::LoadFunctions() {"dxDrawMaterialPrimitive", DxDrawMaterialPrimitive}, {"dxDrawMaterialPrimitive3D", DxDrawMaterialPrimitive3D}, {"dxDrawWiredSphere", ArgumentParser}, + {"dxDrawModel3D", ArgumentParser}, {"dxGetTextWidth", DxGetTextWidth}, {"dxGetTextSize", ArgumentParser}, {"dxGetFontHeight", DxGetFontHeight}, @@ -2121,3 +2122,21 @@ bool CLuaDrawingDefs::DxDrawWiredSphere(lua_State* const luaVM, const CVector po g_pCore->GetGraphics()->DrawWiredSphere(position, radius, color.value(), lineWidth.value_or(1), iterations.value_or(1)); return true; } + +bool CLuaDrawingDefs::DxDrawModel3D(std::uint32_t modelID, CVector position, CVector rotation, const std::optional scale) +{ + CModelInfo* pModelInfo = g_pGame->GetModelInfo(modelID); + if (!pModelInfo) + throw std::invalid_argument("Invalid model ID"); + + if (auto modelType = pModelInfo->GetModelType(); + modelType == eModelInfoType::UNKNOWN || modelType == eModelInfoType::VEHICLE || modelType == eModelInfoType::PED) + { + throw std::invalid_argument("Invalid model type"); + } + + ConvertDegreesToRadians(rotation); + + return g_pClientGame->GetModelRenderer()->EnqueueModel(pModelInfo, + CMatrix{position, rotation, scale.value_or(CVector{1.0f, 1.0f, 1.0f})}); +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h index 0bda34f5e9..55dc3adda1 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h @@ -82,6 +82,8 @@ 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); + private: static void AddDxMaterialClass(lua_State* luaVM); static void AddDxTextureClass(lua_State* luaVM); diff --git a/Client/multiplayer_sa/CMultiplayerSA.h b/Client/multiplayer_sa/CMultiplayerSA.h index f725f37b63..802b9b56ea 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.h +++ b/Client/multiplayer_sa/CMultiplayerSA.h @@ -268,6 +268,7 @@ class CMultiplayerSA : public CMultiplayer void SetRender3DStuffHandler(Render3DStuffHandler* pHandler); void SetPreRenderSkyHandler(PreRenderSkyHandler* pHandler); void SetRenderHeliLightHandler(RenderHeliLightHandler* pHandler); + void SetRenderEverythingBarRoadsHandler(RenderEverythingBarRoadsHandler* pHandler) override; void Reset(); diff --git a/Client/multiplayer_sa/CMultiplayerSA_Rendering.cpp b/Client/multiplayer_sa/CMultiplayerSA_Rendering.cpp index 03a27688d2..b346f25874 100644 --- a/Client/multiplayer_sa/CMultiplayerSA_Rendering.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA_Rendering.cpp @@ -13,6 +13,7 @@ extern CCoreInterface* g_pCore; GameEntityRenderHandler* pGameEntityRenderHandler = nullptr; PreRenderSkyHandler* pPreRenderSkyHandlerHandler = nullptr; RenderHeliLightHandler* pRenderHeliLightHandler = nullptr; +RenderEverythingBarRoadsHandler* pRenderEverythingBarRoadsHandler = nullptr; #define VAR_CCullZones_NumMirrorAttributeZones 0x0C87AC4 // int #define VAR_CMirrors_d3dRestored 0x0C7C729 // uchar @@ -581,6 +582,17 @@ void CMultiplayerSA::SetRenderHeliLightHandler(RenderHeliLightHandler* pHandler) pRenderHeliLightHandler = pHandler; } +////////////////////////////////////////////////////////////////////////////////////////// +// +// CMultiplayerSA::SetRenderEverythingBarRoadsHandler +// +// +////////////////////////////////////////////////////////////////////////////////////////// +void CMultiplayerSA::SetRenderEverythingBarRoadsHandler(RenderEverythingBarRoadsHandler* pHandler) +{ + pRenderEverythingBarRoadsHandler = pHandler; +} + ////////////////////////////////////////////////////////////////////////////////////////// // // CMultiplayerSA::SetIsMinimizedAndNotConnected @@ -703,6 +715,30 @@ void _declspec(naked) HOOK_CVisibilityPlugins_RenderPedCB() } } +// Hook info +#define HOOKPOS_CRenderer_EverythingBarRoads 0x553C78 +#define HOOKSIZE_CRenderer_EverythingBarRoads 5 +DWORD RETURN_CRenderer_EverythingBarRoads = 0x553C7D; +DWORD DO_CRenderer_EverythingBarRoads = 0x7EE180; +void _declspec(naked) HOOK_CRenderer_EverythingBarRoads() +{ + _asm + { + pushad + } + + if (pRenderEverythingBarRoadsHandler) + pRenderEverythingBarRoadsHandler(); + + _asm + { + popad + call DO_CRenderer_EverythingBarRoads + jmp RETURN_CRenderer_EverythingBarRoads + + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // // CMultiplayerSA::InitHooks_Rendering @@ -726,4 +762,5 @@ void CMultiplayerSA::InitHooks_Rendering() EZHookInstallChecked(CClouds_RenderSkyPolys); EZHookInstallChecked(RwCameraSetNearClipPlane); EZHookInstall(RenderEffects_HeliLight); + EZHookInstall(CRenderer_EverythingBarRoads); } diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index a1d792813e..2314fdad0e 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -68,6 +68,7 @@ class CWeather; class CWorld; class CIplStore; class CBuildingRemoval; +class CRenderer; enum eEntityType; enum ePedPieceTypes; @@ -149,6 +150,7 @@ class __declspec(novtable) CGame virtual CPointLights* GetPointLights() = 0; virtual CColStore* GetCollisionStore() = 0; virtual CBuildingRemoval* GetBuildingRemoval() = 0; + virtual CRenderer* GetRenderer() const noexcept = 0; virtual CWeaponInfo* GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill = WEAPONSKILL_STD) = 0; virtual CModelInfo* GetModelInfo(DWORD dwModelID, bool bCanBeInvalid = false) = 0; diff --git a/Client/sdk/game/CModelInfo.h b/Client/sdk/game/CModelInfo.h index af9fa1bdf3..08cb032e4c 100644 --- a/Client/sdk/game/CModelInfo.h +++ b/Client/sdk/game/CModelInfo.h @@ -60,6 +60,7 @@ enum class eModelInfoType : unsigned char VEHICLE = 6, PED = 7, LOD_ATOMIC = 8, + UNKNOWN = 9 }; enum eVehicleUpgradePosn diff --git a/Client/sdk/game/CRenderer.h b/Client/sdk/game/CRenderer.h new file mode 100644 index 0000000000..65d6a8bdca --- /dev/null +++ b/Client/sdk/game/CRenderer.h @@ -0,0 +1,23 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: sdk/game/CRenderer.h + * PURPOSE: Renderer interface + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +class CModelInfo; +class CMatrix; + +class CRenderer +{ +public: + virtual ~CRenderer() {} + + virtual void RenderModel(CModelInfo* pModelInfo, const CMatrix& matrix) = 0; +}; diff --git a/Client/sdk/game/CVisibilityPlugins.h b/Client/sdk/game/CVisibilityPlugins.h index 1d8d1b47cc..f2e948f65a 100644 --- a/Client/sdk/game/CVisibilityPlugins.h +++ b/Client/sdk/game/CVisibilityPlugins.h @@ -22,4 +22,6 @@ class CVisibilityPlugins public: virtual void SetClumpAlpha(RpClump* pClump, int iAlpha) = 0; virtual int GetAtomicId(RwObject* pAtomic) = 0; + + virtual bool InsertEntityIntoEntityList(void* entity, float distance, void* callback) = 0; }; diff --git a/Client/sdk/multiplayer/CMultiplayer.h b/Client/sdk/multiplayer/CMultiplayer.h index c8b043a37f..02c932cf57 100644 --- a/Client/sdk/multiplayer/CMultiplayer.h +++ b/Client/sdk/multiplayer/CMultiplayer.h @@ -104,6 +104,7 @@ typedef void(IdleHandler)(); typedef void(PreFxRenderHandler)(); typedef void(PostColorFilterRenderHandler)(); typedef void(PreHudRenderHandler)(); +typedef void(RenderEverythingBarRoadsHandler)(); typedef CAnimBlendAssociationSAInterface*(AddAnimationHandler)(RpClump* pClump, AssocGroupId animGroup, AnimationId animID); typedef CAnimBlendAssociationSAInterface*(AddAnimationAndSyncHandler)(RpClump* pClump, CAnimBlendAssociationSAInterface* pAnimAssocToSyncWith, AssocGroupId animGroup, AnimationId animID); @@ -385,6 +386,7 @@ class CMultiplayer virtual void SetRender3DStuffHandler(Render3DStuffHandler* pHandler) = 0; virtual void SetPreRenderSkyHandler(PreRenderSkyHandler* pHandler) = 0; virtual void SetRenderHeliLightHandler(RenderHeliLightHandler* pHandler) = 0; + virtual void SetRenderEverythingBarRoadsHandler(RenderEverythingBarRoadsHandler* pHandler) = 0; virtual void Reset() = 0;