game_toolkit_gfx/
camera.rs1use bytemuck::{Pod, Zeroable};
2
3#[derive(Copy, Clone, Debug)]
5pub struct Camera2D {
6 pub center: [f32; 2],
7 pub zoom: f32,
8 pub viewport: [f32; 2],
9 pub y_down: bool,
11}
12
13impl Camera2D {
14 pub fn new(viewport_w: f32, viewport_h: f32) -> Self {
15 Self {
16 center: [viewport_w * 0.5, viewport_h * 0.5],
17 zoom: 1.0,
18 viewport: [viewport_w, viewport_h],
19 y_down: true,
20 }
21 }
22
23 pub fn resize(&mut self, w: f32, h: f32) {
24 let z = self.zoom.max(1e-4);
32 let top_left = [
33 self.center[0] - self.viewport[0] * 0.5 / z,
34 self.center[1] - self.viewport[1] * 0.5 / z,
35 ];
36 self.viewport = [w, h];
37 self.center = [top_left[0] + w * 0.5 / z, top_left[1] + h * 0.5 / z];
38 }
39
40 pub fn visible_rect(&self) -> ([f32; 2], [f32; 2]) {
42 let z = self.zoom.max(1e-4);
43 let hw = self.viewport[0] * 0.5 / z;
44 let hh = self.viewport[1] * 0.5 / z;
45 (
46 [self.center[0] - hw, self.center[1] - hh],
47 [self.center[0] + hw, self.center[1] + hh],
48 )
49 }
50
51 pub fn view_proj(&self) -> [[f32; 4]; 4] {
52 let z = self.zoom.max(1e-4);
53 let hw = self.viewport[0] * 0.5 / z;
54 let hh = self.viewport[1] * 0.5 / z;
55 let l = self.center[0] - hw;
56 let r = self.center[0] + hw;
57 let (b, t) = if self.y_down {
58 (self.center[1] + hh, self.center[1] - hh)
59 } else {
60 (self.center[1] - hh, self.center[1] + hh)
61 };
62 ortho(l, r, b, t, -1.0, 1.0)
63 }
64}
65
66fn ortho(l: f32, r: f32, b: f32, t: f32, n: f32, f: f32) -> [[f32; 4]; 4] {
67 let rml = r - l;
68 let tmb = t - b;
69 let fmn = f - n;
70 [
71 [2.0 / rml, 0.0, 0.0, 0.0],
72 [0.0, 2.0 / tmb, 0.0, 0.0],
73 [0.0, 0.0, -1.0 / fmn, 0.0],
74 [-(r + l) / rml, -(t + b) / tmb, -n / fmn, 1.0],
75 ]
76}
77
78#[repr(C)]
79#[derive(Copy, Clone, Pod, Zeroable)]
80pub(crate) struct CameraUniform {
81 pub view_proj: [[f32; 4]; 4],
82}