renderling/primitive/
cpu.rs

1//! Mesh primitives.
2
3use core::ops::Deref;
4use std::sync::{Arc, Mutex};
5
6use craballoc::value::Hybrid;
7use crabslab::{Array, Id};
8
9use crate::{
10    bvol::BoundingSphere,
11    geometry::{Indices, MorphTargetWeights, MorphTargets, Skin, Vertices},
12    material::Material,
13    primitive::shader::PrimitiveDescriptor,
14    stage::Stage,
15    transform::Transform,
16    types::GpuOnlyArray,
17};
18
19/// A unit of rendering.
20///
21/// A `Primitive` represents one draw call, or one mesh primitive.
22pub struct Primitive {
23    pub(crate) descriptor: Hybrid<PrimitiveDescriptor>,
24
25    vertices: Arc<Mutex<Option<Vertices<GpuOnlyArray>>>>,
26    indices: Arc<Mutex<Option<Indices<GpuOnlyArray>>>>,
27
28    pub(crate) transform: Arc<Mutex<Option<Transform>>>,
29    pub(crate) material: Arc<Mutex<Option<Material>>>,
30    skin: Arc<Mutex<Option<Skin>>>,
31    morph_targets: Arc<Mutex<Option<(MorphTargets, MorphTargetWeights)>>>,
32}
33
34impl Primitive {
35    /// Create a new [`Primitive`], automatically adding it to the
36    /// [`Stage`](crate::stage::Stage) to be drawn.
37    ///
38    /// The returned [`Primitive`] will have the stage's default [`Vertices`],
39    /// which is an all-white unit cube.
40    pub fn new(stage: &Stage) -> Self {
41        let descriptor = stage
42            .geometry
43            .slab_allocator()
44            .new_value(PrimitiveDescriptor::default());
45        let primitive = Primitive {
46            descriptor,
47            vertices: Default::default(),
48            indices: Default::default(),
49            transform: Default::default(),
50            material: Default::default(),
51            skin: Default::default(),
52            morph_targets: Default::default(),
53        }
54        .with_vertices(stage.default_vertices());
55        stage.add_primitive(&primitive);
56        primitive
57    }
58}
59
60impl Clone for Primitive {
61    fn clone(&self) -> Self {
62        Self {
63            descriptor: self.descriptor.clone(),
64            vertices: self.vertices.clone(),
65            indices: self.indices.clone(),
66            transform: self.transform.clone(),
67            material: self.material.clone(),
68            skin: self.skin.clone(),
69            morph_targets: self.morph_targets.clone(),
70        }
71    }
72}
73
74// Vertices impls
75impl Primitive {
76    /// Set the vertex data of this primitive.
77    pub fn set_vertices(&self, vertices: impl Into<Vertices<GpuOnlyArray>>) -> &Self {
78        let vertices = vertices.into();
79        let array = vertices.array();
80        self.descriptor.modify(|d| d.vertices_array = array);
81        *self.vertices.lock().unwrap() = Some(vertices.clone());
82        self
83    }
84
85    /// Set the vertex data of this primitive and return the primitive.
86    pub fn with_vertices(self, vertices: impl Into<Vertices<GpuOnlyArray>>) -> Self {
87        self.set_vertices(vertices);
88        self
89    }
90}
91
92// Indices impls
93impl Primitive {
94    /// Set the index data of this primitive.
95    pub fn set_indices(&self, indices: impl Into<Indices<GpuOnlyArray>>) -> &Self {
96        let indices = indices.into();
97        let array = indices.array();
98        self.descriptor.modify(|d| d.indices_array = array);
99        *self.indices.lock().unwrap() = Some(indices.clone());
100        self
101    }
102
103    /// Set the index data of this primitive and return the primitive.
104    pub fn with_indices(self, indices: impl Into<Indices<GpuOnlyArray>>) -> Self {
105        self.set_indices(indices);
106        self
107    }
108
109    /// Remove the indices from this primitive.
110    pub fn remove_indices(&self) -> &Self {
111        *self.indices.lock().unwrap() = None;
112        self.descriptor.modify(|d| d.indices_array = Array::NONE);
113        self
114    }
115}
116
117// PrimitiveDescriptor impls
118impl Primitive {
119    /// Return a pointer to the underlying descriptor on the GPU.
120    pub fn id(&self) -> Id<PrimitiveDescriptor> {
121        self.descriptor.id()
122    }
123
124    /// Return the underlying descriptor.
125    pub fn descriptor(&self) -> PrimitiveDescriptor {
126        self.descriptor.get()
127    }
128
129    /// Set the bounds of this primitive.
130    pub fn set_bounds(&self, bounds: BoundingSphere) -> &Self {
131        self.descriptor.modify(|d| d.bounds = bounds);
132        self
133    }
134
135    /// Set the bounds and return the primitive.
136    pub fn with_bounds(self, bounds: BoundingSphere) -> Self {
137        self.set_bounds(bounds);
138        self
139    }
140
141    /// Get the bounds.
142    ///
143    /// Returns the current [`BoundingSphere`].
144    pub fn bounds(&self) -> BoundingSphere {
145        self.descriptor.get().bounds
146    }
147
148    /// Modify the bounds of the primitive.
149    ///
150    /// # Arguments
151    ///
152    /// * `f` - A closure that takes a mutable reference to the
153    ///   [`BoundingSphere`] and returns a value of type `T`.
154    pub fn modify_bounds<T: 'static>(&self, f: impl FnOnce(&mut BoundingSphere) -> T) -> T {
155        self.descriptor.modify(|d| f(&mut d.bounds))
156    }
157
158    /// Set the visibility of this primitive.
159    pub fn set_visible(&self, visible: bool) -> &Self {
160        self.descriptor.modify(|d| d.visible = visible);
161        self
162    }
163
164    /// Set the visibility and return the primitive.
165    pub fn with_visible(self, visible: bool) -> Self {
166        self.set_visible(visible);
167        self
168    }
169
170    /// Return the primitive's visibility.
171    pub fn visible(&self) -> bool {
172        self.descriptor.get().visible
173    }
174
175    /// Modify the visible of the primitive.
176    ///
177    /// # Arguments
178    ///
179    /// * `f` - A closure that takes a mutable reference to the visibility and
180    ///   returns a value of type `T`.
181    pub fn modify_visible<T: 'static>(&self, f: impl FnOnce(&mut bool) -> T) -> T {
182        self.descriptor.modify(|d| f(&mut d.visible))
183    }
184}
185
186// Transform functions
187impl Primitive {
188    /// Set the transform.
189    ///
190    /// # Note
191    /// This can be set with [`Transform`] or
192    /// [`NestedTransform`](crate::transform::NestedTransform).
193    pub fn set_transform(&self, transform: impl Into<Transform>) -> &Self {
194        let transform = transform.into();
195        self.descriptor.modify(|d| d.transform_id = transform.id());
196        *self.transform.lock().unwrap() = Some(transform.clone());
197        self
198    }
199
200    /// Set the transform and return the `Primitive`.
201    ///
202    /// # Note
203    /// This can be set with [`Transform`] or
204    /// [`NestedTransform`](crate::transform::NestedTransform).
205    pub fn with_transform(self, transform: impl Into<Transform>) -> Self {
206        self.set_transform(transform);
207        self
208    }
209
210    /// Get the transform.
211    ///
212    /// Returns a reference to the current `Transform`, if any.
213    pub fn transform(&self) -> impl Deref<Target = Option<Transform>> + '_ {
214        self.transform.lock().unwrap()
215    }
216
217    /// Remove the transform from this primitive.
218    ///
219    /// This effectively makes the transform the identity.
220    pub fn remove_transform(&self) -> &Self {
221        self.descriptor.modify(|d| d.transform_id = Id::NONE);
222        *self.transform.lock().unwrap() = None;
223        self
224    }
225}
226
227// Material impls
228impl Primitive {
229    /// Set the material of this primitive.
230    pub fn set_material(&self, material: impl Into<Material>) -> &Self {
231        let material = material.into();
232        self.descriptor.modify(|d| d.material_id = material.id());
233        *self.material.lock().unwrap() = Some(material);
234        self
235    }
236
237    /// Set the material and return the primitive.
238    pub fn with_material(self, material: impl Into<Material>) -> Self {
239        self.set_material(material);
240        self
241    }
242
243    /// Get the material.
244    ///
245    /// Returns a reference to the current `Material`, if any.
246    pub fn material(&self) -> impl Deref<Target = Option<Material>> + '_ {
247        self.material.lock().unwrap()
248    }
249
250    /// Remove the material from this primitive.
251    pub fn remove_material(&self) -> &Self {
252        self.descriptor.modify(|d| d.material_id = Id::NONE);
253        *self.material.lock().unwrap() = None;
254        self
255    }
256}
257
258// Skin impls
259impl Primitive {
260    /// Set the skin of this primitive.
261    pub fn set_skin(&self, skin: impl Into<Skin>) -> &Self {
262        let skin = skin.into();
263        self.descriptor.modify(|d| d.skin_id = skin.id());
264        *self.skin.lock().unwrap() = Some(skin.clone());
265        self
266    }
267
268    /// Set the skin and return the primitive.
269    pub fn with_skin(self, skin: impl Into<Skin>) -> Self {
270        self.set_skin(skin);
271        self
272    }
273
274    /// Get the skin.
275    ///
276    /// Returns a reference to the current `Skin`, if any.
277    pub fn skin(&self) -> impl Deref<Target = Option<Skin>> + '_ {
278        self.skin.lock().unwrap()
279    }
280
281    /// Remove the skin from this primitive.
282    pub fn remove_skin(&self) -> &Self {
283        self.descriptor.modify(|d| d.skin_id = Id::NONE);
284        *self.skin.lock().unwrap() = None;
285        self
286    }
287}
288
289// (MorphTargets, MorphTargetsWeights) impls
290impl Primitive {
291    /// Set the morph targets and weights of this primitive.
292    pub fn set_morph_targets(
293        &self,
294        morph_targets: impl Into<MorphTargets>,
295        weights: impl Into<MorphTargetWeights>,
296    ) -> &Self {
297        let morph_targets = morph_targets.into();
298        let weights = weights.into();
299        self.descriptor.modify(|d| {
300            d.morph_targets = morph_targets.array();
301            d.morph_weights = weights.array();
302        });
303        *self.morph_targets.lock().unwrap() = Some((morph_targets.clone(), weights.clone()));
304        self
305    }
306
307    /// Set the morph targets and weights and return the primitive.
308    pub fn with_morph_targets(
309        self,
310        morph_targets: impl Into<MorphTargets>,
311        weights: impl Into<MorphTargetWeights>,
312    ) -> Self {
313        self.set_morph_targets(morph_targets, weights);
314        self
315    }
316
317    /// Get the morph targets and weights.
318    ///
319    /// Returns a reference to the current `MorphTargets` and `MorphTargetsWeights`, if any.
320    pub fn morph_targets(
321        &self,
322    ) -> impl Deref<Target = Option<(MorphTargets, MorphTargetWeights)>> + '_ {
323        self.morph_targets.lock().unwrap()
324    }
325
326    /// Remove the morph targets and weights from this primitive.
327    pub fn remove_morph_targets(&self) -> &Self {
328        self.descriptor.modify(|d| {
329            d.morph_targets = Array::NONE;
330            d.morph_weights = Array::NONE;
331        });
332        *self.morph_targets.lock().unwrap() = None;
333        self
334    }
335}