renderling/geometry/
cpu.rs

1//! CPU side of the [super::geometry](geometry) module.
2use std::sync::{Arc, Mutex};
3
4use craballoc::{
5    runtime::{IsRuntime, WgpuRuntime},
6    slab::{SlabAllocator, SlabBuffer},
7    value::{GpuArray, Hybrid, HybridArray, IsContainer},
8};
9use crabslab::{Array, Id};
10use glam::{Mat4, UVec2, Vec4};
11
12use crate::{
13    camera::Camera,
14    geometry::{
15        shader::{GeometryDescriptor, SkinDescriptor},
16        MorphTarget, Vertex,
17    },
18    transform::{shader::TransformDescriptor, NestedTransform, Transform},
19    types::{GpuCpuArray, GpuOnlyArray},
20};
21
22/// A contiguous array of vertices, staged on the GPU.
23///
24/// The type variable `Ct` denotes whether the staged data lives on the GPU
25/// only, or on the CPU and the GPU.
26///
27/// # Note
28/// The amount of data staged in `Vertices` can potentially be very large, and
29/// it is common to unload the data from the CPU with
30/// [`Vertices::into_gpu_only`].
31///
32/// The only reason to keep data on the CPU is if it needs to be inspected and
33/// modified _in place_. This type of modification can be done with
34/// [`Vertices::modify_vertex`].
35///
36/// After unloading it is still possible to _replace_ a [`Vertex`] at a
37/// specific index using [`Vertices::set_vertex`].
38pub struct Vertices<Ct: IsContainer = GpuCpuArray> {
39    inner: Ct::Container<Vertex>,
40}
41
42impl<Ct> Clone for Vertices<Ct>
43where
44    Ct: IsContainer,
45    Ct::Container<Vertex>: Clone,
46{
47    fn clone(&self) -> Self {
48        Self {
49            inner: self.inner.clone(),
50        }
51    }
52}
53
54impl<Ct> std::fmt::Debug for Vertices<Ct>
55where
56    Ct: IsContainer<Pointer<Vertex> = Array<Vertex>>,
57{
58    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
59        f.debug_struct("Vertices")
60            .field("array", &Ct::get_pointer(&self.inner))
61            .finish()
62    }
63}
64
65impl From<Vertices> for Vertices<GpuOnlyArray> {
66    fn from(value: Vertices) -> Self {
67        value.into_gpu_only()
68    }
69}
70
71impl From<&Vertices> for Vertices<GpuOnlyArray> {
72    fn from(value: &Vertices) -> Self {
73        value.clone().into_gpu_only()
74    }
75}
76
77impl From<&Vertices<GpuOnlyArray>> for Vertices<GpuOnlyArray> {
78    fn from(value: &Vertices<GpuOnlyArray>) -> Self {
79        value.clone()
80    }
81}
82
83impl Vertices {
84    /// Stage a new array of vertex data on the GPU.
85    ///
86    /// The resulting `Vertices` will live on the GPU and CPU, allowing for modification.
87    /// If you would like to unload the CPU side, use [`Vertices::into_gpu_only`].
88    pub(crate) fn new(
89        slab: &SlabAllocator<WgpuRuntime>,
90        vertices: impl IntoIterator<Item = Vertex>,
91    ) -> Self {
92        Vertices {
93            inner: slab.new_array(vertices),
94        }
95    }
96
97    /// Unload the CPU side of vertex data.
98    ///
99    /// After this operation the data can still be updated using [`Vertices::set_item`],
100    /// but it cannot be modified in-place.
101    pub fn into_gpu_only(self) -> Vertices<GpuOnlyArray> {
102        Vertices {
103            inner: self.inner.into_gpu_only(),
104        }
105    }
106
107    /// Returns a [`Vertex`] at a specific index, if any.
108    pub fn get_vertex(&self, index: usize) -> Option<Vertex> {
109        self.inner.get(index)
110    }
111
112    /// Return all vertices as a vector.
113    pub fn get_vec(&self) -> Vec<Vertex> {
114        self.inner.get_vec()
115    }
116
117    /// Modify a vertex at a specific index, if it exists.
118    pub fn modify_vertex<T: 'static>(
119        &self,
120        index: usize,
121        f: impl FnOnce(&mut Vertex) -> T,
122    ) -> Option<T> {
123        self.inner.modify(index, f)
124    }
125}
126
127impl<T> Vertices<T>
128where
129    T: IsContainer<Pointer<Vertex> = Array<Vertex>>,
130{
131    /// Returns a pointer to the underlying data on the GPU.
132    pub fn array(&self) -> Array<Vertex> {
133        T::get_pointer(&self.inner)
134    }
135}
136
137impl Vertices<GpuOnlyArray> {
138    /// Set the [`Vertex`] at the given index to the given value, if the item at
139    /// the index exists.
140    pub fn set_vertex(&self, index: usize, value: &Vertex) {
141        self.inner.set_item(index, value)
142    }
143}
144
145/// A contiguous array of indices, staged on the GPU.
146/// The type variable `Ct` denotes whether the data lives on the GPU only, or on
147/// the CPU and the GPU.
148pub struct Indices<Ct: IsContainer = GpuCpuArray> {
149    inner: Ct::Container<u32>,
150}
151
152impl<Ct> std::fmt::Debug for Indices<Ct>
153where
154    Ct: IsContainer<Pointer<u32> = Array<u32>>,
155{
156    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157        f.debug_struct("Indices")
158            .field("array", &Ct::get_pointer(&self.inner))
159            .finish()
160    }
161}
162
163impl<Ct> Clone for Indices<Ct>
164where
165    Ct: IsContainer,
166    Ct::Container<u32>: Clone,
167{
168    fn clone(&self) -> Self {
169        Self {
170            inner: self.inner.clone(),
171        }
172    }
173}
174
175impl From<Indices> for Indices<GpuOnlyArray> {
176    fn from(value: Indices) -> Self {
177        value.into_gpu_only()
178    }
179}
180
181impl From<&Indices> for Indices<GpuOnlyArray> {
182    fn from(value: &Indices) -> Self {
183        value.clone().into_gpu_only()
184    }
185}
186
187impl From<&Indices<GpuOnlyArray>> for Indices<GpuOnlyArray> {
188    fn from(value: &Indices<GpuOnlyArray>) -> Self {
189        value.clone()
190    }
191}
192
193impl<T> Indices<T>
194where
195    T: IsContainer<Pointer<u32> = Array<u32>>,
196{
197    /// Returns a pointer to the underlying data on the GPU.
198    pub fn array(&self) -> Array<u32> {
199        T::get_pointer(&self.inner)
200    }
201}
202
203impl Indices {
204    /// Stage a new array of index data on the GPU.
205    ///
206    /// The resulting `Indices` will live on the GPU and CPU, allowing for modification.
207    /// If you would like to unload the CPU side, use [`Indices::into_gpu_only`].
208    pub fn new(geometry: &Geometry, indices: impl IntoIterator<Item = u32>) -> Self {
209        Indices {
210            inner: geometry.slab.new_array(indices),
211        }
212    }
213
214    /// Unload the CPU side of this index data.
215    pub fn into_gpu_only(self) -> Indices<GpuOnlyArray> {
216        Indices {
217            inner: self.inner.into_gpu_only(),
218        }
219    }
220}
221
222/// Holds morph targets for animated nodes.
223#[derive(Clone)]
224pub struct MorphTargets {
225    // Held onto so the values don't drop from under us
226    _targets: Arc<Vec<GpuArray<MorphTarget>>>,
227    arrays: HybridArray<Array<MorphTarget>>,
228}
229
230impl From<&MorphTargets> for MorphTargets {
231    fn from(value: &MorphTargets) -> Self {
232        value.clone()
233    }
234}
235
236impl std::fmt::Debug for MorphTargets {
237    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
238        f.debug_struct("MorphTargets")
239            .field("arrays", &self.arrays)
240            .field("targets", &"...")
241            .finish()
242    }
243}
244
245impl MorphTargets {
246    pub(crate) fn new(
247        slab: &SlabAllocator<impl IsRuntime>,
248        morph_targets: impl IntoIterator<Item = impl IntoIterator<Item = MorphTarget>>,
249    ) -> Self {
250        let targets = morph_targets
251            .into_iter()
252            .map(|verts| slab.new_array(verts).into_gpu_only())
253            .collect::<Vec<_>>();
254        let arrays = slab.new_array(targets.iter().map(|ts| ts.array()));
255        Self {
256            _targets: targets.into(),
257            arrays,
258        }
259    }
260    /// Returns a pointer to the underlying morph targets data on the GPU.                    
261    pub fn array(&self) -> Array<Array<MorphTarget>> {
262        self.arrays.array()
263    }
264}
265
266/// Holds morph targets weights for animated nodes.
267#[derive(Clone, Debug)]
268pub struct MorphTargetWeights {
269    inner: HybridArray<f32>,
270}
271
272impl From<&MorphTargetWeights> for MorphTargetWeights {
273    fn from(value: &MorphTargetWeights) -> Self {
274        value.clone()
275    }
276}
277
278impl MorphTargetWeights {
279    pub(crate) fn new(
280        slab: &SlabAllocator<impl IsRuntime>,
281        data: impl IntoIterator<Item = f32>,
282    ) -> Self {
283        Self {
284            inner: slab.new_array(data),
285        }
286    }
287
288    /// Returns a pointer to the underlying morph targets weights data on the GPU.            
289    pub fn array(&self) -> Array<f32> {
290        self.inner.array()
291    }
292
293    /// Return the weight at the given index, if any.
294    pub fn get_item(&self, index: usize) -> Option<f32> {
295        self.inner.get(index)
296    }
297
298    /// Update the weight at the given index.
299    pub fn set_item(&self, index: usize, weight: f32) {
300        self.inner.set_item(index, weight);
301    }
302}
303
304/// Wrapper around the geometry slab, which holds mesh data and more.
305#[derive(Clone)]
306pub struct Geometry {
307    slab: SlabAllocator<WgpuRuntime>,
308    descriptor: Hybrid<GeometryDescriptor>,
309    /// A plain white cube to use as default geometry.
310    default_vertices: Vertices,
311    /// Holds the current camera just in case the user drops it,
312    /// this way we never lose a camera that is in use. Dropping
313    /// the camera would cause a blank screen, which is very confusing
314    /// =(
315    camera: Arc<Mutex<Option<Camera>>>,
316}
317
318impl AsRef<WgpuRuntime> for Geometry {
319    fn as_ref(&self) -> &WgpuRuntime {
320        self.slab.runtime()
321    }
322}
323
324impl AsRef<SlabAllocator<WgpuRuntime>> for Geometry {
325    fn as_ref(&self) -> &SlabAllocator<WgpuRuntime> {
326        &self.slab
327    }
328}
329
330impl Geometry {
331    pub fn new(runtime: impl AsRef<WgpuRuntime>, resolution: UVec2, atlas_size: UVec2) -> Self {
332        let runtime = runtime.as_ref();
333        let slab = SlabAllocator::new(runtime, "geometry", wgpu::BufferUsages::empty());
334        let descriptor = slab.new_value(GeometryDescriptor {
335            atlas_size,
336            resolution,
337            ..Default::default()
338        });
339        let default_vertices = Vertices::new(
340            &slab,
341            crate::math::unit_cube().into_iter().map(|(p, n)| {
342                Vertex::default()
343                    .with_position(p)
344                    .with_normal(n)
345                    .with_color(Vec4::ONE)
346            }),
347        );
348        Self {
349            slab,
350            descriptor,
351            default_vertices,
352            camera: Default::default(),
353        }
354    }
355
356    pub fn runtime(&self) -> &WgpuRuntime {
357        self.as_ref()
358    }
359
360    pub fn slab_allocator(&self) -> &SlabAllocator<WgpuRuntime> {
361        self.as_ref()
362    }
363
364    pub fn descriptor(&self) -> &Hybrid<GeometryDescriptor> {
365        &self.descriptor
366    }
367
368    /// Returns the vertices of a white unit cube.
369    pub fn default_vertices(&self) -> &Vertices {
370        &self.default_vertices
371    }
372
373    #[must_use]
374    pub fn commit(&self) -> SlabBuffer<wgpu::Buffer> {
375        self.slab.commit()
376    }
377
378    /// Create a new camera.
379    ///
380    /// If this is the first camera created, it will be automatically used.
381    pub fn new_camera(&self) -> Camera {
382        let c = Camera::new(&self.slab);
383        if self.descriptor.get().camera_id.is_none() {
384            self.use_camera(&c);
385        }
386        c
387    }
388
389    /// Set all geometry to use the given camera.
390    pub fn use_camera(&self, camera: &Camera) {
391        let id = camera.id();
392        log::info!("using camera: {id:?}");
393        // Save a clone so we never lose the active camera, even if the user drops it
394        self.descriptor.modify(|cfg| cfg.camera_id = id);
395        *self.camera.lock().unwrap() = Some(camera.clone());
396    }
397
398    /// Stage a new transform.
399    pub fn new_transform(&self) -> Transform {
400        Transform::new(&self.slab)
401    }
402
403    /// Stage vertex geometry data on the GPU.
404    pub fn new_vertices(&self, vertices: impl IntoIterator<Item = Vertex>) -> Vertices {
405        Vertices::new(self.slab_allocator(), vertices)
406    }
407
408    /// Stage indices that point to offsets of an array of vertices.
409    pub fn new_indices(&self, indices: impl IntoIterator<Item = u32>) -> Indices {
410        Indices::new(self, indices)
411    }
412
413    /// Stage new morph targets on the GPU.
414    pub fn new_morph_targets(
415        &self,
416        data: impl IntoIterator<Item = impl IntoIterator<Item = MorphTarget>>,
417    ) -> MorphTargets {
418        MorphTargets::new(&self.slab, data)
419    }
420
421    /// Create new morph target weights.
422    pub fn new_morph_target_weights(
423        &self,
424        data: impl IntoIterator<Item = f32>,
425    ) -> MorphTargetWeights {
426        MorphTargetWeights::new(&self.slab, data)
427    }
428
429    /// Create a new array of matrices.
430    pub fn new_matrices(&self, data: impl IntoIterator<Item = Mat4>) -> HybridArray<Mat4> {
431        self.slab.new_array(data)
432    }
433
434    pub fn new_skin(
435        &self,
436        joints: impl IntoIterator<Item = impl Into<SkinJoint>>,
437        inverse_bind_matrices: impl IntoIterator<Item = impl Into<Mat4>>,
438    ) -> Skin {
439        Skin::new(self.slab_allocator(), joints, inverse_bind_matrices)
440    }
441}
442
443/// A vertex skin.
444///
445/// For more info on vertex skinning, see
446/// <https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_019_SimpleSkin.html>
447#[derive(Clone)]
448pub struct Skin {
449    descriptor: Hybrid<SkinDescriptor>,
450    joints: HybridArray<Id<TransformDescriptor>>,
451    // Held onto so the transforms don't drop from under us
452    _skin_joints: Arc<Mutex<Vec<SkinJoint>>>,
453    // Contains the 4x4 inverse-bind matrices.
454    //
455    // When None, each matrix is assumed to be the 4x4 identity matrix which implies that the
456    // inverse-bind matrices were pre-applied.
457    _inverse_bind_matrices: Arc<Mutex<Option<GpuArray<Mat4>>>>,
458}
459
460impl From<&Skin> for Skin {
461    fn from(value: &Skin) -> Self {
462        value.clone()
463    }
464}
465
466impl core::fmt::Debug for Skin {
467    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
468        f.debug_struct("Skin")
469            .field("descriptor", &self.descriptor)
470            .field("joints", &self.joints)
471            .field("joint_transforms", &"...")
472            .field("inverse_bind_matrices", &"...")
473            .finish()
474    }
475}
476
477impl Skin {
478    /// Stage a new skin on the GPU.
479    pub fn new(
480        slab: &SlabAllocator<impl IsRuntime>,
481        joints: impl IntoIterator<Item = impl Into<SkinJoint>>,
482        inverse_bind_matrices: impl IntoIterator<Item = impl Into<Mat4>>,
483    ) -> Self {
484        let descriptor = slab.new_value(SkinDescriptor::default());
485        let skin_joints = joints.into_iter().map(|t| t.into()).collect::<Vec<_>>();
486        let joints = skin_joints.iter().map(|sj| sj.0.id()).collect::<Vec<_>>();
487        let inverse_bind_matrices = inverse_bind_matrices
488            .into_iter()
489            .map(|m| m.into())
490            .collect::<Vec<_>>();
491        let inverse_bind_matrices = if inverse_bind_matrices.is_empty() {
492            None
493        } else {
494            Some(slab.new_array(inverse_bind_matrices).into_gpu_only())
495        };
496
497        Skin {
498            descriptor,
499            joints: slab.new_array(joints),
500            // We hold on to the transforms so they don't get dropped if the user drops them.
501            _skin_joints: Arc::new(Mutex::new(skin_joints)),
502            _inverse_bind_matrices: Arc::new(Mutex::new(inverse_bind_matrices)),
503        }
504    }
505
506    /// Return a pointer to the underlying descriptor data on the GPU.
507    pub fn id(&self) -> Id<SkinDescriptor> {
508        self.descriptor.id()
509    }
510
511    /// Return a copy of the underlying descriptor.
512    pub fn descriptor(&self) -> SkinDescriptor {
513        self.descriptor.get()
514    }
515}
516
517/// A joint in a skinned rigging.
518///
519/// This is a thin wrapper over [`Transform`] and
520/// [`NestedTransform`]. You can create a [`SkinJoint`]
521/// from either of those types using the [`From`] trait.
522///
523/// You can also pass an iterator of either [`Transform`] or [`NestedTransform`]
524/// to [`Stage::new_skin`](crate::stage::Stage::new_skin).
525pub struct SkinJoint(pub(crate) Transform);
526
527impl From<Transform> for SkinJoint {
528    fn from(transform: Transform) -> Self {
529        SkinJoint(transform)
530    }
531}
532
533impl From<&Transform> for SkinJoint {
534    fn from(transform: &Transform) -> Self {
535        transform.clone().into()
536    }
537}
538
539impl From<NestedTransform> for SkinJoint {
540    fn from(value: NestedTransform) -> Self {
541        SkinJoint(value.global_transform)
542    }
543}
544
545impl From<&NestedTransform> for SkinJoint {
546    fn from(value: &NestedTransform) -> Self {
547        value.clone().into()
548    }
549}