Skip to content

Commit 9385483

Browse files
authored
bugfix(shadow): Fix missing tree shadow decals when no object shadow decals exist (#1590)
1 parent a8f6955 commit 9385483

File tree

11 files changed

+126
-74
lines changed

11 files changed

+126
-74
lines changed

Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class W3DProjectedShadowManager : public ProjectedShadowManager
5757
Bool init(void); ///<allocate one-time shadow assets for length of entire game.
5858
void reset(void); ///<free all existing shadows - ready for next map.
5959
void shutdown(void); ///<free all assets prior to shutdown of entire game.
60+
void prepareShadows();
6061
Int renderShadows(RenderInfoClass & rinfo); ///<iterate over each object and render its shadow onto affected objects.
6162
void ReleaseResources(void); ///<release device dependent D3D resources.
6263
Bool ReAcquireResources(void); ///<allocate device dependent D3D resources.
@@ -76,6 +77,8 @@ class W3DProjectedShadowManager : public ProjectedShadowManager
7677
void flushDecals(W3DShadowTexture *texture, ShadowType type); ///<empty queue by rendering all decals with given texture
7778

7879
private:
80+
Int renderProjectedTerrainShadow(W3DProjectedShadow *shadow, AABoxClass &box); ///<render shadow on map terrain.
81+
7982
W3DProjectedShadow *m_shadowList;
8083
W3DProjectedShadow *m_decalList;
8184
TextureClass *m_dynamicRenderTarget; ///<offscreen video memory texture used to render all shadow textures.
@@ -86,7 +89,12 @@ class W3DProjectedShadowManager : public ProjectedShadowManager
8689
W3DShadowTextureManager *m_W3DShadowTextureManager;
8790
Int m_numDecalShadows; ///< number of decal shadows in the system.
8891
Int m_numProjectionShadows; ///< number of projected shadows in the system.
89-
Int renderProjectedTerrainShadow(W3DProjectedShadow *shadow, AABoxClass &box); ///<render shadow on map terrain.
92+
93+
//Bounding rectangle around rendered portion of terrain.
94+
Int m_drawEdgeX;
95+
Int m_drawEdgeY;
96+
Int m_drawStartX;
97+
Int m_drawStartY;
9098
};
9199

92100
extern W3DProjectedShadowManager *TheW3DProjectedShadowManager;

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3019,7 +3019,9 @@ void W3DModelDraw::setModelState(const ModelConditionInfo* newState)
30193019
shadowInfo.m_sizeY = tmplate->getShadowSizeY();
30203020
shadowInfo.m_offsetX = tmplate->getShadowOffsetX();
30213021
shadowInfo.m_offsetY = tmplate->getShadowOffsetY();
3022-
m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw);
3022+
3023+
DEBUG_ASSERTCRASH(m_shadow == NULL, ("m_shadow is not NULL"));
3024+
m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw);
30233025
if (m_shadow)
30243026
{ m_shadow->enableShadowInvisible(m_fullyObscuredByShroud);
30253027
m_shadow->enableShadowRender(m_shadowEnabled);

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,6 @@ extern int nShadowStartBatchIndex;
8888
extern int SHADOW_VERTEX_SIZE;
8989
extern int SHADOW_INDEX_SIZE;
9090

91-
//Bounding rectangle around rendered portion of terrain.
92-
static Int drawEdgeX=0;
93-
static Int drawEdgeY=0;
94-
static Int drawStartX=0;
95-
static Int drawStartY=0;
96-
9791
//Global streaming vertex buffer with x,y,z,u,v type.
9892
struct SHADOW_DECAL_VERTEX //vertex structure passed to D3D
9993
{
@@ -215,6 +209,10 @@ W3DProjectedShadowManager::W3DProjectedShadowManager(void)
215209
m_W3DShadowTextureManager = NULL;
216210
m_shadowCamera = NULL;
217211
m_shadowContext= NULL;
212+
m_drawEdgeX = 0;
213+
m_drawEdgeY = 0;
214+
m_drawStartX = 0;
215+
m_drawStartY = 0;
218216
}
219217

220218
W3DProjectedShadowManager::~W3DProjectedShadowManager(void)
@@ -959,15 +957,15 @@ void W3DProjectedShadowManager::queueDecal(W3DProjectedShadow *shadow)
959957
Int startY=REAL_TO_INT_FLOOR(((objPos.Y+min_y)*mapScaleInv)) + borderSize;
960958
Int endY=REAL_TO_INT_CEIL(((objPos.Y+max_y)*mapScaleInv)) + borderSize;
961959

962-
startX = __max(startX,drawStartX);
963-
startX = __min(startX,drawEdgeX);
964-
startY = __max(startY,drawStartY);
965-
startY = __min(startY,drawEdgeY);
960+
startX = __max(startX,m_drawStartX);
961+
startX = __min(startX,m_drawEdgeX);
962+
startY = __max(startY,m_drawStartY);
963+
startY = __min(startY,m_drawEdgeY);
966964

967-
endX = __max(endX,drawStartX);
968-
endX = __min(endX,drawEdgeX);
969-
endY = __max(endY,drawStartY);
970-
endY = __min(endY,drawEdgeY);
965+
endX = __max(endX,m_drawStartX);
966+
endX = __min(endX,m_drawEdgeX);
967+
endY = __max(endY,m_drawStartY);
968+
endY = __min(endY,m_drawEdgeY);
971969

972970
//Check if decal too large to fit inside 65536 index buffer.
973971
//try clipping each direction to < 104 since that's more than
@@ -1276,33 +1274,40 @@ void W3DProjectedShadowManager::queueSimpleDecal(W3DProjectedShadow *shadow)
12761274

12771275
}
12781276

