renderling/camera/cpu.rs
1//! CPU side of [crate::camera].
2
3use craballoc::{runtime::IsRuntime, slab::SlabAllocator, value::Hybrid};
4use crabslab::Id;
5
6use crate::camera::shader::CameraDescriptor;
7
8use super::*;
9
10/// A camera used for transforming the stage during rendering.
11///
12/// * Use [`Stage::new_camera`](crate::stage::Stage::new_camera) to create a new camera.
13/// * Use [`Stage::use_camera`](crate::stage::Stage::use_camera) to set a camera on the stage.
14///
15/// ## Note
16///
17/// Clones of this type all point to the same underlying data.
18#[derive(Clone, Debug)]
19pub struct Camera {
20 inner: Hybrid<CameraDescriptor>,
21}
22
23impl AsRef<Camera> for Camera {
24 fn as_ref(&self) -> &Camera {
25 self
26 }
27}
28
29impl Camera {
30 /// Stage a new camera on the given slab.
31 pub fn new(slab: &SlabAllocator<impl IsRuntime>) -> Self {
32 Self {
33 inner: slab.new_value(CameraDescriptor::default()),
34 }
35 }
36
37 /// Returns a pointer to the underlying descriptor on the GPU.
38 pub fn id(&self) -> Id<CameraDescriptor> {
39 self.inner.id()
40 }
41
42 /// Returns a copy of the underlying descriptor.
43 pub fn descriptor(&self) -> CameraDescriptor {
44 self.inner.get()
45 }
46
47 /// Set the camera to a default perspective projection and view based
48 /// on the width and height of the viewport.
49 ///
50 /// The default projection and view matrices are defined as:
51 ///
52 /// ```rust
53 /// use glam::*;
54 ///
55 /// let width = 800.0;
56 /// let height = 600.0;
57 /// let aspect = width / height;
58 /// let fovy = core::f32::consts::PI / 4.0;
59 /// let znear = 0.1;
60 /// let zfar = 100.0;
61 /// let projection = Mat4::perspective_rh(fovy, aspect, znear, zfar);
62 /// let eye = Vec3::new(0.0, 12.0, 20.0);
63 /// let target = Vec3::ZERO;
64 /// let up = Vec3::Y;
65 /// let view = Mat4::look_at_rh(eye, target, up);
66 /// assert_eq!(renderling::camera::default_perspective(width, height), (projection, view));
67 /// ```
68 pub fn set_default_perspective(&self, width: f32, height: f32) -> &Self {
69 self.inner
70 .modify(|d| *d = CameraDescriptor::default_perspective(width, height));
71 self
72 }
73
74 /// Set the camera to a default perspective projection and view based
75 /// on the width and height of the viewport.
76 ///
77 /// The default projection and view matrices are defined as:
78 ///
79 /// ```rust
80 /// use glam::*;
81 ///
82 /// let width = 800.0;
83 /// let height = 600.0;
84 /// let aspect = width / height;
85 /// let fovy = core::f32::consts::PI / 4.0;
86 /// let znear = 0.1;
87 /// let zfar = 100.0;
88 /// let projection = Mat4::perspective_rh(fovy, aspect, znear, zfar);
89 /// let eye = Vec3::new(0.0, 12.0, 20.0);
90 /// let target = Vec3::ZERO;
91 /// let up = Vec3::Y;
92 /// let view = Mat4::look_at_rh(eye, target, up);
93 /// assert_eq!(renderling::camera::default_perspective(width, height), (projection, view));
94 /// ```
95 pub fn with_default_perspective(self, width: f32, height: f32) -> Self {
96 self.set_default_perspective(width, height);
97 self
98 }
99
100 /// Set the camera to a default orthographic 2d projection and view based
101 /// on the width and height of the viewport.
102 pub fn set_default_ortho2d(&self, width: f32, height: f32) -> &Self {
103 self.inner
104 .modify(|d| *d = CameraDescriptor::default_ortho2d(width, height));
105 self
106 }
107
108 /// Set the camera to a default orthographic 2d projection and view based
109 /// on the width and height of the viewport.
110 pub fn with_default_ortho2d(self, width: f32, height: f32) -> Self {
111 self.set_default_ortho2d(width, height);
112 self
113 }
114
115 /// Set the projection and view matrices of this camera.
116 pub fn set_projection_and_view(
117 &self,
118 projection: impl Into<Mat4>,
119 view: impl Into<Mat4>,
120 ) -> &Self {
121 self.inner
122 .modify(|d| d.set_projection_and_view(projection.into(), view.into()));
123 self
124 }
125
126 /// Set the projection and view matrices and return this camera.
127 pub fn with_projection_and_view(
128 self,
129 projection: impl Into<Mat4>,
130 view: impl Into<Mat4>,
131 ) -> Self {
132 self.set_projection_and_view(projection, view);
133 self
134 }
135
136 /// Returns the projection and view matrices.
137 pub fn projection_and_view(&self) -> (Mat4, Mat4) {
138 let d = self.inner.get();
139 (d.projection(), d.view())
140 }
141
142 /// Set the projection matrix of this camera.
143 pub fn set_projection(&self, projection: impl Into<Mat4>) -> &Self {
144 self.inner.modify(|d| d.set_projection(projection.into()));
145 self
146 }
147
148 /// Set the projection matrix and return this camera.
149 pub fn with_projection(self, projection: impl Into<Mat4>) -> Self {
150 self.set_projection(projection);
151 self
152 }
153
154 /// Returns the projection matrix.
155 pub fn projection(&self) -> Mat4 {
156 self.inner.get().projection()
157 }
158
159 /// Set the view matrix of this camera.
160 pub fn set_view(&self, view: impl Into<Mat4>) -> &Self {
161 self.inner.modify(|d| d.set_view(view.into()));
162 self
163 }
164
165 /// Set the view matrix and return this camera.
166 pub fn with_view(self, view: impl Into<Mat4>) -> Self {
167 self.set_view(view);
168 self
169 }
170
171 /// Returns the view matrix.
172 pub fn view(&self) -> Mat4 {
173 self.inner.get().view()
174 }
175}
176
177#[cfg(test)]
178mod test {
179 use craballoc::{runtime::CpuRuntime, slab::SlabAllocator};
180
181 use super::*;
182
183 #[test]
184 fn camera_position_sanity() {
185 let slab = SlabAllocator::new(CpuRuntime, "camera test", ());
186 let camera = Camera::new(&slab);
187 let projection = Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, 1.0, 0.01, 10.0);
188 let view = Mat4::look_at_rh(Vec3::ONE, Vec3::ZERO, Vec3::Y);
189 camera.set_projection_and_view(projection, view);
190 let position = camera.descriptor().position();
191 assert_eq!(Vec3::ONE, position);
192 }
193}