wormhole/
camera.rs

1// Camera System - Handles view and projection matrices
2
3use cgmath::*;
4use std::sync::{Arc, Mutex};
5
6#[derive(Clone)]
7pub struct Camera {
8    // Position in world space
9    position: Point3<f32>,
10    
11    // Rotation (pitch, yaw, roll in radians)
12    pitch: f32,  // Rotation around X axis (up/down)
13    yaw: f32,    // Rotation around Y axis (left/right)
14    
15    // Projection settings
16    fov: f32,              // Field of view in degrees
17    aspect_ratio: f32,     // Width / height
18    near: f32,             // Near clipping plane
19    far: f32,              // Far clipping plane
20    
21    // Computed matrices (cached, recalculated every frame)
22    view_matrix: Matrix4<f32>,
23    projection_matrix: Matrix4<f32>,
24}
25
26impl Camera {
27    pub fn new(width: u32, height: u32) -> Self {
28        let aspect = width as f32 / height as f32;
29        let mut camera = Self {
30            position: Point3::new(0.0, 0.0, 5.0),
31            pitch: 0.0,
32            yaw: -std::f32::consts::PI / 2.0,  // Start looking along -Z (toward origin/cube)
33            fov: 45.0,
34            aspect_ratio: aspect,
35            near: 0.1,
36            far: 100.0,
37            view_matrix: Matrix4::identity(),
38            projection_matrix: Matrix4::identity(),
39        };
40        camera.update_matrices();
41        camera
42    }
43
44    /// Update camera matrices (always recalculates)
45    fn update_matrices(&mut self) {
46        // Calculate forward vector from pitch and yaw
47        // Yaw rotates around Y axis (left/right)
48        // Pitch rotates around X axis (up/down)
49        let forward = Vector3::new(
50            self.yaw.cos() * self.pitch.cos(),
51            self.pitch.sin(),
52            self.yaw.sin() * self.pitch.cos(),
53        ).normalize();
54        
55        // Calculate target point (camera position + forward direction)
56        let target = self.position + forward;
57        
58        // Calculate up vector (perpendicular to forward, preferring world up)
59        // For simplicity, use world up (Y axis) for now
60        // In a more advanced system, we might want to handle roll
61        let up = Vector3::unit_y();
62        
63        // Calculate view matrix using look_at
64        self.view_matrix = Matrix4::look_at_rh(
65            self.position,
66            target,
67            up,
68        );
69
70        // Calculate projection matrix
71        self.projection_matrix = perspective(
72            Deg(self.fov),
73            self.aspect_ratio,
74            self.near,
75            self.far,
76        );
77    }
78
79    /// Get the view matrix (updates matrices if needed)
80    pub fn view_matrix(&mut self) -> Matrix4<f32> {
81        self.update_matrices();
82        self.view_matrix
83    }
84
85    /// Get the projection matrix (assumes view_matrix was called first to update matrices)
86    pub fn projection_matrix(&mut self) -> Matrix4<f32> {
87        // Matrices are already updated by view_matrix() call, just return cached value
88        self.projection_matrix
89    }
90
91    /// Set camera position
92    pub fn set_position(&mut self, x: f32, y: f32, z: f32) {
93        self.position = Point3::new(x, y, z);
94    }
95
96    /// Get camera position
97    pub fn position(&self) -> (f32, f32, f32) {
98        (self.position.x, self.position.y, self.position.z)
99    }
100
101    /// Set camera rotation (pitch and yaw in radians)
102    pub fn set_rotation(&mut self, pitch: f32, yaw: f32) {
103        self.pitch = pitch;
104        self.yaw = yaw;
105    }
106
107    /// Get camera rotation
108    pub fn rotation(&self) -> (f32, f32) {
109        (self.pitch, self.yaw)
110    }
111
112    /// Set field of view (in degrees)
113    pub fn set_fov(&mut self, fov: f32) {
114        self.fov = fov;
115    }
116
117    /// Get field of view
118    pub fn fov(&self) -> f32 {
119        self.fov
120    }
121
122    /// Update aspect ratio (call when window is resized)
123    pub fn set_aspect_ratio(&mut self, width: u32, height: u32) {
124        self.aspect_ratio = width as f32 / height as f32;
125    }
126
127    /// Move camera relative to its current orientation
128    pub fn translate(&mut self, dx: f32, dy: f32, dz: f32) {
129        // Calculate forward vector from pitch and yaw (same as in update_matrices)
130        let forward = Vector3::new(
131            self.yaw.cos() * self.pitch.cos(),
132            self.pitch.sin(),
133            self.yaw.sin() * self.pitch.cos(),
134        ).normalize();
135        
136        // Calculate right vector (forward cross world up)
137        let right = forward.cross(Vector3::unit_y()).normalize();
138        
139        // Calculate up vector (right cross forward)
140        let up = right.cross(forward).normalize();
141        
142        // Translate in camera space
143        // dx = left/right, dy = up/down, dz = forward/back
144        let movement = right * dx + up * dy + forward * dz;
145        self.position += movement;
146    }
147}
148
149// Thread-safe camera for FFI
150pub type CameraState = Arc<Mutex<Camera>>;