From c95c171aff159632773fca6d8287f10e911e4350 Mon Sep 17 00:00:00 2001 From: Joseph Ameer Aziz Date: Sat, 30 May 2026 07:55:50 +0300 Subject: [PATCH 1/2] bugfix(camera): Fix Generals terrain rendering black for one frame on far camera jumps The shroud destination texture in Generals was allocated at visible terrain size rather than full map size. This caused the shroud to render only the visible region based on getDrawOrgX/Y, which is stale before W3DDisplay::updateViews runs. On far camera jumps such as radar clicks, the shroud rendered the wrong region of the map for one frame, causing newly visible terrain to appear black. Unifies the Generals shroud destination texture allocation with Zero Hour, which allocates at full map size and always renders the full shroud each frame. This makes the shroud rendering independent of the draw origin state. --- .../Source/W3DDevice/GameClient/W3DShroud.cpp | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp index abead507fd4..ac6674bcdd1 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp @@ -120,13 +120,17 @@ void W3DShroud::init(WorldHeightMap *pMap, Real worldCellSizeX, Real worldCellSi //Precompute a bounding box for entire shroud layer if (pMap) { - m_numCellsX = REAL_TO_INT_CEIL((Real)(pMap->getXExtent() - 1 - pMap->getBorderSize()*2)*MAP_XY_FACTOR/m_cellWidth); - m_numCellsY = REAL_TO_INT_CEIL((Real)(pMap->getYExtent() - 1 - pMap->getBorderSize()*2)*MAP_XY_FACTOR/m_cellHeight); + m_numCellsX = REAL_TO_INT_CEIL((Real)(pMap->getXExtent() - 1 - pMap->getBorderSizeInline()*2)*MAP_XY_FACTOR/m_cellWidth); + m_numCellsY = REAL_TO_INT_CEIL((Real)(pMap->getYExtent() - 1 - pMap->getBorderSizeInline()*2)*MAP_XY_FACTOR/m_cellHeight); //Maximum visible cells will depend on maximum drawable terrain size plus 1 for partial cells (since //shroud cells are larger than terrain cells). dstTextureWidth=m_numMaxVisibleCellsX=REAL_TO_INT_FLOOR((Real)(pMap->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; dstTextureHeight=m_numMaxVisibleCellsY=REAL_TO_INT_FLOOR((Real)(pMap->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1; + + dstTextureWidth = m_numCellsX; + dstTextureHeight = m_numCellsY; + dstTextureWidth += 2; //enlarge by 2 pixels so we can have a border color all the way around. unsigned int depth = 1; dstTextureHeight += 2; //enlarge by 2 pixels so we can have border color all the way around. @@ -225,7 +229,7 @@ void W3DShroud::ReleaseResources() Bool W3DShroud::ReAcquireResources() { if (!m_dstTextureWidth) - return TRUE; //nothing to reaquire since shroud was never initialized with valid data + return TRUE; //nothing to reacquire since shroud was never initialized with valid data DEBUG_ASSERTCRASH( m_pDstTexture == nullptr, ("ReAcquire of existing shroud texture")); @@ -613,15 +617,23 @@ void W3DShroud::render(CameraClass *cam) WorldHeightMap *hm=TheTerrainRenderObject->getMap(); - Int visStartX=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgX()-hm->getBorderSize())*MAP_XY_FACTOR/m_cellWidth); //start of rendered heightmap rectangle + Int visStartX=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgX()-hm->getBorderSizeInline())*MAP_XY_FACTOR/m_cellWidth); //start of rendered heightmap rectangle if (visStartX < 0) visStartX = 0; //no shroud is applied in border area so it always starts at > 0 - Int visStartY=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgY()-hm->getBorderSize())*MAP_XY_FACTOR/m_cellHeight); + Int visStartY=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgY()-hm->getBorderSizeInline())*MAP_XY_FACTOR/m_cellHeight); if (visStartY < 0) visStartY = 0; //no shroud is applied in border area so it always starts at > 0 + + visStartX = 0; + visStartY = 0; + Int visEndX=visStartX+REAL_TO_INT_FLOOR((Real)(hm->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; //size of rendered heightmap rectangle Int visEndY=visStartY+REAL_TO_INT_FLOOR((Real)(hm->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1; + + visEndX = m_numCellsX; + visEndY = m_numCellsY; + if (visEndX > m_numCellsX) { visStartX -= visEndX - m_numCellsX; //shift visible rectangle to fall within terrain bounds From 0a1870efa1d99047cecd7f9fbab55b00aada2e39 Mon Sep 17 00:00:00 2001 From: Joseph Ameer Aziz Date: Sat, 30 May 2026 15:36:40 +0300 Subject: [PATCH 2/2] Add Comments and blank line for merge purposes --- .../Source/W3DDevice/GameClient/W3DShroud.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp index ac6674bcdd1..26a5a2f32da 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp @@ -137,6 +137,7 @@ void W3DShroud::init(WorldHeightMap *pMap, Real worldCellSizeX, Real worldCellSi TextureLoader::Validate_Texture_Size((unsigned int &)dstTextureWidth,(unsigned int &)dstTextureHeight, depth); } + UnsignedInt srcWidth,srcHeight; srcWidth=m_numCellsX; @@ -624,13 +625,14 @@ void W3DShroud::render(CameraClass *cam) if (visStartY < 0) visStartY = 0; //no shroud is applied in border area so it always starts at > 0 + // Do it all [3/11/2003] visStartX = 0; visStartY = 0; Int visEndX=visStartX+REAL_TO_INT_FLOOR((Real)(hm->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; //size of rendered heightmap rectangle Int visEndY=visStartY+REAL_TO_INT_FLOOR((Real)(hm->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1; - + // Do it all [3/11/2003] visEndX = m_numCellsX; visEndY = m_numCellsY;