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