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