petaplot_render/
camera.rs1use bytemuck::{Pod, Zeroable};
2
3#[repr(C)]
6#[derive(Debug, Clone, Copy, Pod, Zeroable)]
7pub struct CameraUniform {
8 pub transform_matrix: [[f32; 4]; 4],
9 pub color: [f32; 4],
10 pub line_width: f32,
11 pub _padding: [f32; 3],
12}
13
14impl Default for CameraUniform {
15 fn default() -> Self {
16 Self {
17 transform_matrix: [
18 [1.0, 0.0, 0.0, 0.0],
19 [0.0, 1.0, 0.0, 0.0],
20 [0.0, 0.0, 1.0, 0.0],
21 [0.0, 0.0, 0.0, 1.0],
22 ],
23 color: [0.2, 0.6, 1.0, 1.0], line_width: 1.5,
25 _padding: [0.0; 3],
26 }
27 }
28}
29
30pub struct ViewportCamera {
32 pub x_min: f64,
33 pub x_max: f64,
34 pub y_min: f32,
35 pub y_max: f32,
36 pub color: [f32; 4],
37 pub line_width: f32,
38}
39
40impl Default for ViewportCamera {
41 fn default() -> Self {
42 Self {
43 x_min: 0.0,
44 x_max: 100.0,
45 y_min: -1.0,
46 y_max: 1.0,
47 color: [0.2, 0.7, 1.0, 1.0],
48 line_width: 1.5,
49 }
50 }
51}
52
53impl ViewportCamera {
54 pub fn new(x_min: f64, x_max: f64, y_min: f32, y_max: f32) -> Self {
55 Self {
56 x_min,
57 x_max,
58 y_min,
59 y_max,
60 ..Default::default()
61 }
62 }
63
64 pub fn pan_x(&mut self, delta_x: f64) {
66 self.x_min += delta_x;
67 self.x_max += delta_x;
68 }
69
70 pub fn zoom_x(&mut self, center_x: f64, factor: f64) {
72 let span = self.x_max - self.x_min;
73 let new_span = (span * factor).max(1e-6);
74
75 let ratio = if span > 0.0 {
76 (center_x - self.x_min) / span
77 } else {
78 0.5
79 };
80
81 self.x_min = center_x - ratio * new_span;
82 self.x_max = self.x_min + new_span;
83 }
84
85 pub fn build_uniform(&self) -> CameraUniform {
87 let span_x = (self.x_max - self.x_min) as f32;
88 let span_y = self.y_max - self.y_min;
89
90 let scale_x = if span_x > 0.0 { 2.0 / span_x } else { 1.0 };
91 let scale_y = if span_y > 0.0 { 2.0 / span_y } else { 1.0 };
92
93 let offset_x = -1.0 - (self.x_min as f32) * scale_x;
94 let offset_y = -1.0 - self.y_min * scale_y;
95
96 let transform_matrix = [
97 [scale_x, 0.0, 0.0, 0.0],
98 [0.0, scale_y, 0.0, 0.0],
99 [0.0, 0.0, 1.0, 0.0],
100 [offset_x, offset_y, 0.0, 1.0],
101 ];
102
103 CameraUniform {
104 transform_matrix,
105 color: self.color,
106 line_width: self.line_width,
107 _padding: [0.0; 3],
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_camera_uniform_transformation() {
118 let camera = ViewportCamera::new(0.0, 100.0, -1.0, 1.0);
119 let uniform = camera.build_uniform();
120
121 let scale_x = uniform.transform_matrix[0][0];
123 let offset_x = uniform.transform_matrix[3][0];
124 let ndc_x = 50.0 * scale_x + offset_x;
125
126 assert!((ndc_x - 0.0).abs() < 1e-5);
127 }
128}