geng_camera/
lib.rs

1use batbox_la::*;
2use batbox_lapp::*;
3use serde::{Deserialize, Serialize};
4
5mod camera_2d;
6mod pixel_perfect;
7
8pub use camera_2d::*;
9pub use pixel_perfect::*;
10
11/// Represents any 3d camera.
12pub trait AbstractCamera3d {
13    fn view_matrix(&self) -> mat4<f32>;
14    fn projection_matrix(&self, framebuffer_size: vec2<f32>) -> mat4<f32>;
15
16    fn uniforms(&self, framebuffer_size: vec2<f32>) -> Uniforms3d {
17        Uniforms3d::new(self, framebuffer_size)
18    }
19
20    fn world_to_screen(&self, framebuffer_size: vec2<f32>, pos: vec3<f32>) -> Option<vec2<f32>> {
21        let pos = (self.projection_matrix(framebuffer_size) * self.view_matrix()) * pos.extend(1.0);
22        let pos = pos.xyz() / pos.w;
23        if pos.x.abs() > 1.0 || pos.y.abs() > 1.0 || pos.z.abs() > 1.0 {
24            return None;
25        }
26        Some(vec2(
27            (pos.x + 1.0) / 2.0 * framebuffer_size.x,
28            (pos.y + 1.0) / 2.0 * framebuffer_size.y,
29        ))
30    }
31
32    fn pixel_ray(&self, framebuffer_size: vec2<f32>, pos: vec2<f32>) -> Ray {
33        let pos = vec2(
34            pos.x / framebuffer_size.x * 2.0 - 1.0,
35            pos.y / framebuffer_size.y * 2.0 - 1.0,
36        );
37        // proj * view * (rx, ry, 0, 1 / w) = (px, py, ?, 1)
38        let inv_matrix = (self.projection_matrix(framebuffer_size) * self.view_matrix()).inverse();
39        let p1 = inv_matrix * pos.extend(0.0).extend(1.0);
40        let p2 = inv_matrix * pos.extend(1.0).extend(1.0);
41        let p1 = p1.xyz() / p1.w;
42        let p2 = p2.xyz() / p2.w;
43        Ray {
44            from: p1,
45            dir: p2 - p1,
46        }
47    }
48}
49
50/// Represents any 2d camera.
51pub trait AbstractCamera2d {
52    fn view_matrix(&self) -> mat3<f32>;
53    fn projection_matrix(&self, framebuffer_size: vec2<f32>) -> mat3<f32>;
54
55    fn uniforms(&self, framebuffer_size: vec2<f32>) -> Uniforms2d {
56        Uniforms2d::new(self, framebuffer_size)
57    }
58
59    fn screen_to_world(&self, framebuffer_size: vec2<f32>, pos: vec2<f32>) -> vec2<f32> {
60        let pos = vec2(
61            pos.x / framebuffer_size.x * 2.0 - 1.0,
62            pos.y / framebuffer_size.y * 2.0 - 1.0,
63        );
64        let pos = (AbstractCamera2d::projection_matrix(self, framebuffer_size)
65            * AbstractCamera2d::view_matrix(self))
66        .inverse()
67            * pos.extend(1.0);
68        pos.xy()
69    }
70
71    fn world_to_screen(&self, framebuffer_size: vec2<f32>, pos: vec2<f32>) -> Option<vec2<f32>> {
72        let pos = (self.projection_matrix(framebuffer_size) * self.view_matrix()) * pos.extend(1.0);
73        let pos = pos.xy() / pos.z;
74        if pos.x.abs() > 1.0 || pos.y.abs() > 1.0 {
75            return None;
76        }
77        Some(vec2(
78            (pos.x + 1.0) / 2.0 * framebuffer_size.x,
79            (pos.y + 1.0) / 2.0 * framebuffer_size.y,
80        ))
81    }
82
83    fn view_area(&self, framebuffer_size: vec2<f32>) -> Quad<f32> {
84        Quad {
85            transform: (self.projection_matrix(framebuffer_size) * self.view_matrix()).inverse(),
86        }
87    }
88}
89
90pub struct Camera2dAs3d<T>(pub T);
91
92impl<C: AbstractCamera2d> AbstractCamera3d for Camera2dAs3d<C> {
93    fn view_matrix(&self) -> mat4<f32> {
94        self.0.view_matrix().extend3d()
95    }
96    fn projection_matrix(&self, framebuffer_size: vec2<f32>) -> mat4<f32> {
97        self.0.projection_matrix(framebuffer_size).extend3d()
98    }
99}
100
101#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
102pub struct Ray {
103    pub from: vec3<f32>,
104    pub dir: vec3<f32>,
105}
106
107#[derive(ugli::Uniforms)]
108pub struct Uniforms3d {
109    pub u_projection_matrix: mat4<f32>,
110    pub u_view_matrix: mat4<f32>,
111}
112
113impl Uniforms3d {
114    pub fn new<C: AbstractCamera3d + ?Sized>(camera: &C, framebuffer_size: vec2<f32>) -> Self {
115        Self {
116            u_projection_matrix: camera.projection_matrix(framebuffer_size),
117            u_view_matrix: camera.view_matrix(),
118        }
119    }
120}
121
122#[derive(ugli::Uniforms)]
123pub struct Uniforms2d {
124    pub u_projection_matrix: mat3<f32>,
125    pub u_view_matrix: mat3<f32>,
126}
127
128impl Uniforms2d {
129    pub fn new<C: AbstractCamera2d + ?Sized>(camera: &C, framebuffer_size: vec2<f32>) -> Self {
130        Self {
131            u_projection_matrix: camera.projection_matrix(framebuffer_size),
132            u_view_matrix: camera.view_matrix(),
133        }
134    }
135}