Skip to content

Fix do_view_track - #7731

Open
wookieejedi wants to merge 1 commit into
scp-fs2open:masterfrom
wookieejedi:fix-do-view-track
Open

Fix do_view_track#7731
wookieejedi wants to merge 1 commit into
scp-fs2open:masterfrom
wookieejedi:fix-do-view-track

Conversation

@wookieejedi

@wookieejedi wookieejedi commented Aug 21, 2026

Copy link
Copy Markdown
Member

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() 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;

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;
@wookieejedi wookieejedi added regression A bug introduced by a new feature that breaks something which used to work. fix A fix for bugs, not-a-bugs, and/or regressions. labels Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix A fix for bugs, not-a-bugs, and/or regressions. regression A bug introduced by a new feature that breaks something which used to work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants