Skip to main content

mraphics_core/geometry/
geometry.rs

1use crate::{GadgetData, GadgetIndex, InstanceUpdater, Interpolatable, constants};
2use nalgebra::Matrix4;
3use std::collections::HashMap;
4
5pub trait AllowedIndexFormat {}
6impl AllowedIndexFormat for u32 {}
7impl AllowedIndexFormat for u16 {}
8
9#[derive(Debug, Clone)]
10pub struct CustomIndices<T: AllowedIndexFormat> {
11    pub data: Vec<T>,
12    pub buffer: Option<wgpu::Buffer>,
13}
14
15impl<T: AllowedIndexFormat> CustomIndices<T> {
16    pub fn new(data: Vec<T>) -> Self {
17        Self { data, buffer: None }
18    }
19}
20
21#[derive(Debug, Clone)]
22pub enum GeometryIndices {
23    Sequential(u32),
24    CustomU16(CustomIndices<u16>),
25    CustomU32(CustomIndices<u32>),
26}
27
28#[derive(Debug)]
29pub enum GeometryViewError {
30    UnknownAttributeLabel,
31    UnknownUniformLabel,
32}
33
34/// A view of geometric data that can be consumed by shaders.
35///
36/// This struct represents a collection of attributes, uniforms, and indices
37/// that define a geometry.
38#[derive(Debug)]
39pub struct GeometryView {
40    /// Vertex attributes of the geometry (e.g., position, normal, color).
41    pub attributes: Vec<GadgetData>,
42
43    /// Maps attribute labels to their indices in [`Self::attributes`].
44    /// Used for querying a attribute by its label.
45    attribute_map: HashMap<String, usize>,
46
47    /// Uniform variables of the geometry.
48    pub uniforms: Vec<GadgetData>,
49
50    /// Maps uniform labels to their indices in [`Self::uniforms`].
51    /// Used for querying a uniform by its label.
52    uniform_map: HashMap<String, usize>,
53
54    /// Index buffer specifying how vertices are connected.
55    pub indices: GeometryIndices,
56}
57
58impl GeometryView {
59    pub fn new() -> Self {
60        let mut out = Self {
61            indices: GeometryIndices::Sequential(0),
62
63            attributes: Vec::new(),
64            attribute_map: HashMap::new(),
65
66            uniforms: Vec::new(),
67            uniform_map: HashMap::new(),
68        };
69
70        out.add_uniform(
71            constants::MODEL_MAT_LABEL,
72            constants::MODEL_MAT_INDEX,
73            bytemuck::cast_slice(Matrix4::<f32>::identity().as_slice()).to_vec(),
74        );
75
76        out
77    }
78
79    pub fn with_indices(mut self, indices: GeometryIndices) -> Self {
80        self.indices = indices;
81        self
82    }
83
84    pub fn with_attributes(mut self, attributes: Vec<GadgetData>) -> Self {
85        self.attributes = attributes;
86        self
87    }
88
89    pub fn with_uniforms(mut self, uniforms: Vec<GadgetData>) -> Self {
90        self.uniforms = uniforms;
91        self
92    }
93
94    pub fn add_attribute(&mut self, label: &str, index: GadgetIndex, data: Vec<u8>) {
95        let attribute = GadgetData {
96            label: label.to_string(),
97            index,
98            data,
99            needs_update_value: true,
100            needs_update_buffer: true,
101        };
102
103        self.attribute_map
104            .insert(attribute.label.clone(), self.attributes.len());
105        self.attributes.push(attribute);
106    }
107
108    pub fn get_attribute(&self, label: &str) -> Result<&GadgetData, GeometryViewError> {
109        if let Some(index) = self.attribute_map.get(label) {
110            let attribute = &self.attributes[*index];
111            return Ok(attribute);
112        }
113
114        Err(GeometryViewError::UnknownAttributeLabel)
115    }
116
117    pub fn get_attribute_mut(&mut self, label: &str) -> Result<&mut GadgetData, GeometryViewError> {
118        if let Some(index) = self.attribute_map.get(label) {
119            let attribute = &mut self.attributes[*index];
120            return Ok(attribute);
121        }
122
123        Err(GeometryViewError::UnknownAttributeLabel)
124    }
125
126    pub fn set_attribute(&mut self, label: &str, data: Vec<u8>) -> Result<(), GeometryViewError> {
127        let attribute = self.get_attribute_mut(label)?;
128
129        if attribute.data.len() != data.len() {
130            attribute.needs_update_buffer = true;
131        }
132
133        attribute.data = data;
134        attribute.needs_update_value = true;
135
136        Ok(())
137    }
138
139    pub fn get_uniform(&self, label: &str) -> Result<&GadgetData, GeometryViewError> {
140        if let Some(index) = self.uniform_map.get(label) {
141            let uniform = &self.uniforms[*index];
142            return Ok(uniform);
143        }
144
145        Err(GeometryViewError::UnknownUniformLabel)
146    }
147
148    pub fn get_uniform_mut(&mut self, label: &str) -> Result<&mut GadgetData, GeometryViewError> {
149        if let Some(index) = self.uniform_map.get(label) {
150            let uniform = &mut self.uniforms[*index];
151            return Ok(uniform);
152        }
153
154        Err(GeometryViewError::UnknownUniformLabel)
155    }
156
157    pub fn add_uniform(&mut self, label: &str, index: GadgetIndex, data: Vec<u8>) {
158        let uniform = GadgetData {
159            label: label.to_string(),
160            index,
161            data,
162            needs_update_value: true,
163            needs_update_buffer: true,
164        };
165
166        self.uniform_map
167            .insert(uniform.label.clone(), self.uniforms.len());
168        self.uniforms.push(uniform);
169    }
170
171    pub fn set_uniform(&mut self, label: &str, data: Vec<u8>) -> Result<(), GeometryViewError> {
172        let uniform = self.get_uniform_mut(label)?;
173
174        if uniform.data.len() != data.len() {
175            uniform.needs_update_buffer = true;
176        }
177
178        uniform.data = data;
179        uniform.needs_update_value = true;
180
181        Ok(())
182    }
183
184    pub fn reset_vertices(&mut self) {
185        self.attributes = Vec::new();
186        self.attribute_map = HashMap::new();
187        self.indices = GeometryIndices::Sequential(0);
188    }
189
190    pub fn reset_uniforms(&mut self) {
191        self.uniforms = Vec::new();
192        self.uniform_map = HashMap::new();
193    }
194}
195
196/// A trait for objects that can both initialize and update a [`GeometryView`].
197///
198/// Types implementing this trait can:
199/// - Create a complete geometry view from scratch
200/// - Modify an existing geometry view
201/// - Are cloneable to support duplication of geometric data.
202///
203/// # Required Trait Bounds
204/// - [`Clone`]: For copying geometric data
205pub trait Geometry: Clone {
206    /// Initializes a new [`GeometryView`].
207    fn init_view(&self, view: &mut GeometryView);
208
209    /// Updates an existing [`GeometryView`] with this object's data.
210    fn update_view(&self, view: &mut GeometryView);
211
212    /// Updates self before updating geometry view, optional.
213    fn update(&mut self) {}
214}
215
216/// The minimal implementation of [`Geometry`]
217///
218/// A collection of vertices in homogeneous coordinates (x, y, z, w).
219/// This is typically used as an intermediate representation, especially in animations.
220#[derive(Clone)]
221pub struct Vertices {
222    pub data: Vec<[f32; 4]>,
223}
224
225impl Vertices {
226    /// Craetes a new collection of vertices.
227    pub fn new() -> Self {
228        Self { data: Vec::new() }
229    }
230
231    /// Applies a transform.
232    pub fn apply_transform<Trans: Fn(&[f32; 4]) -> [f32; 4]>(&self, transform: Trans) -> Self {
233        Self {
234            data: self.data.iter().map(transform).collect(),
235        }
236    }
237
238    /// Updates a instance with [`Vertices`].
239    ///
240    /// # Notes
241    /// This implementation does not modify existing indices
242    pub fn update_geometry_view(&self, view: &mut GeometryView) {
243        let mut vertices = Vec::new();
244
245        for vertex in &self.data {
246            vertices.push(vertex[0]);
247            vertices.push(vertex[1]);
248            vertices.push(vertex[2]);
249            vertices.push(vertex[3]);
250        }
251
252        view.set_attribute(
253            crate::constants::POSITION_ATTR_LABEL,
254            Vec::from(bytemuck::cast_slice::<f32, u8>(&vertices)),
255        )
256        .unwrap();
257    }
258}
259
260impl Interpolatable for Vertices {
261    fn interpolate(&self, to: &Self, p: f32) -> Self {
262        Self {
263            data: self.data.interpolate(&to.data, p),
264        }
265    }
266}
267
268/// Updates a instance with [`Vertices`].
269///
270/// # Notes
271/// This implementation only modifies geometry view and it does not modify existing indices
272impl InstanceUpdater for Vertices {
273    fn update_instance(&self, instance: &mut super::RenderInstance) {
274        self.update_geometry_view(&mut instance.geometry);
275    }
276}
277
278impl Geometry for Vertices {
279    fn init_view(&self, view: &mut GeometryView) {
280        view.add_attribute(
281            crate::constants::POSITION_ATTR_LABEL,
282            crate::constants::POSITION_ATTR_INDEX,
283            bytemuck::cast_slice::<f32, u8>(&self.data.concat()).to_vec(),
284        );
285    }
286
287    fn update_view(&self, view: &mut GeometryView) {
288        self.update_geometry_view(view);
289    }
290}