Skip to content

bugfix(view): Fix and improve camera area constraints and camera pivoting#2506

Merged
xezon merged 2 commits intoTheSuperHackers:mainfrom
xezon:xezon/fix-view-constraints
Mar 30, 2026
Merged

bugfix(view): Fix and improve camera area constraints and camera pivoting#2506
xezon merged 2 commits intoTheSuperHackers:mainfrom
xezon:xezon/fix-view-constraints

Conversation

@xezon
Copy link
Copy Markdown

@xezon xezon commented Mar 30, 2026

Merge with Rebase

The camera area constraints are now recalculated when the camera zoom changes, for example because of terrain elevation changes in the camera's view. The camera will be smoothly pushed away from the constraints, but not while the user is scrolling, to make the scrolling along the map border a pleasant experience. This behavior ensures that the view can reach and see all areas of the map, and especially the bottom map border. The camera can now also be moved a bit closer to the map edges. All this is very useful to avoid issues where some units or structures are not possible to get into the view, for example a Chinook at a Supply at the top edge of a map (TheSuperHackers/GeneralsRankedMaps#7). Or a Dozer at the bottom edge of a valley on Defcon 6.

Additionally the camera pivoting was fixed. The camera now repositions correctly towards its ground pivot instead of zooming to a pivot that is not aligned to the terrain ground. User facing this looks identical, but technically it is different. Scrolling to different locations of the map will now keep the camera pivot always correctly centered to the ground. It is no longer necessary to press Numpad 5 to recenter the pivot.

This change also implicitly fixes the broken scripted camera in the USA 01 intro, which was introduced by change #2291.

Known issues

The scripted camera will not always position perfectly at the original locations when the ground pivot was changed. This will be fixed in a future change.

@xezon xezon added this to the Camera Improvements milestone Mar 30, 2026
@xezon xezon added Bug Something is not working right, typically is user facing Enhancement Is new feature or request Major Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour labels Mar 30, 2026
@xezon
Copy link
Copy Markdown
Author

xezon commented Mar 30, 2026

I recreated #2480 because I merged it incorrectly to main branch prior.

@xezon xezon force-pushed the xezon/fix-view-constraints branch from 9c4e01a to 41209ea Compare March 30, 2026 17:36
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This PR overhauls camera area constraint handling and camera pivoting in W3DView, fixing issues where units near map edges (particularly the bottom border) could be unreachable and where camera pivoting was misaligned to terrain ground level.

Key changes:

  • Camera pivot fix: movePivotToGround() smoothly repositions the camera pivot to the terrain ground height each frame, replacing the old zoom-only approach. Middle-click and Numpad 5 resets now correctly call userResetPivotToGround() before resetting angle/pitch/zoom in both Generals and GeneralsMD.
  • Dynamic constraint recalculation: Camera area constraints are now invalidated whenever zoom or pivot changes. While scrolling, recalculation is deferred to m_recalcCameraConstraintsAfterScrolling to avoid jarring edge collisions mid-scroll; they flush when scrolling stops.
  • Constraint clipping refactored: The per-frame clipping logic is extracted from setCameraTransform into the new updateCameraAreaConstraints / clipCameraIntoAreaConstraints helpers, making the flow clearer and eliminating the duplicate clipping that existed in buildCameraPosition.
  • Offset reduction: calcCameraAreaOffset now applies a 0.85f multiplier so the camera can scroll closer to map edges, and uses the full screen height (instead of 95%) when looking down.
  • Base type utilities: zero() helpers and isInRegion accessors added to Region2D, IRegion2D, and related structs. Region3D::isInRegionWithZ is renamed to isInRegion (no existing callers of the old name).
  • WWMath::Inverse_Lerp added and used for smooth pitch-based repositioning strength in movePivotToGround.

Confidence Score: 5/5

Safe to merge; all remaining findings are minor style suggestions with no impact on runtime behavior.

No P0 or P1 issues found. The three findings are P2: a comment date from 2025, a duplicate separator line, and a missing division-by-zero guard in a new utility function whose sole call site cannot trigger it. The logic restructuring is well-reasoned, the deferred constraint recalculation state machine is coherent, and the removal of duplicate clipping from buildCameraPosition is correct.

Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp — comment date convention and duplicate separator.

Important Files Changed

