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
11pub 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 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
50pub 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}