diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-04-15 22:22:45 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-04-15 22:22:45 -0400 |
| commit | 3dc92fad981e28c760f3c6e95f5a8153ea6c9be4 (patch) | |
| tree | 9e806c4ad09cf22957bc4dccd415718045fc4b0f /src/tacmap/camera.rs | |
| parent | b5ced3af46c96ceb959fbbf1addfeba3bd4f76d5 (diff) | |
| download | systemic4x-3dc92fad981e28c760f3c6e95f5a8153ea6c9be4.tar.gz systemic4x-3dc92fad981e28c760f3c6e95f5a8153ea6c9be4.tar.bz2 systemic4x-3dc92fad981e28c760f3c6e95f5a8153ea6c9be4.zip | |
work on orbits (not right yet), orbit camera
Diffstat (limited to 'src/tacmap/camera.rs')
| -rw-r--r-- | src/tacmap/camera.rs | 150 |
1 files changed, 124 insertions, 26 deletions
diff --git a/src/tacmap/camera.rs b/src/tacmap/camera.rs index 1a2787b..c6ee5c0 100644 --- a/src/tacmap/camera.rs +++ b/src/tacmap/camera.rs @@ -1,9 +1,9 @@ -use std::time::Duration; +use std::{cell::RefCell, time::Duration}; -use cgmath::{InnerSpace, Point3, Rad, Vector2, Vector3, Vector4, Zero, perspective}; +use cgmath::{EuclideanSpace, InnerSpace, Point3, Rad, Vector2, Vector3, Vector4, Zero, perspective}; use winit::{event::ElementState, keyboard::KeyCode}; -use crate::{solar_system::BodyId, wgpuctx::WgpuCtx}; +use crate::{GameState, solar_system, wgpuctx::WgpuCtx, window::ui::GameWindowUiState}; pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::from_cols( Vector4::new(1.0, 0.0, 0.0, 0.0), @@ -14,12 +14,13 @@ pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::from_co pub struct Camera { - position: Point3<f32>, + abs_position: Point3<f32>, + rel_position: Point3<f32>, pitch: Rad<f32>, yaw: Rad<f32>, scale: f32, - target: Option<BodyId>, + target: Option<solar_system::BodyId>, buffer: wgpu::Buffer, staging_buffer: wgpu::Buffer, @@ -96,7 +97,8 @@ impl Camera } ); Self { - position: position.into(), + abs_position: position.into(), + rel_position: Point3::new(0.0, 0.0, 0.0), yaw: yaw.into(), pitch: pitch.into(), scale: 1.0, @@ -110,6 +112,14 @@ impl Camera pub fn get_scale(&self) -> f32 { self.scale } + pub fn get_position(&self) -> Point3<f32> + { + Point3::new( + self.abs_position.x + self.rel_position.x, + self.abs_position.y + self.rel_position.y, + self.abs_position.z + self.rel_position.z) + } + pub fn bindgroup_layout(wgpuctx: &WgpuCtx) -> wgpu::BindGroupLayout { @@ -152,22 +162,44 @@ impl Camera wgpuctx.queue().write_buffer(&self.staging_buffer, 0, bytemuck::cast_slice(&[self.uniform(projection)])); } + pub fn set_target( + &mut self, + target: Option<solar_system::BodyId>) + { + if target == self.target { return; } + if !target.is_some() || !self.target.is_some() { + self.abs_position = self.get_position(); + self.rel_position = Point3::new(0.0, 0.0, 0.0); + } + self.target = target; + } + + pub fn get_target(&self) -> Option<solar_system::BodyId> + { self.target } + pub fn view_matrix( &self) -> cgmath::Matrix4<f32> { - let (yaw_sin, yaw_cos) = self.yaw.0.sin_cos(); - let (pitch_sin, pitch_cos) = self.pitch.0.sin_cos(); - - cgmath::Matrix4::look_to_rh( - self.position, - Vector3::new( - pitch_cos * yaw_cos, - pitch_sin, - pitch_cos * yaw_sin - ).normalize(), - Vector3::unit_y() - ) + let (yaw_sin, yaw_cos) = self.pitch.0.sin_cos(); + let (pitch_sin, pitch_cos) = self.yaw.0.sin_cos(); + + if self.target.is_some() { + cgmath::Matrix4::look_at_rh( + self.get_position(), + self.abs_position, + Vector3::unit_y()) + }else{ + cgmath::Matrix4::look_to_rh( + self.get_position(), + Vector3::new( + pitch_cos * yaw_cos, + pitch_sin, + pitch_cos * yaw_sin + ).normalize(), + Vector3::unit_y() + ) + } } pub fn uniform( @@ -177,7 +209,7 @@ impl Camera { CameraUniform { view: (self.view_matrix()).into(), - proj: (OPENGL_TO_WGPU_MATRIX * projection.projection_matrix()).into(), + proj: projection.projection_matrix().into(), scale: self.scale } } @@ -215,30 +247,96 @@ impl CameraController } } - pub fn update( + fn update_orbit( &mut self, camera: &mut Camera, + target: Point3<f32>, + min_radius: f32, dt: Duration) { + camera.abs_position = target * camera.scale; + let dt = dt.as_secs_f32(); let speed = 1.0; - camera.pitch.0 += (self.rotation_pos_delta.x - self.rotation_neg_delta.x) * speed * dt; - camera.yaw.0 += (self.rotation_pos_delta.y - self.rotation_neg_delta.y) * speed * dt; + let current_radius = camera.rel_position.to_vec().magnitude(); + + let polar_diff = (self.position_pos_delta.z - self.position_neg_delta.z) * speed * dt; + let azimuth_diff = (self.position_pos_delta.x - self.position_neg_delta.x) * speed * dt; + let dist_diff = (self.position_pos_delta.y - self.position_neg_delta.y) * speed * dt; + + camera.pitch.0 += polar_diff; + let polar_cap = cgmath::Deg(179.999).0; + if camera.pitch.0 > polar_cap { camera.pitch.0 = polar_cap; } + if camera.pitch.0 < -polar_cap { camera.pitch.0 = -polar_cap; } + + camera.yaw.0 += azimuth_diff; + + let (az_sin, az_cos) = camera.yaw.0.sin_cos(); + let (p_sin, p_cos) = camera.pitch.0.sin_cos(); + + let radius = f32::max(min_radius * camera.scale, current_radius + dist_diff); + camera.rel_position = Point3::new( + radius * p_cos * az_cos, + radius * p_sin, + radius * p_cos * az_sin + ); + } + + fn update_pan( + &mut self, + camera: &mut Camera, + dt: Duration) + { + let dt = dt.as_secs_f32(); + let speed = 1.0; let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); let up = Vector3::new(0.0, 1.0, 0.0); - camera.position += forward * (self.position_pos_delta.z - self.position_neg_delta.z) * speed * dt; - camera.position += right * (self.position_pos_delta.x - self.position_neg_delta.x) * speed * dt; - camera.position += up * (self.position_pos_delta.y - self.position_neg_delta.y) * speed * dt; + camera.rel_position += forward * (self.position_pos_delta.z - self.position_neg_delta.z) * speed * dt; + camera.rel_position += right * (self.position_pos_delta.x - self.position_neg_delta.x) * speed * dt; + camera.rel_position += up * (self.position_pos_delta.y - self.position_neg_delta.y) * speed * dt; + + camera.abs_position = camera.rel_position; + + camera.pitch.0 += (self.rotation_pos_delta.x - self.rotation_neg_delta.x) * speed * dt; + camera.yaw.0 += (self.rotation_pos_delta.y - self.rotation_neg_delta.y) * speed * dt; + } + + pub fn update( + &mut self, + camera: &mut Camera, + game_state: &RefCell<GameState>, + ui_state: &mut GameWindowUiState, + dt: Duration) + { camera.scale *= 1.0 + ((self.scale_delta.y - self.scale_delta.x) * 0.1); camera.scale = f32::max(1e-16, f32::min(1.0, camera.scale)); + + match ui_state.camera_target { + Some(body_id) => { + let game_state = game_state.borrow(); + let solar_systems = game_state.solar_systems(); + let current_system = match ui_state.current_system { + Some(id) => &solar_systems[id], + None => return +}; + + let body = ¤t_system.bodies()[body_id]; + self.update_orbit( + camera, + body.position().cast().unwrap(), + body.radius(), + dt); + } + None => self.update_pan(camera, dt) + } } -} +} //impl CameraController impl Projection { pub fn new< |