1277+
void W3DProjectedShadowManager::prepareShadows()
1278+
{
1279+
if (!TheTerrainRenderObject)
1280+
return;
1281+
1282+
WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
1283+
1284+
if (!hmap)
1285+
return;
1286+
1287+
//Find extents of visible terrain
1288+
m_drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1;
1289+
m_drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1;
1290+
if (m_drawEdgeX > (hmap->getXExtent()-1))
1291+
m_drawEdgeX = hmap->getXExtent()-1;
1292+
if (m_drawEdgeY > (hmap->getYExtent()-1))
1293+
m_drawEdgeY = hmap->getYExtent()-1;
1294+
m_drawStartX=hmap->getDrawOrgX();
1295+
m_drawStartY=hmap->getDrawOrgY();
1296+
}
1297+
12791298
Int W3DProjectedShadowManager::renderShadows(RenderInfoClass & rinfo)
12801299
{
1281-
///@todo: implement this method.
1282-
W3DProjectedShadow *shadow;
1283-
static AABoxClass aaBox;
1284-
static SphereClass sphere;
12851300
Int projectionCount=0;
12861301

1302+
if (!TheTerrainRenderObject)
1303+
return projectionCount;
1304+
12871305
if (!m_shadowList && !m_decalList)
12881306
return projectionCount; //there are no shadows to render.
12891307

1290-
//Find extents of visible terrain
1291-
if (TheTerrainRenderObject)
1292-
{
1293-
WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
1294-
1295-
drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1;
1296-
drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1;
1297-
if (drawEdgeX > (hmap->getXExtent()-1))
1298-
drawEdgeX = hmap->getXExtent()-1;
1299-
if (drawEdgeY > (hmap->getYExtent()-1))
1300-
drawEdgeY = hmap->getYExtent()-1;
1301-
drawStartX=hmap->getDrawOrgX();
1302-
drawStartY=hmap->getDrawOrgY();
1303-
}
1304-
else
1305-
return projectionCount;
1308+
W3DProjectedShadow *shadow;
1309+
static AABoxClass aaBox;
1310+
static SphereClass sphere;
13061311

13071312
//According to Nvidia there's a D3D bug that happens if you don't start with a
13081313
//new dynamic VB each frame - so we force a DISCARD by overflowing the counter.

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ Vector3 LightPosWorld[ MAX_SHADOW_LIGHTS ] =
6363
Vector3( 94.0161f, 50.499f, 200.0f)
6464
};
6565

