diff options
| author | Valentin Popov <valentin@popov.link> | 2026-07-18 13:03:18 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-07-18 13:03:18 +0300 |
| commit | 0506a45d578fa5279baff26f2f1200605bc909d7 (patch) | |
| tree | b1ebaa1dc4a9ff4cecd2072402c2767618538b07 /crates/fparkan-render/src | |
| parent | 50a55461e72383edf22120a908a42a8b621e6914 (diff) | |
| download | fparkan-0506a45d578fa5279baff26f2f1200605bc909d7.tar.xz fparkan-0506a45d578fa5279baff26f2f1200605bc909d7.zip | |
feat(render): retain raw camera poses
Diffstat (limited to 'crates/fparkan-render/src')
| -rw-r--r-- | crates/fparkan-render/src/lib.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/crates/fparkan-render/src/lib.rs b/crates/fparkan-render/src/lib.rs index 4f2192d..fe83290 100644 --- a/crates/fparkan-render/src/lib.rs +++ b/crates/fparkan-render/src/lib.rs @@ -22,6 +22,42 @@ use fparkan_world::OriginalObjectId; +/// A 64-byte transform block returned by the original Terrain camera ABI. +/// +/// The original uses two selector-dependent transform pointers. Their exact +/// matrix convention is still under recovery, so words are deliberately kept +/// losslessly rather than treated as a renderer-ready matrix. The three +/// translation words have been confirmed at indices 3, 7, and 11. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RawCameraTransform { + /// The exact 16 little-endian dwords returned by the legacy camera. + pub words: [u32; 16], +} + +impl RawCameraTransform { + /// Indices of the confirmed X, Y, and Z translation floats. + pub const TRANSLATION_WORD_INDICES: [usize; 3] = [3, 7, 11]; + + /// Returns the confirmed legacy world position (X, Y, Z). + #[must_use] + pub fn translation(self) -> [f32; 3] { + Self::TRANSLATION_WORD_INDICES.map(|index| f32::from_bits(self.words[index])) + } +} + +/// Raw camera state observed through the original Terrain camera interface. +/// +/// Selector 0 supplies the currently active transform and selector 2 supplies +/// its paired transform. Keeping both lets a later compatibility layer derive +/// a view/projection convention without re-reading the legacy process. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RawCameraPose { + /// Transform returned by selector 0. + pub selector0: RawCameraTransform, + /// Transform returned by selector 2. + pub selector2: RawCameraTransform, +} + /// Immutable camera data visible to command generation. #[derive(Clone, Debug, PartialEq)] pub struct CameraSnapshot { @@ -29,6 +65,12 @@ pub struct CameraSnapshot { pub view: [f32; 16], /// Projection matrix, row-major. pub projection: [f32; 16], + /// Optional unconverted source-camera state. + /// + /// This does not alter rendering until the original matrix and projection + /// conventions have been recovered; it preserves the ABI boundary for the + /// runtime adapter and deterministic captures. + pub raw_pose: Option<RawCameraPose>, } impl Default for CameraSnapshot { @@ -36,6 +78,7 @@ impl Default for CameraSnapshot { Self { view: identity_transform(), projection: identity_transform(), + raw_pose: None, } } } @@ -702,6 +745,29 @@ fn identity_transform() -> [f32; 16] { mod tests { use super::*; + #[test] + fn raw_camera_pose_preserves_words_and_extracts_confirmed_translation() { + let mut active = [0_u32; 16]; + active[0] = 0x7FC0_0001; + active[3] = 491.562_5_f32.to_bits(); + active[7] = 761.550_8_f32.to_bits(); + active[11] = 7.361_0_f32.to_bits(); + let paired = [0xA5A5_5A5A; 16]; + + let pose = RawCameraPose { + selector0: RawCameraTransform { words: active }, + selector2: RawCameraTransform { words: paired }, + }; + + assert_eq!(pose.selector0.words, active); + assert_eq!(pose.selector2.words, paired); + assert_eq!( + pose.selector0.translation(), + [491.562_5, 761.550_8, 7.361_0] + ); + assert_eq!(CameraSnapshot::default().raw_pose, None); + } + fn snapshot_draw( id: u64, phase: RenderPhase, |
