diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h index 0281c53c91..dc1bb3c408 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h @@ -57,6 +57,7 @@ class W3DProjectedShadowManager : public ProjectedShadowManager Bool init(void); ///getShadowSizeY(); shadowInfo.m_offsetX = tmplate->getShadowOffsetX(); shadowInfo.m_offsetY = tmplate->getShadowOffsetY(); - m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw); + + DEBUG_ASSERTCRASH(m_shadow == NULL, ("m_shadow is not NULL")); + m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw); if (m_shadow) { m_shadow->enableShadowInvisible(m_fullyObscuredByShroud); m_shadow->enableShadowRender(m_shadowEnabled); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp index 7014a309f9..b9f1b3d2db 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp @@ -88,12 +88,6 @@ extern int nShadowStartBatchIndex; extern int SHADOW_VERTEX_SIZE; extern int SHADOW_INDEX_SIZE; -//Bounding rectangle around rendered portion of terrain. -static Int drawEdgeX=0; -static Int drawEdgeY=0; -static Int drawStartX=0; -static Int drawStartY=0; - //Global streaming vertex buffer with x,y,z,u,v type. struct SHADOW_DECAL_VERTEX //vertex structure passed to D3D { @@ -215,6 +209,10 @@ W3DProjectedShadowManager::W3DProjectedShadowManager(void) m_W3DShadowTextureManager = NULL; m_shadowCamera = NULL; m_shadowContext= NULL; + m_drawEdgeX = 0; + m_drawEdgeY = 0; + m_drawStartX = 0; + m_drawStartY = 0; } W3DProjectedShadowManager::~W3DProjectedShadowManager(void) @@ -959,15 +957,15 @@ void W3DProjectedShadowManager::queueDecal(W3DProjectedShadow *shadow) Int startY=REAL_TO_INT_FLOOR(((objPos.Y+min_y)*mapScaleInv)) + borderSize; Int endY=REAL_TO_INT_CEIL(((objPos.Y+max_y)*mapScaleInv)) + borderSize; - startX = __max(startX,drawStartX); - startX = __min(startX,drawEdgeX); - startY = __max(startY,drawStartY); - startY = __min(startY,drawEdgeY); + startX = __max(startX,m_drawStartX); + startX = __min(startX,m_drawEdgeX); + startY = __max(startY,m_drawStartY); + startY = __min(startY,m_drawEdgeY); - endX = __max(endX,drawStartX); - endX = __min(endX,drawEdgeX); - endY = __max(endY,drawStartY); - endY = __min(endY,drawEdgeY); + endX = __max(endX,m_drawStartX); + endX = __min(endX,m_drawEdgeX); + endY = __max(endY,m_drawStartY); + endY = __min(endY,m_drawEdgeY); //Check if decal too large to fit inside 65536 index buffer. //try clipping each direction to < 104 since that's more than @@ -1276,33 +1274,40 @@ void W3DProjectedShadowManager::queueSimpleDecal(W3DProjectedShadow *shadow) } +void W3DProjectedShadowManager::prepareShadows() +{ + if (!TheTerrainRenderObject) + return; + + WorldHeightMap *hmap=TheTerrainRenderObject->getMap(); + + if (!hmap) + return; + + //Find extents of visible terrain + m_drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1; + m_drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1; + if (m_drawEdgeX > (hmap->getXExtent()-1)) + m_drawEdgeX = hmap->getXExtent()-1; + if (m_drawEdgeY > (hmap->getYExtent()-1)) + m_drawEdgeY = hmap->getYExtent()-1; + m_drawStartX=hmap->getDrawOrgX(); + m_drawStartY=hmap->getDrawOrgY(); +} + Int W3DProjectedShadowManager::renderShadows(RenderInfoClass & rinfo) { - ///@todo: implement this method. - W3DProjectedShadow *shadow; - static AABoxClass aaBox; - static SphereClass sphere; Int projectionCount=0; + if (!TheTerrainRenderObject) + return projectionCount; + if (!m_shadowList && !m_decalList) return projectionCount; //there are no shadows to render. - //Find extents of visible terrain - if (TheTerrainRenderObject) - { - WorldHeightMap *hmap=TheTerrainRenderObject->getMap(); - - drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1; - drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1; - if (drawEdgeX > (hmap->getXExtent()-1)) - drawEdgeX = hmap->getXExtent()-1; - if (drawEdgeY > (hmap->getYExtent()-1)) - drawEdgeY = hmap->getYExtent()-1; - drawStartX=hmap->getDrawOrgX(); - drawStartY=hmap->getDrawOrgY(); - } - else - return projectionCount; + W3DProjectedShadow *shadow; + static AABoxClass aaBox; + static SphereClass sphere; //According to Nvidia there's a D3D bug that happens if you don't start with a //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp index c87fd141cb..9e5b24fee5 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp @@ -63,6 +63,12 @@ Vector3 LightPosWorld[ MAX_SHADOW_LIGHTS ] = Vector3( 94.0161f, 50.499f, 200.0f) }; +void PrepareShadows() +{ + if (TheW3DProjectedShadowManager) + TheW3DProjectedShadowManager->prepareShadows(); +} + //DECLARE_PERF_TIMER(shadowsRender) void DoShadows(RenderInfoClass & rinfo, Bool stencilPass) { diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp index 48c5f4f5da..a20c12bc11 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp @@ -68,6 +68,7 @@ // DEFINITIONS //////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ///@todo: Remove these globals since we no longer need W3D to call them for us. +extern void PrepareShadows(); extern void DoTrees(RenderInfoClass & rinfo); extern void DoShadows(RenderInfoClass & rinfo, Bool stencilPass); extern void DoParticles(RenderInfoClass & rinfo); @@ -789,6 +790,10 @@ void RTS3DScene::renderOneObject(RenderInfoClass &rinfo, RenderObjClass *robj, I /**Draw everything that was submitted from this scene*/ void RTS3DScene::Flush(RenderInfoClass & rinfo) { + // TheSuperHackers @bugfix Now always prepares shadows to guarantee correct state before doing any + // shadow draw calls. Originally just drawing shadows for trees would not properly prepare shadows. + PrepareShadows(); + //don't draw shadows in this mode because they interfere with destination alpha or are invisible (wireframe) if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE) DoShadows(rinfo, false); //draw all non-stencil shadows (decals) since they fall under other objects. diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h index ef86c77f3d..155f2efc45 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h @@ -57,6 +57,7 @@ class W3DProjectedShadowManager : public ProjectedShadowManager Bool init(void); ///getShadowSizeY(); shadowInfo.m_offsetX = tmplate->getShadowOffsetX(); shadowInfo.m_offsetY = tmplate->getShadowOffsetY(); - m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw); + + DEBUG_ASSERTCRASH(m_shadow == NULL, ("m_shadow is not NULL")); + m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw); if (m_shadow) { m_shadow->enableShadowInvisible(m_fullyObscuredByShroud); m_shadow->enableShadowRender(m_shadowEnabled); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp index 3bfb20da09..b112d5d17d 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp @@ -88,12 +88,6 @@ extern int nShadowStartBatchIndex; extern int SHADOW_VERTEX_SIZE; extern int SHADOW_INDEX_SIZE; -//Bounding rectangle around rendered portion of terrain. -static Int drawEdgeX=0; -static Int drawEdgeY=0; -static Int drawStartX=0; -static Int drawStartY=0; - //Global streaming vertex buffer with x,y,z,u,v type. struct SHADOW_DECAL_VERTEX //vertex structure passed to D3D { @@ -215,6 +209,10 @@ W3DProjectedShadowManager::W3DProjectedShadowManager(void) m_W3DShadowTextureManager = NULL; m_shadowCamera = NULL; m_shadowContext= NULL; + m_drawEdgeX = 0; + m_drawEdgeY = 0; + m_drawStartX = 0; + m_drawStartY = 0; } W3DProjectedShadowManager::~W3DProjectedShadowManager(void) @@ -959,15 +957,15 @@ void W3DProjectedShadowManager::queueDecal(W3DProjectedShadow *shadow) Int startY=REAL_TO_INT_FLOOR(((objPos.Y+min_y)*mapScaleInv)) + borderSize; Int endY=REAL_TO_INT_CEIL(((objPos.Y+max_y)*mapScaleInv)) + borderSize; - startX = __max(startX,drawStartX); - startX = __min(startX,drawEdgeX); - startY = __max(startY,drawStartY); - startY = __min(startY,drawEdgeY); + startX = __max(startX,m_drawStartX); + startX = __min(startX,m_drawEdgeX); + startY = __max(startY,m_drawStartY); + startY = __min(startY,m_drawEdgeY); - endX = __max(endX,drawStartX); - endX = __min(endX,drawEdgeX); - endY = __max(endY,drawStartY); - endY = __min(endY,drawEdgeY); + endX = __max(endX,m_drawStartX); + endX = __min(endX,m_drawEdgeX); + endY = __max(endY,m_drawStartY); + endY = __min(endY,m_drawEdgeY); //Check if decal too large to fit inside 65536 index buffer. //try clipping each direction to < 104 since that's more than @@ -1276,33 +1274,40 @@ void W3DProjectedShadowManager::queueSimpleDecal(W3DProjectedShadow *shadow) } +void W3DProjectedShadowManager::prepareShadows() +{ + if (!TheTerrainRenderObject) + return; + + WorldHeightMap *hmap=TheTerrainRenderObject->getMap(); + + if (!hmap) + return; + + //Find extents of visible terrain + m_drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1; + m_drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1; + if (m_drawEdgeX > (hmap->getXExtent()-1)) + m_drawEdgeX = hmap->getXExtent()-1; + if (m_drawEdgeY > (hmap->getYExtent()-1)) + m_drawEdgeY = hmap->getYExtent()-1; + m_drawStartX=hmap->getDrawOrgX(); + m_drawStartY=hmap->getDrawOrgY(); +} + Int W3DProjectedShadowManager::renderShadows(RenderInfoClass & rinfo) { - ///@todo: implement this method. - W3DProjectedShadow *shadow; - static AABoxClass aaBox; - static SphereClass sphere; Int projectionCount=0; + if (!TheTerrainRenderObject) + return projectionCount; + if (!m_shadowList && !m_decalList) return projectionCount; //there are no shadows to render. - //Find extents of visible terrain - if (TheTerrainRenderObject) - { - WorldHeightMap *hmap=TheTerrainRenderObject->getMap(); - - drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1; - drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1; - if (drawEdgeX > (hmap->getXExtent()-1)) - drawEdgeX = hmap->getXExtent()-1; - if (drawEdgeY > (hmap->getYExtent()-1)) - drawEdgeY = hmap->getYExtent()-1; - drawStartX=hmap->getDrawOrgX(); - drawStartY=hmap->getDrawOrgY(); - } - else - return projectionCount; + W3DProjectedShadow *shadow; + static AABoxClass aaBox; + static SphereClass sphere; //According to Nvidia there's a D3D bug that happens if you don't start with a //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp index 1db6dab0d5..4f2096efa7 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp @@ -63,6 +63,12 @@ Vector3 LightPosWorld[ MAX_SHADOW_LIGHTS ] = Vector3( 94.0161f, 50.499f, 200.0f) }; +void PrepareShadows() +{ + if (TheW3DProjectedShadowManager) + TheW3DProjectedShadowManager->prepareShadows(); +} + //DECLARE_PERF_TIMER(shadowsRender) void DoShadows(RenderInfoClass & rinfo, Bool stencilPass) { diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp index 7c815982fe..5bdbe1ab5a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp @@ -69,6 +69,7 @@ // DEFINITIONS //////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ///@todo: Remove these globals since we no longer need W3D to call them for us. +extern void PrepareShadows(); extern void DoTrees(RenderInfoClass & rinfo); extern void DoShadows(RenderInfoClass & rinfo, Bool stencilPass); extern void DoParticles(RenderInfoClass & rinfo); @@ -827,6 +828,10 @@ void RTS3DScene::renderOneObject(RenderInfoClass &rinfo, RenderObjClass *robj, I /**Draw everything that was submitted from this scene*/ void RTS3DScene::Flush(RenderInfoClass & rinfo) { + // TheSuperHackers @bugfix Now always prepares shadows to guarantee correct state before doing any + // shadow draw calls. Originally just drawing shadows for trees would not properly prepare shadows. + PrepareShadows(); + //don't draw shadows in this mode because they interfere with destination alpha or are invisible (wireframe) if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE) DoShadows(rinfo, false); //draw all non-stencil shadows (decals) since they fall under other objects. diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DTreeBuffer.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DTreeBuffer.cpp index 48d2470b69..e418aaef20 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DTreeBuffer.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DTreeBuffer.cpp @@ -1604,12 +1604,12 @@ void W3DTreeBuffer::drawTrees(CameraClass * camera, RefRenderObjListIterator *pD if (!m_trees[curTree].visible || !m_treeTypes[type].m_doShadow) { continue; } - Real factor = 1.0f; + if (m_trees[curTree].m_toppleState == TOPPLE_FALLING || m_trees[curTree].m_toppleState == TOPPLE_DOWN) { continue; } - m_shadow->setSize(m_treeTypes[type].m_shadowSize, -m_treeTypes[type].m_shadowSize*factor); + m_shadow->setSize(m_treeTypes[type].m_shadowSize, m_treeTypes[type].m_shadowSize); m_shadow->setPosition(m_trees[curTree].location.X, m_trees[curTree].location.Y, m_trees[curTree].location.Z); TheW3DProjectedShadowManager->queueDecal(m_shadow); }