66+
void PrepareShadows()
67+
{
68+
if (TheW3DProjectedShadowManager)
69+
TheW3DProjectedShadowManager->prepareShadows();
70+
}
71+
6672
//DECLARE_PERF_TIMER(shadowsRender)
6773
void DoShadows(RenderInfoClass & rinfo, Bool stencilPass)
6874
{

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
// DEFINITIONS ////////////////////////////////////////////////////////////////
6969
///////////////////////////////////////////////////////////////////////////////
7070
///@todo: Remove these globals since we no longer need W3D to call them for us.
71+
extern void PrepareShadows();
7172
extern void DoTrees(RenderInfoClass & rinfo);
7273
extern void DoShadows(RenderInfoClass & rinfo, Bool stencilPass);
7374
extern void DoParticles(RenderInfoClass & rinfo);
@@ -789,6 +790,10 @@ void RTS3DScene::renderOneObject(RenderInfoClass &rinfo, RenderObjClass *robj, I
789790
/**Draw everything that was submitted from this scene*/
790791
void RTS3DScene::Flush(RenderInfoClass & rinfo)
791792
{
793+
// TheSuperHackers @bugfix Now always prepares shadows to guarantee correct state before doing any
794+
// shadow draw calls. Originally just drawing shadows for trees would not properly prepare shadows.
795+
PrepareShadows();
796+
792797
//don't draw shadows in this mode because they interfere with destination alpha or are invisible (wireframe)
793798
if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
794799
DoShadows(rinfo, false); //draw all non-stencil shadows (decals) since they fall under other objects.

GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DProjectedShadow.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class W3DProjectedShadowManager : public ProjectedShadowManager
5757
Bool init(void); ///<allocate one-time shadow assets for length of entire game.
5858
void reset(void); ///<free all existing shadows - ready for next map.
5959
void shutdown(void); ///<free all assets prior to shutdown of entire game.
60+
void prepareShadows();
6061
Int renderShadows(RenderInfoClass & rinfo); ///<iterate over each object and render its shadow onto affected objects.
6162
void ReleaseResources(void); ///<release device dependent D3D resources.
6263
Bool ReAcquireResources(void); ///<allocate device dependent D3D resources.
@@ -76,6 +77,8 @@ class W3DProjectedShadowManager : public ProjectedShadowManager
7677
void flushDecals(W3DShadowTexture *texture, ShadowType type); ///<empty queue by rendering all decals with given texture
7778

7879
private:
80+
Int renderProjectedTerrainShadow(W3DProjectedShadow *shadow, AABoxClass &box); ///<render shadow on map terrain.
81+
7982
W3DProjectedShadow *m_shadowList;
8083
W3DProjectedShadow *m_decalList;
8184
TextureClass *m_dynamicRenderTarget; ///<offscreen video memory texture used to render all shadow textures.
@@ -86,7 +89,12 @@ class W3DProjectedShadowManager : public ProjectedShadowManager
8689
W3DShadowTextureManager *m_W3DShadowTextureManager;
8790
Int m_numDecalShadows; ///< number of decal shadows in the system.
8891
Int m_numProjectionShadows; ///< number of projected shadows in the system.
89-
Int renderProjectedTerrainShadow(W3DProjectedShadow *shadow, AABoxClass &box); ///<render shadow on map terrain.
92+
93+
//Bounding rectangle around rendered portion of terrain.
94+
Int m_drawEdgeX;
95+
Int m_drawEdgeY;
96+
Int m_drawStartX;
97+
Int m_drawStartY;
9098
};
9199

92100
extern W3DProjectedShadowManager *TheW3DProjectedShadowManager;

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3078,7 +3078,9 @@ void W3DModelDraw::setModelState(const ModelConditionInfo* newState)
30783078
shadowInfo.m_sizeY = tmplate->getShadowSizeY();
30793079
shadowInfo.m_offsetX = tmplate->getShadowOffsetX();
30803080
shadowInfo.m_offsetY = tmplate->getShadowOffsetY();
3081-
m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw);
3081+
3082+
DEBUG_ASSERTCRASH(m_shadow == NULL, ("m_shadow is not NULL"));
3083+
m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw);
30823084
if (m_shadow)
30833085
{ m_shadow->enableShadowInvisible(m_fullyObscuredByShroud);
30843086
m_shadow->enableShadowRender(m_shadowEnabled);

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,6 @@ extern int nShadowStartBatchIndex;
8888
extern int SHADOW_VERTEX_SIZE;
8989
extern int SHADOW_INDEX_SIZE;
9090

91-
//Bounding rectangle around rendered portion of terrain.
92-
static Int drawEdgeX=0;
93-
static Int drawEdgeY=0;
94-
static Int drawStartX=0;
95-
static Int drawStartY=0;
96-
9791
//Global streaming vertex buffer with x,y,z,u,v type.
9892
struct SHADOW_DECAL_VERTEX //vertex structure passed to D3D
9993
{
@@ -215,6 +209,10 @@ W3DProjectedShadowManager::W3DProjectedShadowManager(void)
215209
m_W3DShadowTextureManager = NULL;
216210
m_shadowCamera = NULL;
217211
m_shadowContext= NULL;
212+
m_drawEdgeX = 0;
213+
m_drawEdgeY = 0;
214+
m_drawStartX = 0;
215+
m_drawStartY = 0;
218216
}
219217

220218
W3DProjectedShadowManager::~W3DProjectedShadowManager(void)
@@ -959,15 +957,15 @@ void W3DProjectedShadowManager::queueDecal(W3DProjectedShadow *shadow)
959957
Int startY=REAL_TO_INT_FLOOR(((objPos.Y+min_y)*mapScaleInv)) + borderSize;
960958
Int endY=REAL_TO_INT_CEIL(((objPos.Y+max_y)*mapScaleInv)) + borderSize;
961959

962-
startX = __max(startX,drawStartX);
963-
startX = __min(startX,drawEdgeX);
964-
startY = __max(startY,drawStartY);
965-
startY = __min(startY,drawEdgeY);
960+
startX = __max(startX,m_drawStartX);
961+
startX = __min(startX,m_drawEdgeX);
962+
startY = __max(startY,m_drawStartY);
963+
startY = __min(startY,m_drawEdgeY);
966964

967-
endX = __max(endX,drawStartX);
968-
endX = __min(endX,drawEdgeX);
969-
endY = __max(endY,drawStartY);
970-
endY = __min(endY,drawEdgeY);
965+
endX = __max(endX,m_drawStartX);
966+
endX = __min(endX,m_drawEdgeX);
967+
endY = __max(endY,m_drawStartY);
968+
endY = __min(endY,m_drawEdgeY);
971969

972970
//Check if decal too large to fit inside 65536 index buffer.
973971
//try clipping each direction to < 104 since that's more than
@@ -1276,33 +1274,40 @@ void W3DProjectedShadowManager::queueSimpleDecal(W3DProjectedShadow *shadow)
12761274

12771275
}
12781276

