bugfix(heightmap): Fix full terrain rebuild on every frame when DrawEntireTerrain is enabled#2846
bugfix(heightmap): Fix full terrain rebuild on every frame when DrawEntireTerrain is enabled#2846xezon wants to merge 2 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp | Core of the fix: m_updating correctly moved before the full-map early-return, m_needFullUpdate guard added, oversizeTerrain updated to pass (0,0) to preserve desired size, and setTerrainDrawSize refactored with m_desiredDrawWidth/Height. reset() still does not reinitialise m_desiredDrawWidth/Height (noted in previous review). |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp | New getDesiredTerrainDrawSize correctly separates DrawEntireTerrain from pitch-based logic and adds a scripted-camera (!m_isUserControlled) guard; setTerrainDrawSize is now only called when a size is actually determined. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp | Correctly removes DrawEntireTerrain and stretchTerrain overrides from the constructor and createDrawArea; createDrawArea now simply clamps to map width/height. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp | Replaces hardcoded 7 with TERRAIN_LOD_MAX and removes the stale == 5 null-assignment for the now-deleted TERRAIN_LOD_STRETCH_CLOUDS. |
| Core/GameEngine/Include/GameClient/TerrainVisual.h | Removes three legacy LOD enum entries (STRETCH_NO_CLOUDS, HALF_CLOUDS, STRETCH_CLOUDS) and their name-table strings; remaining values renumber automatically. |
| Core/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h | Adds m_desiredDrawWidth / m_desiredDrawHeight member declarations alongside the existing oversize fields. |
| Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h | Declares the new private helper getDesiredTerrainDrawSize returning a bool and populating an ICoord2D. |
| Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h | Removes STRETCH_DRAW_WIDTH / STRETCH_DRAW_HEIGHT constants; NORMAL_DRAW_* and LOW_ANGLE_DRAW_* constants unchanged. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DTreeBuffer.cpp | Removes a large block of commented-out panel-tree code that relied on the now-deleted m_useHalfHeightMap / m_stretchTerrain flags. |
| GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h | Marks m_stretchTerrain and m_useHalfHeightMap as Legacy, unused without removing them, preserving binary layout while communicating intent. |
| GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp | Removes the TERRAIN_LOD_HALF_CLOUDS step in calculateTerrainLOD, skipping directly from NO_WATER to DISABLE. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[W3DView::updateTerrain called each frame] --> B[getDesiredTerrainDrawSize]
B --> C{DrawEntireTerrain?}
C -- Yes --> D{heightMap available?}
D -- Yes --> E[dimensions = map XExtent x YExtent]
D -- No --> F[return false - setTerrainDrawSize skipped]
C -- No --> G{scripted camera or high pitch?}
G -- Yes --> H[dimensions = NORMAL_DRAW_WIDTH x HEIGHT]
G -- No --> I[dimensions = LOW_ANGLE_DRAW_WIDTH x HEIGHT]
E --> J[return true]
H --> J
I --> J
J --> K[setTerrainDrawSize width height]
K --> L{width or height > 0?}
L -- Yes --> M[update m_desiredDrawWidth/Height]
L -- No --> N[keep existing m_desiredDrawWidth/Height]
M --> O[effective = max oversizeW desiredW - clamped to map extent]
N --> O
O --> P[updateCenter]
P --> Q{m_x >= XExtent AND m_y >= YExtent?}
Q -- Yes - full map covered --> R{m_needFullUpdate?}
R -- Yes --> S[updateBlock full terrain - m_needFullUpdate = false]
R -- No --> T[skip rebuild - m_updating = false - return early]
S --> T
Q -- No - partial coverage --> U[standard origin tracking and partial block updates]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[W3DView::updateTerrain called each frame] --> B[getDesiredTerrainDrawSize]
B --> C{DrawEntireTerrain?}
C -- Yes --> D{heightMap available?}
D -- Yes --> E[dimensions = map XExtent x YExtent]
D -- No --> F[return false - setTerrainDrawSize skipped]
C -- No --> G{scripted camera or high pitch?}
G -- Yes --> H[dimensions = NORMAL_DRAW_WIDTH x HEIGHT]
G -- No --> I[dimensions = LOW_ANGLE_DRAW_WIDTH x HEIGHT]
E --> J[return true]
H --> J
I --> J
J --> K[setTerrainDrawSize width height]
K --> L{width or height > 0?}
L -- Yes --> M[update m_desiredDrawWidth/Height]
L -- No --> N[keep existing m_desiredDrawWidth/Height]
M --> O[effective = max oversizeW desiredW - clamped to map extent]
N --> O
O --> P[updateCenter]
P --> Q{m_x >= XExtent AND m_y >= YExtent?}
Q -- Yes - full map covered --> R{m_needFullUpdate?}
R -- Yes --> S[updateBlock full terrain - m_needFullUpdate = false]
R -- No --> T[skip rebuild - m_updating = false - return early]
S --> T
Q -- No - partial coverage --> U[standard origin tracking and partial block updates]
Reviews (3): Last reviewed commit: "bugfix(heightmap): Prevent full terrain ..." | Re-trigger Greptile
| Bool m_stretchTerrain; | ||
| Bool m_useHalfHeightMap; | ||
| Bool m_stretchTerrain; // TheSuperHackers @info Legacy, unused | ||
| Bool m_useHalfHeightMap; // TheSuperHackers @info Legacy, unused |
There was a problem hiding this comment.
I am not sure if it should be removed or left. The settings still exist in the game INI files, and this allows to see that it does nothing if someone searched for it.
|
|
||
| BaseHeightMapRenderObjClass *newROBJ = nullptr; | ||
| if (TheGlobalData->m_terrainLOD==7) { | ||
| if (TheGlobalData->m_terrainLOD == TERRAIN_LOD_MAX) { |
There was a problem hiding this comment.
7 previously referred to TERRAIN_LOD_MAX
| newROBJ = NEW_REF( FlatHeightMapRenderObjClass, () ); | ||
| } | ||
| } | ||
| if (TheGlobalData->m_terrainLOD == 5) |
There was a problem hiding this comment.
5 previously referred to enum value TERRAIN_LOD_STRETCH_CLOUDS, which was removed.
It set newROBJ to null which meant it would have leaked here. Very strange code.
2b94631 to
5ce335a
Compare
|
Thanks for taking this on, @xezon - I reviewed the branch locally and I'm happy to see it land in place of #2786. The approach here is cleaner than mine: making A few things I checked while reviewing: • I also confirmed it carries over the the branch doesn't compile for the base Generals target (Zero Hour / GeneralsMD builds fine). The chore commit ( ffe9ce6 ) removes Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp:1646
case TERRAIN_LOD_HALF_CLOUDS: curLOD = TERRAIN_LOD_DISABLE; break;
case TERRAIN_LOD_NO_WATER: curLOD = TERRAIN_LOD_HALF_CLOUDS; break;So the base-game compile fails with The fix is just to mirror the GeneralsMD change — collapse those two lines to: case TERRAIN_LOD_NO_WATER: curLOD = TERRAIN_LOD_DISABLE; break;That's the only dangling reference I found - grepping the tree, the removed LGTM from my side. Thanks for the cleanup commit too — good to see the dead stretch-terrain / half-height-map paths finally gone ! |
|
There's an issue with building placement that I noticed with this branch & gen_zh_building_placement.mp4 |
|
I ran the new chat "5.6-sol" model over this and it had this to say:
and indeed it does appear to read the map height array out of bounds for very small maps after the changes made in this PR, i tested with a 30x30 map, but also maps like "[NoMoney] 1v1 Survival" would be affected, still pretty niche though, Could be verified using this at WorldHeightMap.h:260 UnsignedByte getDisplayHeight(Int x, Int y)
{
const Int mapX = x + m_drawOriginX;
const Int mapY = y + m_drawOriginY;
const Int ndx = mapX + m_width * mapY;
DEBUG_ASSERTCRASH(
//mapX >= 0 && mapX < m_width &&
//mapY >= 0 && mapY < m_height &&
ndx >= 0 && ndx < m_dataSize,
("Height sample (%d, %d) is outside %dx%d heightmap; index %d, size %d",
mapX, mapY, m_width, m_height, ndx, m_dataSize));
return m_data[ndx];
} |
…d Half Height Map (#2846)
…rawEntireTerrain is enabled (#2846)
5ce335a to
ac2971e
Compare
The branch was outdated. Is fixed after Rebase. |

Merge with Rebase
This change fixes the terrain update for DrawEntireTerrain.
It has 2 commits:
The first commit removes the legacy and unused code for stretched terrain and half height map.
The second commit fixes the terrain update for DrawEntireTerrain. W3DView tells the HeightMapRenderObjClass which size to use. The terrain oversize logic for the scripted camera was adapted to indirectly account for DrawEntireTerrain as well. All DrawEntireTerrain specific knowledge was removed from height map.
TODO