summaryrefslogtreecommitdiffstats
path: root/src/tacmap/camera.rs
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-04-15 22:22:45 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-04-15 22:22:45 -0400
commit3dc92fad981e28c760f3c6e95f5a8153ea6c9be4 (patch)
tree9e806c4ad09cf22957bc4dccd415718045fc4b0f /src/tacmap/camera.rs
parentb5ced3af46c96ceb959fbbf1addfeba3bd4f76d5 (diff)
downloadsystemic4x-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.rs150
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 = &current_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<