diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index dc09e8edd73..5cf54f2242e 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -1858,6 +1858,10 @@ void CCore::OnDeviceRestore() void CCore::OnPreFxRender() { // Don't do nothing if nothing won't be drawn + + if (CGraphics::GetSingleton().HasPrimitive3DPreGUIQueueItems()) + CGraphics::GetSingleton().DrawPrimitive3DPreGUIQueue(); + if (!CGraphics::GetSingleton().HasLine3DPreGUIQueueItems()) return; diff --git a/Client/core/Graphics/CGraphics.cpp b/Client/core/Graphics/CGraphics.cpp index ce910031676..be132b74d94 100644 --- a/Client/core/Graphics/CGraphics.cpp +++ b/Client/core/Graphics/CGraphics.cpp @@ -15,6 +15,8 @@ #include "CMaterialLine3DBatcher.h" #include "CPrimitiveBatcher.h" #include "CPrimitiveMaterialBatcher.h" +#include "CPrimitive3DBatcher.h" +#include "CMaterialPrimitive3DBatcher.h" #include "CAspectRatioConverter.h" extern CCore* g_pCore; extern bool g_bInGTAScene; @@ -58,6 +60,10 @@ CGraphics::CGraphics(CLocalGUI* pGUI) m_pLine3DBatcherPostGUI = new CLine3DBatcher(false); m_pMaterialLine3DBatcherPreGUI = new CMaterialLine3DBatcher(true); m_pMaterialLine3DBatcherPostGUI = new CMaterialLine3DBatcher(false); + m_pPrimitive3DBatcherPreGUI = new CPrimitive3DBatcher(true); + m_pPrimitive3DBatcherPostGUI = new CPrimitive3DBatcher(false); + m_pMaterialPrimitive3DBatcherPreGUI = new CMaterialPrimitive3DBatcher(true, this); + m_pMaterialPrimitive3DBatcherPostGUI = new CMaterialPrimitive3DBatcher(false, this); m_pPrimitiveBatcher = new CPrimitiveBatcher(); m_pPrimitiveMaterialBatcher = new CPrimitiveMaterialBatcher(this); @@ -84,6 +90,10 @@ CGraphics::~CGraphics() SAFE_DELETE(m_pMaterialLine3DBatcherPostGUI); SAFE_DELETE(m_pPrimitiveBatcher); SAFE_DELETE(m_pPrimitiveMaterialBatcher); + SAFE_DELETE(m_pPrimitive3DBatcherPreGUI); + SAFE_DELETE(m_pPrimitive3DBatcherPostGUI); + SAFE_DELETE(m_pMaterialPrimitive3DBatcherPreGUI); + SAFE_DELETE(m_pMaterialPrimitive3DBatcherPostGUI); SAFE_DELETE(m_pScreenGrabber); SAFE_DELETE(m_pPixelsManager); SAFE_DELETE(m_pAspectRatioConverter); @@ -898,6 +908,44 @@ void CGraphics::DrawPrimitiveQueued(std::vector* pVecVertices, AddQueueItem(Item, bPostGUI); } +void CGraphics::DrawPrimitive3DQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, bool bPostGUI) +{ + // Prevent queuing when minimized + if (g_pCore->IsWindowMinimized()) + { + delete pVecVertices; + return; + } + + // Add it to the queue + if (bPostGUI && !CCore::GetSingleton().IsMenuVisible()) + m_pPrimitive3DBatcherPostGUI->AddPrimitive(eType, pVecVertices); + else + m_pPrimitive3DBatcherPreGUI->AddPrimitive(eType, pVecVertices); +} + +void CGraphics::DrawMaterialPrimitive3DQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, bool bPostGUI) +{ + // Prevent queuing when minimized + if (g_pCore->IsWindowMinimized()) + { + delete pVecVertices; + return; + } + + if (CShaderItem* pShaderItem = DynamicCast(pMaterial)) + { + // If material is a shader, use its current instance + pMaterial = pShaderItem->m_pShaderInstance; + } + + // Add it to the queue + if (bPostGUI && !CCore::GetSingleton().IsMenuVisible()) + m_pMaterialPrimitive3DBatcherPostGUI->AddPrimitive(eType, pMaterial, pVecVertices); + else + m_pMaterialPrimitive3DBatcherPreGUI->AddPrimitive(eType, pMaterial, pVecVertices); +} + void CGraphics::DrawMaterialPrimitiveQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, bool bPostGUI) { @@ -1437,7 +1485,10 @@ void CGraphics::OnDeviceCreate(IDirect3DDevice9* pDevice) m_pMaterialLine3DBatcherPreGUI->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); m_pMaterialLine3DBatcherPostGUI->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); m_pPrimitiveBatcher->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); - m_pPrimitiveMaterialBatcher->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); + m_pPrimitive3DBatcherPreGUI->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); + m_pPrimitive3DBatcherPostGUI->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); + m_pMaterialPrimitive3DBatcherPreGUI->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); + m_pMaterialPrimitive3DBatcherPostGUI->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); m_pRenderItemManager->OnDeviceCreate(pDevice, GetViewportWidth(), GetViewportHeight()); m_pScreenGrabber->OnDeviceCreate(pDevice); m_pPixelsManager->OnDeviceCreate(pDevice); @@ -1513,6 +1564,8 @@ void CGraphics::DrawPostGUIQueue() DrawQueue(m_PostGUIQueue); m_pLine3DBatcherPostGUI->Flush(); m_pMaterialLine3DBatcherPostGUI->Flush(); + m_pPrimitive3DBatcherPostGUI->Flush(); + m_pMaterialPrimitive3DBatcherPostGUI->Flush(); // Both queues should be empty now, and there should be no outstanding refs assert(m_PreGUIQueue.empty() && m_iDebugQueueRefs == 0); @@ -1524,11 +1577,22 @@ void CGraphics::DrawLine3DPreGUIQueue() m_pMaterialLine3DBatcherPreGUI->Flush(); } -bool CGraphics::HasLine3DPreGUIQueueItems() +void CGraphics::DrawPrimitive3DPreGUIQueue(void) +{ + m_pPrimitive3DBatcherPreGUI->Flush(); + m_pMaterialPrimitive3DBatcherPreGUI->Flush(); +} + +bool CGraphics::HasLine3DPreGUIQueueItems(void) { return m_pLine3DBatcherPreGUI->HasItems() || m_pMaterialLine3DBatcherPreGUI->HasItems(); } +bool CGraphics::HasPrimitive3DPreGUIQueueItems(void) +{ + return m_pMaterialPrimitive3DBatcherPreGUI->HasItems() || m_pPrimitive3DBatcherPreGUI->HasItems(); +} + void CGraphics::DrawQueue(std::vector& Queue) { BeginDrawBatch(); diff --git a/Client/core/Graphics/CGraphics.h b/Client/core/Graphics/CGraphics.h index 8acb0387143..1a518d1ce7a 100644 --- a/Client/core/Graphics/CGraphics.h +++ b/Client/core/Graphics/CGraphics.h @@ -28,6 +28,8 @@ class CLine3DBatcher; class CMaterialLine3DBatcher; class CPrimitiveBatcher; class CPrimitiveMaterialBatcher; +class CPrimitive3DBatcher; +class CMaterialPrimitive3DBatcher; class CAspectRatioConverter; struct IDirect3DDevice9; struct IDirect3DSurface9; @@ -65,6 +67,7 @@ class CGraphics : public CGraphicsInterface, public CSingleton { friend class CDirect3DEvents9; friend CPrimitiveMaterialBatcher; + friend CMaterialPrimitive3DBatcher; public: ZERO_ON_NEW @@ -147,6 +150,10 @@ class CGraphics : public CGraphicsInterface, public CSingleton void DrawPrimitiveQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, bool bPostGUI = false); void DrawMaterialPrimitiveQueued(std::vector* vertices, D3DPRIMITIVETYPE type, CMaterialItem* pMaterial, bool bPostGUI); + + void DrawPrimitive3DQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, bool bPostGUI); + void DrawMaterialPrimitive3DQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, bool bPostGUI); + void DrawCircleQueued(float fX, float fY, float fRadius, float fStartAngle, float fStopAngle, unsigned long ulColor, unsigned long ulColorCenter, short siSegments, float fRatio, bool bPostGUI); @@ -174,10 +181,12 @@ class CGraphics : public CGraphicsInterface, public CSingleton bool CopyDataFromSurface(IDirect3DSurface9* pSurface, CBuffer& outBuffer); // To draw queued up drawings - void DrawPreGUIQueue(); - void DrawPostGUIQueue(); - void DrawLine3DPreGUIQueue(); - bool HasLine3DPreGUIQueueItems(); + void DrawPreGUIQueue(void); + void DrawPostGUIQueue(void); + void DrawLine3DPreGUIQueue(void); + bool HasLine3DPreGUIQueueItems(void); + void DrawPrimitive3DPreGUIQueue(void); + bool HasPrimitive3DPreGUIQueueItems(void); void DidRenderScene(); void SetProgressMessage(const SString& strMessage); @@ -207,17 +216,21 @@ class CGraphics : public CGraphicsInterface, public CSingleton IDirect3DDevice9* m_pDevice; - CRenderItemManager* m_pRenderItemManager; - CScreenGrabberInterface* m_pScreenGrabber; - CPixelsManagerInterface* m_pPixelsManager; - CTileBatcher* m_pTileBatcher; - CLine3DBatcher* m_pLine3DBatcherPreGUI; - CLine3DBatcher* m_pLine3DBatcherPostGUI; - CMaterialLine3DBatcher* m_pMaterialLine3DBatcherPreGUI; - CMaterialLine3DBatcher* m_pMaterialLine3DBatcherPostGUI; - CPrimitiveBatcher* m_pPrimitiveBatcher; - CPrimitiveMaterialBatcher* m_pPrimitiveMaterialBatcher; - CAspectRatioConverter* m_pAspectRatioConverter; + CRenderItemManager* m_pRenderItemManager; + CScreenGrabberInterface* m_pScreenGrabber; + CPixelsManagerInterface* m_pPixelsManager; + CTileBatcher* m_pTileBatcher; + CLine3DBatcher* m_pLine3DBatcherPreGUI; + CLine3DBatcher* m_pLine3DBatcherPostGUI; + CMaterialLine3DBatcher* m_pMaterialLine3DBatcherPreGUI; + CMaterialLine3DBatcher* m_pMaterialLine3DBatcherPostGUI; + CPrimitiveBatcher* m_pPrimitiveBatcher; + CPrimitiveMaterialBatcher* m_pPrimitiveMaterialBatcher; + CPrimitive3DBatcher* m_pPrimitive3DBatcherPreGUI; + CPrimitive3DBatcher* m_pPrimitive3DBatcherPostGUI; + CMaterialPrimitive3DBatcher* m_pMaterialPrimitive3DBatcherPreGUI; + CMaterialPrimitive3DBatcher* m_pMaterialPrimitive3DBatcherPostGUI; + CAspectRatioConverter* m_pAspectRatioConverter; // Fonts ID3DXFont* m_pDXFonts[NUM_FONTS]; diff --git a/Client/core/Graphics/CMaterialPrimitive3DBatcher.cpp b/Client/core/Graphics/CMaterialPrimitive3DBatcher.cpp new file mode 100644 index 00000000000..5ef73b65edb --- /dev/null +++ b/Client/core/Graphics/CMaterialPrimitive3DBatcher.cpp @@ -0,0 +1,229 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * (Shared logic for modifications) + * LICENSE: See LICENSE in the top level directory + * FILE: CMaterialPrimitive3DBatcher.cpp + * PURPOSE: + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ +#include +#include "CMaterialPrimitive3DBatcher.h" +//////////////////////////////////////////////////////////////// +// +// CMaterialPrimitive3DBatcher::CMaterialPrimitive3DBatcher +// +// +// +//////////////////////////////////////////////////////////////// +CMaterialPrimitive3DBatcher::CMaterialPrimitive3DBatcher(bool bPreGUI, CGraphics* pGraphics) + : m_bPreGUI(bPreGUI), m_pGraphics(pGraphics) +{ +} +//////////////////////////////////////////////////////////////// +// +// CMaterialPrimitive3DBatcher::OnDeviceCreate +// +// +// +//////////////////////////////////////////////////////////////// +void CMaterialPrimitive3DBatcher::OnDeviceCreate(IDirect3DDevice9* pDevice, float fViewportSizeX, float fViewportSizeY) +{ + m_pDevice = pDevice; +} +//////////////////////////////////////////////////////////////// +// +// CMaterialPrimitive3DBatcher::Flush +// +// Send all buffered vertices to D3D +// +//////////////////////////////////////////////////////////////// +void CMaterialPrimitive3DBatcher::Flush() +{ + if (m_primitiveList.empty()) + return; + + // Get scene matrices + D3DXMATRIX matWorld; + D3DXMatrixIdentity(&matWorld); + const D3DXMATRIX& matView = g_pDeviceState->TransformState.VIEW; + const D3DXMATRIX& matProjection = g_pDeviceState->TransformState.PROJECTION; + + // Pre-calc camera position + D3DXMATRIX matViewInv; + D3DXMatrixInverse(&matViewInv, NULL, &matView); + const CVector vecCameraPos(matViewInv._41, matViewInv._42, matViewInv._43); + + // Set transforms + m_pDevice->SetTransform(D3DTS_WORLD, &matWorld); + m_pDevice->SetTransform(D3DTS_VIEW, &matView); + m_pDevice->SetTransform(D3DTS_PROJECTION, &matProjection); + + + IDirect3DStateBlock9* pSavedStateBlock = nullptr; + m_pDevice->CreateStateBlock(D3DSBT_ALL, &pSavedStateBlock); + + // fix alpha blending, func at address 0x005D6480 drawing models in gtasa + + // Set states + if (g_pDeviceState->AdapterState.bRequiresClipping) + m_pDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + m_pDevice->SetRenderState(D3DRS_ZENABLE, m_bPreGUI ? D3DZB_TRUE : D3DZB_FALSE); + m_pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + m_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + m_pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + m_pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + m_pDevice->SetRenderState(D3DRS_ALPHAREF, 0x01); + m_pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + m_pDevice->SetRenderState(D3DRS_FOGENABLE, TRUE); + m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + // Set vertex stream + m_pDevice->SetFVF(PrimitiveMaterialVertice::FNV); + + // Draw + m_pDevice->SetTexture(0, nullptr); + // Cache last used material, so we don't set directx parameters needlessly + CMaterialItem* pLastMaterial = nullptr; + + uint uiVertexStreamZeroStride = sizeof(PrimitiveMaterialVertice); + + for (auto& primitive : m_primitiveList) { + const void* pVertexStreamZeroData = &primitive.pVecVertices->at(0); + size_t iCollectionSize = primitive.pVecVertices->size(); + + CMaterialItem* pMaterial = primitive.pMaterial; + if (pMaterial != pLastMaterial) + { + // Set texture addressing mode + m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, pMaterial->m_TextureAddress); + m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, pMaterial->m_TextureAddress); + + if (pMaterial->m_TextureAddress == TADDRESS_BORDER) + m_pDevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, pMaterial->m_uiBorderColor); + } + + if (CTextureItem* pTextureItem = DynamicCast(pMaterial)) + { + m_pDevice->SetTexture(0, pTextureItem->m_pD3DTexture); + DrawPrimitive(primitive.eType, primitive.pVecVertices->size(), pVertexStreamZeroData, uiVertexStreamZeroStride); + } + else if (CShaderInstance* pShaderInstance = DynamicCast(pMaterial)) + { + // Draw using shader + ID3DXEffect* pD3DEffect = pShaderInstance->m_pEffectWrap->m_pD3DEffect; + + if (pMaterial != pLastMaterial) + { + // Apply custom parameters + pShaderInstance->ApplyShaderParameters(); + // Apply common parameters + pShaderInstance->m_pEffectWrap->ApplyCommonHandles(); + // Apply mapped parameters + pShaderInstance->m_pEffectWrap->ApplyMappedHandles(); + } + + // Do shader passes + DWORD dwFlags = D3DXFX_DONOTSAVESHADERSTATE; + uint uiNumPasses = 0; + pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags, false); + + for (uint uiPass = 0; uiPass < uiNumPasses; uiPass++) + { + pD3DEffect->BeginPass(uiPass); + DrawPrimitive(primitive.eType, primitive.pVecVertices->size(), pVertexStreamZeroData, uiVertexStreamZeroStride); + pD3DEffect->EndPass(); + } + pShaderInstance->m_pEffectWrap->End(); + + // If we didn't get the effect to save the shader state, clear some things here + if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE) + { + m_pDevice->SetVertexShader(NULL); + m_pDevice->SetPixelShader(NULL); + } + } + pLastMaterial = pMaterial; + pMaterial->Release(); + } + + // Clean up + ClearQueue(); + + if (pSavedStateBlock) + { + pSavedStateBlock->Apply(); + SAFE_RELEASE(pSavedStateBlock); + } +} + +void CMaterialPrimitive3DBatcher::ClearQueue() +{ + // Clean up + for (auto& primitive : m_primitiveList) + { + delete primitive.pVecVertices; + } + + m_primitiveList.clear(); +} +//////////////////////////////////////////////////////////////// +// +// CPrimitiveMaterialBatcher::DrawPrimitive +// +// Draws the primitives on render target +// +//////////////////////////////////////////////////////////////// +void CMaterialPrimitive3DBatcher::DrawPrimitive(D3DPRIMITIVETYPE eType, size_t iCollectionSize, const void* pDataAddr, size_t uiVertexStride) +{ + int iSize = 1; + switch (eType) + { + case D3DPT_POINTLIST: + iSize = iCollectionSize; + break; + case D3DPT_LINELIST: + iSize = iCollectionSize / 2; + break; + case D3DPT_LINESTRIP: + iSize = iCollectionSize - 1; + break; + case D3DPT_TRIANGLEFAN: + case D3DPT_TRIANGLESTRIP: + iSize = iCollectionSize - 2; + break; + case D3DPT_TRIANGLELIST: + iSize = iCollectionSize / 3; + break; + } + m_pDevice->DrawPrimitiveUP(eType, iSize, pDataAddr, uiVertexStride); +} +//////////////////////////////////////////////////////////////// +// +// CMaterialPrimitive3DBatcher::AddPrimitive +// +// Add a new primitive to the list +// +//////////////////////////////////////////////////////////////// +void CMaterialPrimitive3DBatcher::AddPrimitive(D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, std::vector* pVecVertices) +{ + if (!pMaterial) + return; + + pMaterial->AddRef(); + m_primitiveList.push_back({eType, pMaterial, pVecVertices}); +} diff --git a/Client/core/Graphics/CMaterialPrimitive3DBatcher.h b/Client/core/Graphics/CMaterialPrimitive3DBatcher.h new file mode 100644 index 00000000000..bfbb52073e3 --- /dev/null +++ b/Client/core/Graphics/CMaterialPrimitive3DBatcher.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: CMaterialPrimitive3DBatcher.h + * PURPOSE: + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +// Vertex type used by the primitives 3d batcher +struct sPrimitiveMaterial3D +{ + D3DPRIMITIVETYPE eType; + CMaterialItem* pMaterial; + std::vector* pVecVertices; +}; + +// +// Batches primitives drawing +// +class CMaterialPrimitive3DBatcher +{ +public: + CMaterialPrimitive3DBatcher(bool bPreGUI, CGraphics* pGraphics); + void OnDeviceCreate(IDirect3DDevice9* pDevice, float fViewportSizeX, float fViewportSizeY); + void Flush(); + void AddPrimitive(D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, std::vector* pVecVertices); + void DrawPrimitive(D3DPRIMITIVETYPE eType, size_t iCollectionSize, const void* pDataAddr, size_t uiVertexStride); + bool HasItems() const { return !m_primitiveList.empty(); } + void ClearQueue(); + +protected: + bool m_bPreGUI; + IDirect3DDevice9* m_pDevice; + CGraphics* m_pGraphics; + std::vector m_primitiveList; +}; diff --git a/Client/core/Graphics/CPrimitive3DBatcher.cpp b/Client/core/Graphics/CPrimitive3DBatcher.cpp new file mode 100644 index 00000000000..21f3f11c850 --- /dev/null +++ b/Client/core/Graphics/CPrimitive3DBatcher.cpp @@ -0,0 +1,158 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * (Shared logic for modifications) + * LICENSE: See LICENSE in the top level directory + * FILE: CPrimitive3DBatcher.cpp + * PURPOSE: + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ +#include +#include "CPrimitive3DBatcher.h" +//////////////////////////////////////////////////////////////// +// +// CPrimitive3DBatcher::CPrimitive3DBatcher +// +// +// +//////////////////////////////////////////////////////////////// +CPrimitive3DBatcher::CPrimitive3DBatcher(bool bPreGUI) + : m_bPreGUI(bPreGUI) +{ +} +//////////////////////////////////////////////////////////////// +// +// CPrimitive3DBatcher::OnDeviceCreate +// +// +// +//////////////////////////////////////////////////////////////// +void CPrimitive3DBatcher::OnDeviceCreate(IDirect3DDevice9* pDevice, float fViewportSizeX, float fViewportSizeY) +{ + m_pDevice = pDevice; +} +//////////////////////////////////////////////////////////////// +// +// CPrimitive3DBatcher::Flush +// +// Send all buffered vertices to D3D +// +//////////////////////////////////////////////////////////////// +void CPrimitive3DBatcher::Flush() +{ + if (m_primitiveList.empty()) + return; + + // Get scene matrices + D3DXMATRIX matWorld; + D3DXMatrixIdentity(&matWorld); + const D3DXMATRIX& matView = g_pDeviceState->TransformState.VIEW; + const D3DXMATRIX& matProjection = g_pDeviceState->TransformState.PROJECTION; + + // Pre-calc camera position + D3DXMATRIX matViewInv; + D3DXMatrixInverse(&matViewInv, NULL, &matView); + const CVector vecCameraPos(matViewInv._41, matViewInv._42, matViewInv._43); + + + IDirect3DStateBlock9* pSavedStateBlock = nullptr; + m_pDevice->CreateStateBlock(D3DSBT_ALL, &pSavedStateBlock); + + // Set states + if (g_pDeviceState->AdapterState.bRequiresClipping) + m_pDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + m_pDevice->SetRenderState(D3DRS_ZENABLE, m_bPreGUI ? D3DZB_TRUE : D3DZB_FALSE); + m_pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + m_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + m_pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + m_pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + m_pDevice->SetRenderState(D3DRS_ALPHAREF, 0x01); + m_pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + // Set transforms + m_pDevice->SetTransform(D3DTS_WORLD, &matWorld); + m_pDevice->SetTransform(D3DTS_VIEW, &matView); + m_pDevice->SetTransform(D3DTS_PROJECTION, &matProjection); + + // Set vertex stream + m_pDevice->SetFVF(PrimitiveVertice::FNV); + + m_pDevice->SetTexture(0, NULL); + // Draw + + uint VertexStreamZeroStride = sizeof(PrimitiveVertice); + for (auto& primitive : m_primitiveList) { + DrawPrimitive(primitive.eType, primitive.pVecVertices->size(), &primitive.pVecVertices->at(0), VertexStreamZeroStride); + } + + // Clean up + for (auto& primitive : m_primitiveList) { + delete primitive.pVecVertices; + } + + m_primitiveList.clear(); + + if (g_pDeviceState->AdapterState.bRequiresClipping) + m_pDevice->SetRenderState(D3DRS_CLIPPING, FALSE); + + if (pSavedStateBlock) + { + pSavedStateBlock->Apply(); + SAFE_RELEASE(pSavedStateBlock); + } +} +//////////////////////////////////////////////////////////////// +// +// CPrimitiveMaterialBatcher::DrawPrimitive +// +// Draws the primitives on render target +// +//////////////////////////////////////////////////////////////// +void CPrimitive3DBatcher::DrawPrimitive(D3DPRIMITIVETYPE eType, size_t iCollectionSize, const void* pDataAddr, size_t uiVertexStride) +{ + int iSize = 1; + switch (eType) + { + case D3DPT_POINTLIST: + iSize = iCollectionSize; + break; + case D3DPT_LINELIST: + iSize = iCollectionSize / 2; + break; + case D3DPT_LINESTRIP: + iSize = iCollectionSize - 1; + break; + case D3DPT_TRIANGLEFAN: + case D3DPT_TRIANGLESTRIP: + iSize = iCollectionSize - 2; + break; + case D3DPT_TRIANGLELIST: + iSize = iCollectionSize / 3; + break; + } + m_pDevice->DrawPrimitiveUP(eType, iSize, pDataAddr, uiVertexStride); +} +//////////////////////////////////////////////////////////////// +// +// CPrimitive3DBatcher::AddTriangle +// +// Add a new primitive to the list +// +//////////////////////////////////////////////////////////////// +void CPrimitive3DBatcher::AddPrimitive(D3DPRIMITIVETYPE eType, std::vector* pVecVertices) +{ + m_primitiveList.push_back({eType, pVecVertices}); +} diff --git a/Client/core/Graphics/CPrimitive3DBatcher.h b/Client/core/Graphics/CPrimitive3DBatcher.h new file mode 100644 index 00000000000..e32fd9d8c32 --- /dev/null +++ b/Client/core/Graphics/CPrimitive3DBatcher.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: CPrimitive3DBatcher.h + * PURPOSE: + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +// Vertex type used by the primitives 3d batcher +struct sPrimitive3D +{ + D3DPRIMITIVETYPE eType; + std::vector* pVecVertices; +}; + +// +// Batches primitives drawing +// +class CPrimitive3DBatcher +{ +public: + CPrimitive3DBatcher(bool bPreGUI); + void OnDeviceCreate(IDirect3DDevice9* pDevice, float fViewportSizeX, float fViewportSizeY); + void Flush(); + void AddPrimitive(D3DPRIMITIVETYPE eType, std::vector* pVecVertices); + void DrawPrimitive(D3DPRIMITIVETYPE eType, size_t iCollectionSize, const void* pDataAddr, size_t uiVertexStride); + bool HasItems() const { return !m_primitiveList.empty(); } + +protected: + bool m_bPreGUI; + IDirect3DDevice9* m_pDevice; + std::vector m_primitiveList; +}; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp index aaf4e01add4..b7009f3a209 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.cpp @@ -26,7 +26,9 @@ void CLuaDrawingDefs::LoadFunctions() {"dxDrawImage", DxDrawImage}, {"dxDrawImageSection", DxDrawImageSection}, {"dxDrawPrimitive", DxDrawPrimitive}, + {"dxDrawPrimitive3D", DxDrawPrimitive3D}, {"dxDrawMaterialPrimitive", DxDrawMaterialPrimitive}, + {"dxDrawMaterialPrimitive3D", DxDrawMaterialPrimitive3D}, {"dxGetTextWidth", DxGetTextWidth}, {"dxGetFontHeight", DxGetFontHeight}, {"dxCreateFont", DxCreateFont}, @@ -566,12 +568,111 @@ int CLuaDrawingDefs::DxDrawImageSection(lua_State* luaVM) return 1; } +int CLuaDrawingDefs::DxDrawPrimitive3D(lua_State* luaVM) +{ + // bool DxDrawPrimitive3D (string primitiveType, bool postGUI, table vertice1, ...) + D3DPRIMITIVETYPE ePrimitiveType; + auto pVecVertices = new std::vector(); + bool bPostGUI; + CScriptArgReader argStream(luaVM); + argStream.ReadEnumString(ePrimitiveType); + argStream.ReadBool(bPostGUI, false); + + std::vector vecTableContent; + + while (argStream.NextIsTable()) + { + vecTableContent.clear(); + + argStream.ReadNumberTable(vecTableContent); + switch (vecTableContent.size()) + { + case Primitive3DVerticeSizes::VERT_XYZ: + pVecVertices->push_back(PrimitiveVertice{vecTableContent[0], vecTableContent[1], vecTableContent[2], (DWORD)0xFFFFFFFF}); + break; + case Primitive3DVerticeSizes::VERT_XYZ_COLOR: + pVecVertices->push_back(PrimitiveVertice{vecTableContent[0], vecTableContent[1], vecTableContent[2], static_cast(vecTableContent[3])}); + break; + default: + argStream.SetCustomError(SString("Expected table with 3 or 4 numbers, got %i numbers", vecTableContent.size()).c_str()); + break; + } + } + + if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (g_pCore->GetGraphics()->IsValidPrimitiveSize(pVecVertices->size(), ePrimitiveType)) + { + g_pCore->GetGraphics()->DrawPrimitive3DQueued(pVecVertices, ePrimitiveType, bPostGUI); + lua_pushboolean(luaVM, true); + return 1; + } + + // Failed + delete pVecVertices; + lua_pushboolean(luaVM, false); + return 1; +} + +int CLuaDrawingDefs::DxDrawMaterialPrimitive3D(lua_State* luaVM) +{ + // bool DxDrawMaterialPrimitive3D (string primitiveType, dxMaterial material, bool postGUI, table vertice1, ...) + D3DPRIMITIVETYPE ePrimitiveType; + auto pVecVertices = new std::vector(); + CClientMaterial* pMaterialElement; + bool bPostGUI; + + CScriptArgReader argStream(luaVM); + argStream.ReadEnumString(ePrimitiveType); + MixedReadMaterialString(argStream, pMaterialElement); + argStream.ReadBool(bPostGUI, false); + + std::vector vecTableContent; + + while (argStream.NextIsTable()) + { + vecTableContent.clear(); + + argStream.ReadNumberTable(vecTableContent); + switch (vecTableContent.size()) + { + case Primitive3DVerticeSizes::VERT_XYZ_UV: + pVecVertices->push_back(PrimitiveMaterialVertice{vecTableContent[0], vecTableContent[1], vecTableContent[2], (DWORD)0xFFFFFFFF, + vecTableContent[3], vecTableContent[4]}); + break; + case Primitive3DVerticeSizes::VERT_XYZ_COLOR_UV: + pVecVertices->push_back(PrimitiveMaterialVertice{vecTableContent[0], vecTableContent[1], vecTableContent[2], + static_cast(vecTableContent[3]), vecTableContent[4], vecTableContent[5]}); + break; + default: + argStream.SetCustomError(SString("Expected table with 5 or 6 numbers, got %i numbers", vecTableContent.size()).c_str()); + break; + } + } + + if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (g_pCore->GetGraphics()->IsValidPrimitiveSize(pVecVertices->size(), ePrimitiveType)) + { + g_pCore->GetGraphics()->DrawMaterialPrimitive3DQueued(pVecVertices, ePrimitiveType, pMaterialElement->GetMaterialItem(), bPostGUI); + lua_pushboolean(luaVM, true); + return 1; + } + + // Failed + delete pVecVertices; + lua_pushboolean(luaVM, false); + return 1; +} + int CLuaDrawingDefs::DxDrawPrimitive(lua_State* luaVM) { // bool dxDrawPrimitive (string primitiveType, bool postGUI, table vertice1, ...) - D3DPRIMITIVETYPE ePrimitiveType; - auto pVecVertices = new std::vector(); - bool bPostGUI; + D3DPRIMITIVETYPE ePrimitiveType; + auto pVecVertices = new std::vector(); + bool bPostGUI; CScriptArgReader argStream(luaVM); argStream.ReadEnumString(ePrimitiveType); @@ -582,6 +683,7 @@ int CLuaDrawingDefs::DxDrawPrimitive(lua_State* luaVM) while (argStream.NextIsTable()) { vecTableContent.clear(); + argStream.ReadNumberTable(vecTableContent); switch (vecTableContent.size()) { @@ -597,18 +699,14 @@ int CLuaDrawingDefs::DxDrawPrimitive(lua_State* luaVM) } } - if (!argStream.HasErrors()) - { - if (g_pCore->GetGraphics()->IsValidPrimitiveSize(pVecVertices->size(), ePrimitiveType)) - { - g_pCore->GetGraphics()->DrawPrimitiveQueued(pVecVertices, ePrimitiveType, bPostGUI); - lua_pushboolean(luaVM, true); - return 1; - } - } - else + if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (g_pCore->GetGraphics()->IsValidPrimitiveSize(pVecVertices->size(), ePrimitiveType)) { - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + g_pCore->GetGraphics()->DrawPrimitiveQueued(pVecVertices, ePrimitiveType, bPostGUI); + lua_pushboolean(luaVM, true); + return 1; } // Failed @@ -620,10 +718,10 @@ int CLuaDrawingDefs::DxDrawPrimitive(lua_State* luaVM) int CLuaDrawingDefs::DxDrawMaterialPrimitive(lua_State* luaVM) { // bool dxDrawPrimitive (string primitiveType, dxMaterial material, bool postGUI, table vertice1, ...) - D3DPRIMITIVETYPE ePrimitiveType; - auto pVecVertices = new std::vector(); - CClientMaterial* pMaterialElement; - bool bPostGUI; + D3DPRIMITIVETYPE ePrimitiveType; + auto pVecVertices = new std::vector(); + CClientMaterial* pMaterialElement; + bool bPostGUI; CScriptArgReader argStream(luaVM); argStream.ReadEnumString(ePrimitiveType); @@ -635,6 +733,7 @@ int CLuaDrawingDefs::DxDrawMaterialPrimitive(lua_State* luaVM) while (argStream.NextIsTable()) { vecTableContent.clear(); + argStream.ReadNumberTable(vecTableContent); switch (vecTableContent.size()) { @@ -644,7 +743,7 @@ int CLuaDrawingDefs::DxDrawMaterialPrimitive(lua_State* luaVM) break; case PrimitiveVerticeSizes::VERT_XY_COLOR_UV: pVecVertices->push_back(PrimitiveMaterialVertice{vecTableContent[0], vecTableContent[1], 0, static_cast(vecTableContent[2]), - vecTableContent[3], vecTableContent[4]}); + vecTableContent[3], vecTableContent[4]}); break; default: argStream.SetCustomError(SString("Expected table with 4 or 5 numbers, got %i numbers", vecTableContent.size()).c_str()); @@ -652,18 +751,14 @@ int CLuaDrawingDefs::DxDrawMaterialPrimitive(lua_State* luaVM) } } - if (!argStream.HasErrors()) - { - if (pMaterialElement && g_pCore->GetGraphics()->IsValidPrimitiveSize(pVecVertices->size(), ePrimitiveType)) - { - g_pCore->GetGraphics()->DrawMaterialPrimitiveQueued(pVecVertices, ePrimitiveType, pMaterialElement->GetMaterialItem(), bPostGUI); - lua_pushboolean(luaVM, true); - return 1; - } - } if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (g_pCore->GetGraphics()->IsValidPrimitiveSize(pVecVertices->size(), ePrimitiveType)) { - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + g_pCore->GetGraphics()->DrawMaterialPrimitiveQueued(pVecVertices, ePrimitiveType, pMaterialElement->GetMaterialItem(), bPostGUI); + lua_pushboolean(luaVM, true); + return 1; } // Failed diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h index cd0565b664c..99b947fe98d 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDrawingDefs.h @@ -29,6 +29,8 @@ class CLuaDrawingDefs : public CLuaDefs LUA_DECLARE(DxDrawImageSection); LUA_DECLARE(DxDrawPrimitive); LUA_DECLARE(DxDrawMaterialPrimitive); + LUA_DECLARE(DxDrawPrimitive3D); + LUA_DECLARE(DxDrawMaterialPrimitive3D); LUA_DECLARE_OOP(DxGetTextWidth); LUA_DECLARE_OOP(DxGetFontHeight); LUA_DECLARE(DxCreateFont); diff --git a/Client/sdk/core/CGraphicsInterface.h b/Client/sdk/core/CGraphicsInterface.h index 30b69bcfaf2..1ea8c2907ec 100644 --- a/Client/sdk/core/CGraphicsInterface.h +++ b/Client/sdk/core/CGraphicsInterface.h @@ -37,6 +37,14 @@ enum PrimitiveVerticeSizes VERT_XY_COLOR_UV = 5 }; +enum Primitive3DVerticeSizes +{ + VERT_XYZ = 3, + VERT_XYZ_COLOR, + VERT_XYZ_UV, + VERT_XYZ_COLOR_UV, +}; + struct ID3DXFont; struct IDirect3DDevice9; struct IDirect3DTexture9; @@ -153,6 +161,11 @@ class CGraphicsInterface virtual void DrawPrimitiveQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, bool bPostGUI) = 0; virtual void DrawMaterialPrimitiveQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, bool bPostGUI) = 0; + + virtual void DrawPrimitive3DQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, bool bPostGUI) = 0; + virtual void DrawMaterialPrimitive3DQueued(std::vector* pVecVertices, D3DPRIMITIVETYPE eType, CMaterialItem* pMaterial, + bool bPostGUI) = 0; + virtual void DrawCircleQueued(float fX, float fY, float fRadius, float fStartAngle, float fStopAngle, unsigned long ulColor, unsigned long ulColorCenter, short siSegments, float fRatio, bool bPostGUI) = 0;