Fix do_view_track - #7731
Open
wookieejedi wants to merge 1 commit into
Open
Conversation
Root cause Commit 87ea04f "change atan2_safe to atan2" (July 2024) replaced FSO's custom atan2_safe with the standard atan2. The old function returned a different range: range returned old atan2_safe (-PI/2, 3PI/2) standard atan2 (-PI, PI] do_view_track_target() in playercontrol.cpp:417 computes the padlock heading as a raw subtraction of two extracted headings: chase_slew_angles.h = forward_angles.h - view_angles.h; The forward vector rotated into the player's own frame is always (0,0,1), so forward_angles.h is always PI/2. With the old range that subtraction landed in (-PI, PI) — symmetric, and the ±120° neck clamp below applied evenly. With standard atan2 it lands in [-PI/2, 3PI/2) instead: -90° to the left, but +270° to the right. Leftward travel dead-ends at 90° (straight abeam) instead of 120°, and the moment a target crosses just past the player's left shoulder the value wraps to a large positive number and gets clamped to +120° — the camera snaps hard right. The fix Rather than reverting atan2_safe (standard atan2 is correct, and other callers depend on the new range), this PR wraps the heading difference back into (-PI, PI] before the neck clamp, using the same "over-the-top correction" idiom already used by do_view_external() a few hundred lines down: // Do over-the-top correction. // Headings are extracted with atan2, so each one lies in (-PI, PI] and their difference can be // nearly a full circle in either direction. Without wrapping it back into (-PI, PI], a target just // past the left shoulder reads as being almost all the way around to the right instead. if (chase_slew_angles.h > PI) chase_slew_angles.h -= PI2; else if (chase_slew_angles.h < -PI) chase_slew_angles.h += PI2;
JohnAFernandez
approved these changes
Aug 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported bug
https://www.hard-light.net/forums/index.php?topic=100019.0;topicseen
"I've noticed that every FSO version since 24.2.0 has changed the target padlock behavior. The camera used to have an equally wide range leftward and rightward, but now it's significantly smaller to the left. This means that if I padlock a target to my left and misjudge the smaller range, the camera swings as far as it can to the right instead. I have to roll my ship over constantly to track targets more effectively, which is a major annoyance because I use the padlock key constantly in dogfights."
Root cause
Commit 87ea04f "change atan2_safe to atan2" (July 2024) replaced FSO's custom atan2_safe with the standard atan2. The old function returned a different range:
range returned
old atan2_safe (-PI/2, 3PI/2)
standard atan2 (-PI, PI]
do_view_track_target()inplayercontrol.cpp:417computes the padlock heading as a raw subtraction of two extracted headings:chase_slew_angles.h = forward_angles.h - view_angles.h;The forward vector rotated into the player's own frame is always (0,0,1), so
forward_angles.his always PI/2. With the old range that subtraction landed in (-PI, PI) — symmetric, and the ±120° neck clamp below applied evenly. With standard atan2 it lands in [-PI/2, 3PI/2) instead: -90° to the left, but +270° to the right.Leftward travel dead-ends at 90° (straight abeam) instead of 120°, and the moment a target crosses just past the player's left shoulder the value wraps to a large positive number and gets clamped to +120° — the camera snaps hard right.
The fix
Rather than reverting atan2_safe (standard atan2 is correct, and other callers depend on the new range), this PR wraps the heading difference back into (-PI, PI] before the neck clamp, using the same "over-the-top correction" idiom already used by
do_view_external()a few hundred lines down: