diff --git a/context/cockpit-view.md b/context/cockpit-view.md index 46a79f7..ce84d47 100644 --- a/context/cockpit-view.md +++ b/context/cockpit-view.md @@ -199,3 +199,15 @@ the shell green), `BT_COP_DUMP` (per-batch punch/bbox), `BT_EYE_FWD=` (eye po - Uses: [[bgf-format]] (PUNCH, vertex tags) · [[rendering]] (ramp model, skeleton branch) - Feeds: [[gauges-hud]] (the HUD overlays this view) · [[subsystems]] (gyro, task #56) - Gotchas: [[reconstruction-gotchas]] §14 (LookAt axis guess), §15 (per-patch edge counting) + +## Torso-elevation aim -> EYE PITCH (fixed 2026-07-19) [T2, pixel-calibrated] +User+tester report "pitch does not work": the Torso sim integrated R/F (stick-Y) +into `currentElevation` (authored limits/rates) but NOTHING consumed it — the +view and the aim ray (camera basis, `BTGetAimRay`) never pitched. Fix: the +per-frame HUD tick composes `eyepointRotation = EulerAngles(lookPitch + elev, +lookYaw, 0)` (mech4.cpp; look component stored by `BTCommitLookState` in +`gBTLookPitch/Yaw`; elevation via the new `BTGetTorsoElevation` torso.cpp +bridge). `DPLEyeRenderable` reads it every frame -> the view AND the boresight +aim pitch together (crosshair stays screen-centred, authentic). Sign +pixel-calibrated with `BT_FORCE_ELEV=<-1..1>` screenshots: axis +1 (key R) = +aim UP. The torso GEOMETRY does not tilt — only the eye, like the pod. diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index a11e74a..fd5a770 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -2716,6 +2716,18 @@ void sElev = 0.0f; // X recenters pitch too } gBTElevAxis = sElev; + // DIAG (BT_FORCE_ELEV=<-1..1>): pin the elevation + // axis for headless pitch verification (no focus). + { + static float s_fe = -2.0f; + if (s_fe < -1.5f) + { + const char *fe = getenv("BT_FORCE_ELEV"); + s_fe = fe ? (float)atof(fe) : -3.0f; + } + if (s_fe >= -1.0f) + gBTElevAxis = s_fe; + } if (getenv("BT_INPUT_LOG")) { static float s_eacc = 0.0f; s_eacc += dt; @@ -4933,6 +4945,28 @@ void extern float gBTEyeTwist; gBTEyeTwist = gBTHudTwist; } + + // TORSO-ELEVATION AIM -> EYE PITCH (issue #3 follow-up; user + + // tester report "pitch does not work"): the Torso sim integrated + // R/F into currentElevation (authored limits/rates) but NOTHING + // consumed it -- the view and the aim ray (camera basis) never + // pitched. The pod's stick-Y aim pitches the EYE (the torso + // geometry does not tilt); compose it per frame with the look-state + // angles into eyepointRotation, which DPLEyeRenderable reads every + // frame (VIEW = baseOffset * R). BTCommitLookState stores the + // look component in gBTLookPitch/Yaw (below); the elevation rides + // the pitch term. Pitch sign PIXEL-CALIBRATED (BT_FORCE_ELEV + // screenshots): −elev pitched the view DOWN for a positive axis; + // R (axis +1) must aim UP -> +elev. + { + extern float gBTLookPitch, gBTLookYaw; + extern Scalar BTGetTorsoElevation(Subsystem *); + const float elev = (float)BTGetTorsoElevation(GetTorsoSubsystem()); + eyepointRotation = EulerAngles( + Radian(Radian::Normalize(gBTLookPitch + elev)), + Radian(Radian::Normalize(gBTLookYaw)), + Radian(0.0f)); + } } // task #6 ORDER FIX: the scripted block must run BEFORE the fire-push @@ -6368,6 +6402,13 @@ int BTWeaponMountIsRear(void *ownerMech, int segIndex) return rear; } +// The current look-state eye component (pitch/yaw) -- stored so the per-frame +// eyepoint compose (the HUD tick above) can combine it with the live torso +// elevation. Single-viewpoint state (BTCommitLookState runs for the local +// player's mapper only), same pattern as the other viewpoint globals. +float gBTLookPitch = 0.0f; +float gBTLookYaw = 0.0f; + void BTCommitLookState(void *mech_v, int look_state) { Mech *m = (Mech *)mech_v; @@ -6387,6 +6428,8 @@ void BTCommitLookState(void *mech_v, int look_state) case 4: /*LookDown*/ pitch = m->lookFrontAngle; break; default: break; // LookNone: identity } + gBTLookPitch = (float)pitch; // per-frame compose adds elevation + gBTLookYaw = (float)yaw; m->eyepointRotation = EulerAngles( Radian(Radian::Normalize(pitch)), Radian(Radian::Normalize(yaw)), diff --git a/game/reconstructed/torso.cpp b/game/reconstructed/torso.cpp index b03191a..bd304d3 100644 --- a/game/reconstructed/torso.cpp +++ b/game/reconstructed/torso.cpp @@ -1040,6 +1040,18 @@ Scalar BTGetTorsoTwist(Subsystem *torso) return torso ? ((Torso *)torso)->CurrentTwist() : 0.0f; } +// +// Live torso ELEVATION (pitch aim, rad) -- Torso::currentElevation == the +// binary torso+0x1E4. Same complete-type-TU bridge pattern as +// BTGetTorsoTwist above. Consumed by the per-frame eyepoint compose +// (mech4.cpp): the R/F / stick-Y aim pitches the EYE only -- the torso +// geometry does not tilt, exactly like the pod. +// +Scalar BTGetTorsoElevation(Subsystem *torso) +{ + return torso ? ((Torso *)torso)->CurrentElevation() : 0.0f; +} + // // Task #56 bridge -- ADDRESS of the live torso twist for the gyro's external- // pitch pointer (binary bt_mech stream tail: gyro+0x258 = torso+0x1D8; the gyro