1277+
void W3DProjectedShadowManager::prepareShadows()
1278+
{
1279+
if (!TheTerrainRenderObject)
1280+
return;
1281+
1282+
WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
1283+
1284+
if (!hmap)
1285+
return;
1286+
1287+
//Find extents of visible terrain
1288+
m_drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1;
1289+
m_drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1;
1290+
if (m_drawEdgeX > (hmap->getXExtent()-1))
1291+
m_drawEdgeX = hmap->getXExtent()-1;
1292+
if (m_drawEdgeY > (hmap->getYExtent()-1))
1293+
m_drawEdgeY = hmap->getYExtent()-1;
1294+
m_drawStartX=hmap->getDrawOrgX();
1295+
m_drawStartY=hmap->getDrawOrgY();
1296+
}
1297+
12791298
Int W3DProjectedShadowManager::renderShadows(RenderInfoClass & rinfo)
12801299
{
1281-
///@todo: implement this method.
1282-
W3DProjectedShadow *shadow;
1283-
static AABoxClass aaBox;
1284-
static SphereClass sphere;
12851300
Int projectionCount=0;
12861301

1302+
if (!TheTerrainRenderObject)
1303+
return projectionCount;
1304+
12871305
if (!m_shadowList && !m_decalList)
12881306
return projectionCount; //there are no shadows to render.
12891307

1290-
//Find extents of visible terrain
1291-
if (TheTerrainRenderObject)
1292-
{
1293-
WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
1294-
1295-
drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1;
1296-
drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1;
1297-
if (drawEdgeX > (hmap->getXExtent()-1))
1298-
drawEdgeX = hmap->getXExtent()-1;
1299-
if (drawEdgeY > (hmap->getYExtent()-1))
1300-
drawEdgeY = hmap->getYExtent()-1;
1301-
drawStartX=hmap->getDrawOrgX();
1302-
drawStartY=hmap->getDrawOrgY();
1303-
}
1304-
else
1305-
return projectionCount;
1308+
W3DProjectedShadow *shadow;
1309+
static AABoxClass aaBox;
1310+
static SphereClass sphere;
13061311

13071312
//According to Nvidia there's a D3D bug that happens if you don't start with a
13081313
//new dynamic VB each frame - so we force a DISCARD by overflowing the counter.

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DShadow.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ Vector3 LightPosWorld[ MAX_SHADOW_LIGHTS ] =
6363
Vector3( 94.0161f, 50.499f, 200.0f)
6464
};
6565

66+
void PrepareShadows()
67+
{
68+
if (TheW3DProjectedShadowManager)
69+
TheW3DProjectedShadowManager->prepareShadows();
70+
}
71+
6672
//DECLARE_PERF_TIMER(shadowsRender)
6773
void DoShadows(RenderInfoClass & rinfo, Bool stencilPass)
6874
{

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
// DEFINITIONS ////////////////////////////////////////////////////////////////
7070
///////////////////////////////////////////////////////////////////////////////
7171
///@todo: Remove these globals since we no longer need W3D to call them for us.
72+
extern void PrepareShadows();
7273
extern void DoTrees(RenderInfoClass & rinfo);
7374
extern void DoShadows(RenderInfoClass & rinfo, Bool stencilPass);
7475
extern void DoParticles(RenderInfoClass & rinfo);
@@ -827,6 +828,10 @@ void RTS3DScene::renderOneObject(RenderInfoClass &rinfo, RenderObjClass *robj, I
827828
/**Draw everything that was submitted from this scene*/
828829
void RTS3DScene::Flush(RenderInfoClass & rinfo)
829830
{
831+
// TheSuperHackers @bugfix Now always prepares shadows to guarantee correct state before doing any
832+
// shadow draw calls. Originally just drawing shadows for trees would not properly prepare shadows.
833+
PrepareShadows();
834+
830835
//don't draw shadows in this mode because they interfere with destination alpha or are invisible (wireframe)
831836
if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
832837
DoShadows(rinfo, false); //draw all non-stencil shadows (decals) since they fall under other objects.

0 commit comments

Comments
 (0)