Skip to content

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

Open
xezon wants to merge 2 commits intoTheSuperHackers:mainfrom
xezon:xezon/fix-view-constraints
Open

bugfix(view): Fix and improve camera area constraints and camera pivoting#2480
xezon wants to merge 2 commits intoTheSuperHackers:mainfrom
xezon:xezon/fix-view-constraints

Conversation

@xezon
Copy link
Copy Markdown

@xezon xezon commented Mar 21, 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.

TODO

  • Replicate in Generals
  • Add pull id to commits

@xezon xezon added this to the Camera Improvements milestone Mar 21, 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 21, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 21, 2026

Greptile Summary

This PR fixes and improves camera area constraints and camera pivoting in the W3D view layer. The camera's area constraints are now recalculated dynamically when zoom changes (e.g. due to terrain elevation), the pivot point is smoothly moved to the ground during normal play, and the allowed scroll area is expanded slightly (15%) closer to map edges — together resolving visibility issues with units near elevated terrain edges.

Key changes:

  • movePivotToGround() — new function that progressively adjusts m_groundLevel toward the terrain height beneath the pivot and repositions the camera along its view direction accordingly.
  • zoomCameraToDesiredHeight() — existing zoom logic extracted into its own function for clarity.
  • updateCameraAreaConstraints() / clipCameraIntoAreaConstraints() / isWithinCameraAreaConstraints() — constraint enforcement broken out of setCameraTransform() into dedicated methods called every frame from update().
  • m_recalcCameraConstraintsAfterScrolling — new flag that defers constraint recalculation until after the user finishes scrolling.
  • forceCameraAreaConstraintRecalc() simplified to just invalidate the cached constraints rather than recomputing immediately.
  • resetPivotToGround() — new virtual method and userResetPivotToGround() user-action wrapper called on middle-click reset and camera-reset UI button.
  • Region3D::isInRegionWithZ renamed to isInRegion (no remaining callers of the old name); zero() and isInRegion() helpers added to several region/coordinate structs.
  • Inverse_Lerp added to wwmath.h (float and double overloads) and used to blend repositioning strength by camera pitch.

Confidence Score: 5/5

Safe to merge — all remaining findings are minor style/polish issues that do not affect runtime correctness.

The logic changes are well-structured and the core camera constraint/pivot redesign is sound. The only open findings are a stale date annotation (2025 instead of 2026), a duplicate separator line, and a missing division-by-zero guard in Inverse_Lerp at a call site that is provably safe with compile-time constants. None of these affect game behavior.

No files require special attention for merge safety; W3DView.cpp contains the two cosmetic issues worth addressing before final commit.

Important Files Changed

Filename Overview
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp Core of the PR: refactors camera area constraints and pivot tracking into dedicated methods; has a stale date comment (2025) and a duplicate //--- separator.
Core/Libraries/Source/WWVegas/WWMath/wwmath.h Adds Inverse_Lerp (float and double overloads); lacks a division-by-zero guard for the a == b case.
Core/Libraries/Include/Lib/BaseType.h Adds zero() helpers and isInRegion() to several structs; renames Region3D::isInRegionWithZ to isInRegion with no remaining callers of the old name.
Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h Declares resetPivotToGround() override, new private helpers, and m_recalcCameraConstraintsAfterScrolling.
Core/GameEngine/Include/GameClient/View.h Adds resetPivotToGround() virtual method and userResetPivotToGround() user-action wrapper to the base View interface.
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:
**Date in comment references prior year (2025)**

The inline date `26/10/2025` in this annotation is from 2025, which is prior to the current year (2026). Per project convention, code comments should not reference dates prior to 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**

There are two consecutive `//---` separator lines between `initHeightForMap()` and `resetPivotToGround()`. This appears to be a copy-paste artifact — only a single separator is used elsewhere in the file.

```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 guard against division by zero**

When `a == b`, `(b - a)` is `0` and the function produces `NaN`/`Inf`. The current call site in `movePivotToGround()` passes compile-time constants (`DEG_TO_RADF(15.f)` vs `DEG_TO_RADF(30.f)`) so it is always safe there, but as a new general-purpose API it is a latent footgun for future callers. Consider adding a safety guard:

```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;
}

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

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

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

@xezon xezon force-pushed the xezon/fix-view-constraints branch 2 times, most recently from 04d2b61 to 8d78c38 Compare March 21, 2026 19:50
Copy link
Copy Markdown

@Mauller Mauller left a comment

Choose a reason for hiding this comment

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

I don't see any major issues at first glance, but i would perform some replay checking due to the new initialisation of class variables.

@xezon xezon force-pushed the xezon/fix-view-constraints branch 3 times, most recently from f56249d to 7092cdf Compare March 26, 2026 18:41
Copy link
Copy Markdown

@Mauller Mauller left a comment

Choose a reason for hiding this comment

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

Looks good after a second look over

@xezon xezon force-pushed the xezon/fix-view-constraints branch from 7092cdf to 9c4e01a Compare March 29, 2026 09:21
@xezon
Copy link
Copy Markdown
Author

xezon commented Mar 29, 2026

Replicated in Generals with conflict

D:\Projects\TheSuperHackers\GeneralsGameCode>FOR /F "delims=" %b IN ('git merge-base --fork-point main') DO git diff %b  1>changes.patch

D:\Projects\TheSuperHackers\GeneralsGameCode>git diff 8cf9456cee31bbee015dffe6ac87376e361bcd04  1>changes.patch

D:\Projects\TheSuperHackers\GeneralsGameCode>git apply -p2 --directory=Generals --reject --whitespace=fix changes.patch
Checking patch Generals/GameEngine/Include/GameClient/View.h...
error: Generals/GameEngine/Include/GameClient/View.h: No such file or directory
Checking patch Generals/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h...
error: Generals/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h: No such file or directory
Checking patch Generals/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp...
error: Generals/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp: No such file or directory
Checking patch Generals/Libraries/Include/Lib/BaseType.h...
error: Generals/Libraries/Include/Lib/BaseType.h: No such file or directory
Checking patch Generals/Libraries/Source/WWVegas/WWMath/wwmath.h...
error: Generals/Libraries/Source/WWVegas/WWMath/wwmath.h: No such file or directory
Checking patch Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp...
error: while searching for:
//------------------------------------------------------------------------------
void InGameUI::resetCamera()
{
        ViewLocation currentView;
        TheTacticalView->getLocation( &currentView );
        TheTacticalView->resetCamera( &currentView.getPosition(), 1, 0.0f, 0.0f );
}

//------------------------------------------------------------------------------

error: patch failed: Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp:4503
Checking patch Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp...
Hunk #1 succeeded at 315 (offset 1 line).
Applying patch Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp with 1 reject...
Rejected hunk #1.
Applied patch Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp cleanly.

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