Filename Overview
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp Core camera logic overhaul: introduces zoomCameraToDesiredHeight/movePivotToGround split, deferred constraint recalc after scrolling, and moves clipping out of setCameraTransform into updateCameraAreaConstraints; one date-convention violation and a duplicate separator found.
Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h Adds resetPivotToGround override, m_recalcCameraConstraintsAfterScrolling member, and new private helper declarations; forceCameraAreaConstraintRecalc now lazily invalidates instead of eagerly recalculating.
Core/GameEngine/Include/GameClient/View.h Adds resetPivotToGround virtual method to the base View interface and exposes userResetPivotToGround as a user-action helper.
Core/Libraries/Include/Lib/BaseType.h Adds zero() helpers to RealRange/Coord2D/ICoord2D/Region2D/IRegion2D/IRegion3D, isInRegion(x,y) to Region2D/IRegion2D, and renames Region3D::isInRegionWithZ to isInRegion; no existing callers of the old name found.
Core/Libraries/Source/WWVegas/WWMath/wwmath.h Adds Inverse_Lerp(float/double) utility functions and renames Lerp parameter from 'lerp' to 't'; no division-by-zero guard in Inverse_Lerp.
Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp resetCamera now uses userResetPivotToGround + individual user actions instead of a positional resetCamera call, aligning Generals and GeneralsMD implementations.
GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp Same resetCamera refactor as Generals counterpart.
Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp Middle-click camera reset now calls userResetPivotToGround before resetting angle/pitch/zoom.
GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp Same middle-click pivot reset as Generals counterpart.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[W3DView::update] --> B{m_okToAdjustHeight?}
    B -- No --> H
    B -- Yes --> C{adjustZoomWhenScrolling or adjustZoomWhenNotScrolling?}
    C -- No --> E
    C -- Yes --> D1[zoomCameraToDesiredHeight]
    D1 --> D2[movePivotToGround]
    D2 --> D3{isZoomingOrMovingPivot?}
    D3 -- No --> E
    D3 -- Yes --> D4{isScrolling?}
    D4 -- Yes --> D5[m_recalcCameraConstraintsAfterScrolling = true]
    D4 -- No --> D6[m_cameraAreaConstraintsValid = false]
    D5 --> E
    D6 --> E
    E{m_recalcCameraConstraintsAfterScrolling && !isScrolling?}
    E -- Yes --> F[m_cameraAreaConstraintsValid = false]
    E -- No --> G
    F --> G
    G{isTimeFast?}
    G -- Yes --> RET[return early]
    G -- No --> H[updateCameraAreaConstraints]
    H --> H1{m_cameraAreaConstraintsValid?}
    H1 -- No --> H2[calcCameraAreaConstraints]
    H2 --> H3
    H1 -- Yes --> H3{isWithinCameraAreaConstraints?}
    H3 -- No --> H4[clipCameraIntoAreaConstraints + m_recalcCamera=true]
    H3 -- Yes --> I
    H4 --> I{m_recalcCamera?}
    I -- Yes --> J[setCameraTransform]
    I -- No --> K[End]
    J --> K
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp
Line: 1419

Comment:
**Comment date references prior year**

This newly added comment references `26/10/2025`, which is prior to the current year (2026). Per the project's convention, dates in newly created comments should reflect the current year.

```suggestion
	// TheSuperHackers @bugfix xezon 26/10/2026 The camera area constraints are now recalculated when
```

**Rule Used:** What: Flag newly created code comments that refere... ([source](https://app.greptile.com/review/custom-context?memory=fd72a556-4fd8-4db4-8b08-8e51516a64ad))

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp
Line: 2455-2456

Comment:
**Duplicate separator line**

Two consecutive `//---` separator lines appear before `resetPivotToGround`. The rest of the codebase consistently uses only a single separator line between functions. The extra line is likely unintentional.

```suggestion
//-------------------------------------------------------------------------------------------------
void W3DView::resetPivotToGround( void )
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: Core/Libraries/Source/WWVegas/WWMath/wwmath.h
Line: 278-285

Comment:
**`Inverse_Lerp` has no division-by-zero guard**

When `a == b`, `(b - a)` is `0.0f` and both overloads will produce `NaN` or `±Inf`. The current call site in `movePivotToGround` uses compile-time distinct constants (`DEG_TO_RADF(15.f)` and `DEG_TO_RADF(30.f)`), so there is no current bug. However, as a general-purpose utility exposed in a header, it is worth adding an early-return guard to prevent silent issues in future callers.

```cpp
WWINLINE float WWMath::Inverse_Lerp(float a, float b, float v)
{
    const float denom = b - a;
    return (denom != 0.0f) ? (v - a) / denom : 0.0f;
}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "bugfix(view): Fix and improve camera piv..." | Re-trigger Greptile

Copy link
Copy Markdown

@Skyaero42 Skyaero42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@xezon xezon merged commit 1845a2d into TheSuperHackers:main Mar 30, 2026
23 checks passed
@xezon xezon deleted the xezon/fix-view-constraints branch March 30, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something is not working right, typically is user facing Enhancement Is new feature or request Gen Relates to Generals Major Severity: Minor < Major < Critical < Blocker ZH Relates to Zero Hour

Projects

None yet

2 participants