mod3d_gltf/
gltf.rs

1//a Imports
2use mod3d_base::hierarchy::Hierarchy;
3use mod3d_base::Transformation;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[cfg(feature = "serde_json")]
9use serde_json::Value as JsonValue;
10
11#[cfg(not(feature = "serde_json"))]
12pub type JsonValue = ();
13
14use crate::{
15    AccessorIndex, BufferIndex, ImageIndex, Indexable, MaterialIndex, MeshIndex, NHIndex,
16    NodeIndex, SceneIndex, TextureIndex, ViewIndex,
17};
18use crate::{Error, Named, Result};
19use crate::{
20    GltfAccessor, GltfAsset, GltfBuffer, GltfBufferView, GltfImage, GltfMaterial, GltfMesh,
21    GltfNode, GltfScene, GltfTexture,
22};
23
24//a Gltf
25//tp Gltf
26/// A Gltf file
27#[derive(Debug, Default)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29#[cfg_attr(feature = "serde", serde(default))]
30pub struct Gltf {
31    /// The 'asset' field is required in Gltf; it describes the version of Gltf
32    /// that the Json is in, and copyright, generator and other such
33    /// information
34    asset: GltfAsset,
35
36    /// All the 'buffers' from the Json file, in gltf order; this is
37    /// the URI but not any client-side buffer representation
38    buffers: Vec<GltfBuffer>,
39
40    /// All the 'bufferViews' from the Json file, in gltf order;
41    /// buffers are referred to by BufferIndex into the 'buffers'
42    /// property
43    #[cfg_attr(feature = "serde", serde(rename = "bufferViews"))]
44    buffer_views: Vec<GltfBufferView>,
45
46    /// All the 'accessors' from the Json file, in gltf order;
47    /// buffer views are referred to by ViewIndex into the 'buffer_views'
48    /// property
49    accessors: Vec<GltfAccessor>,
50
51    /// All the 'materials' from the Json file, in gltf order
52    /// Currently not filled out
53    materials: Vec<GltfMaterial>,
54
55    /// All the 'meshes' from the Json file, in gltf order; the
56    /// primitives refer to accessors and materials by AccessorIndex
57    /// and MaterialIndex into the relevant properties
58    meshes: Vec<GltfMesh>,
59
60    /// All the 'nodes' from the Json file, representing nodes in a
61    /// hierarchy of meshes AND nodes in a skeleton - gltf conflates
62    /// the two (plus cameras, lights, etc)
63    nodes: Vec<GltfNode>,
64
65    /// The default scene to be presented by the gltf
66    scene: Option<SceneIndex>,
67
68    /// The scenes in the gltf; each refers to an array of NodeIndex
69    /// that are the roots of the (distinct) trees that are to be
70    /// rendered for a scene
71    scenes: Vec<GltfScene>,
72
73    /// The camers in the gltf; currently unfilled
74    cameras: Vec<JsonValue>,
75
76    /// The image descriptors from the Json file; this is the URI or
77    /// buffer views, not the underlying image data
78    images: Vec<GltfImage>,
79
80    /// The sampler descriptors from the Json file
81    samplers: JsonValue,
82
83    /// The texture descriptors from the Json file; these refer to
84    /// SamplerIndex and ImageIndex
85    textures: Vec<GltfTexture>,
86
87    /// The skin (skeleton) descriptors from the Json file
88    skins: Vec<JsonValue>,
89
90    /// The animations in the Json file
91    animations: JsonValue,
92
93    /// The hierarchy of nodes
94    ///
95    /// This is generated after the Json file is read; Gltf requries
96    /// the nodes to form distinct trees (each node is in precisely
97    /// one tree) so a hierarchy will have each NodeInde once as
98    /// either a root or once as the child of a single parent
99    #[cfg_attr(feature = "serde", serde(skip_deserializing))]
100    #[cfg_attr(feature = "serde", serde(skip_serializing))]
101    node_hierarchy: Hierarchy<NodeIndex>,
102
103    /// A mapping from NodeIndex to node_hierarchy index
104    ///
105    /// Which node hierarchy element a particular NodeIndex corresponds to
106    #[cfg_attr(feature = "serde", serde(skip_deserializing))]
107    #[cfg_attr(feature = "serde", serde(skip_serializing))]
108    nh_index: Vec<NHIndex>,
109}
110
111//ip Index<NodeIndex> for Gltf
112impl std::ops::Index<NodeIndex> for Gltf {
113    type Output = GltfNode;
114    fn index(&self, index: NodeIndex) -> &Self::Output {
115        &self.nodes[index.as_usize()]
116    }
117}
118
119//ip Index<AccessorIndex> for Gltf
120impl std::ops::Index<AccessorIndex> for Gltf {
121    type Output = GltfAccessor;
122    fn index(&self, index: AccessorIndex) -> &Self::Output {
123        &self.accessors[index.as_usize()]
124    }
125}
126
127//ip Index<ViewIndex> for Gltf
128impl std::ops::Index<ViewIndex> for Gltf {
129    type Output = GltfBufferView;
130    fn index(&self, index: ViewIndex) -> &Self::Output {
131        &self.buffer_views[index.as_usize()]
132    }
133}
134
135//ip Index<MeshIndex> for Gltf
136impl std::ops::Index<MeshIndex> for Gltf {
137    type Output = GltfMesh;
138    fn index(&self, index: MeshIndex) -> &Self::Output {
139        &self.meshes[index.as_usize()]
140    }
141}
142
143//ip Index<ImageIndex> for Gltf
144impl std::ops::Index<ImageIndex> for Gltf {
145    type Output = GltfImage;
146    fn index(&self, index: ImageIndex) -> &Self::Output {
147        &self.images[index.as_usize()]
148    }
149}
150
151//ip Index<TextureIndex> for Gltf
152impl std::ops::Index<TextureIndex> for Gltf {
153    type Output = GltfTexture;
154    fn index(&self, index: TextureIndex) -> &Self::Output {
155        &self.textures[index.as_usize()]
156    }
157}
158
159//ip Index<MaterialIndex> for Gltf
160impl std::ops::Index<MaterialIndex> for Gltf {
161    type Output = GltfMaterial;
162    fn index(&self, index: MaterialIndex) -> &Self::Output {
163        &self.materials[index.as_usize()]
164    }
165}
166
167//ip Gltf
168impl Gltf {
169    pub fn set_asset(&mut self, asset: GltfAsset) {
170        self.asset = asset;
171    }
172
173    pub fn add_buffer(&mut self, buffer: GltfBuffer) -> BufferIndex {
174        let n = self.buffers.len();
175        self.buffers.push(buffer);
176        n.into()
177    }
178    pub fn add_mesh(&mut self, mesh: GltfMesh) -> MeshIndex {
179        let n = self.meshes.len();
180        self.meshes.push(mesh);
181        n.into()
182    }
183    pub fn add_node(&mut self, node: GltfNode) -> NodeIndex {
184        let n = self.nodes.len();
185        self.nodes.push(node);
186        n.into()
187    }
188    pub fn add_scene(&mut self, scene: GltfScene) -> SceneIndex {
189        let n = self.scenes.len();
190        self.scenes.push(scene);
191        n.into()
192    }
193    pub fn add_view(
194        &mut self,
195        buffer: BufferIndex,
196        byte_offset: usize,
197        byte_length: usize,
198        byte_stride: Option<usize>,
199    ) -> ViewIndex {
200        let view = GltfBufferView {
201            buffer,
202            byte_length,
203            byte_offset,
204            byte_stride,
205        };
206
207        let n = self.buffer_views.len();
208        self.buffer_views.push(view);
209        n.into()
210    }
211    pub fn add_accessor(
212        &mut self,
213        buffer_view: ViewIndex,
214        byte_offset: u32,
215        count: u32,
216        element_type: mod3d_base::BufferElementType,
217        elements_per_data: usize,
218    ) -> AccessorIndex {
219        let acc = GltfAccessor::new(
220            buffer_view,
221            byte_offset as usize,
222            count as usize,
223            element_type,
224            elements_per_data,
225        );
226
227        let n = self.accessors.len();
228        self.accessors.push(acc);
229        n.into()
230    }
231    //mp validate_buffer_views
232    /// Validate the contents - check indices in range, etc
233    fn validate_buffer_views(&self) -> Result<()> {
234        let n = self.buffers.len();
235        for (i, bv) in self.buffer_views.iter().enumerate() {
236            let b = bv.buffer();
237            if b.as_usize() >= n {
238                return Err(Error::BadJson(format!(
239                    "Buffer view index {i} has buffer {b} out of range (must be < {n})",
240                )));
241            }
242            let l = self.buffers[b.as_usize()].byte_length();
243            if bv.byte_end() > l {
244                return Err(Error::BadJson(format!(
245                    "Buffer view index {i} specifies subrange outside the buffer size {l})",
246                )));
247            }
248        }
249        Ok(())
250    }
251
252    //mp validate_accessors
253    /// Validate the contents - check indices in range, etc
254    fn validate_accessors(&self) -> Result<()> {
255        let n = self.buffer_views.len();
256        for acc in &self.accessors {
257            let bv_index = acc.buffer_view();
258            let Some(bv_index) = bv_index else {
259                return Err(Error::BadJson(
260                    "Accessor is not permitted to not specify a BufferView in this GLTF reader"
261                        .into(),
262                ));
263            };
264            if bv_index.as_usize() >= n {
265                return Err(Error::BadJson(format!(
266                    "Accessor's buffer view index {bv_index} out of range (must be < {n})",
267                )));
268            }
269            let bv = &self.buffer_views[bv_index.as_usize()];
270            let acc_byte_end = acc.byte_view_end(bv.byte_stride(0));
271            if acc_byte_end > bv.byte_length() {
272                return Err(Error::BadJson(format!(
273                    "Accessor's last element ends (@{0}) beyond end of buffer view index {1} (at {2})",
274                    acc_byte_end,
275                    bv.buffer(),
276                    bv.byte_length()
277                )));
278            }
279        }
280        Ok(())
281    }
282
283    //mp validate_nodes
284    pub fn validate_nodes(&self) -> Result<()> {
285        let l = self.nodes.len();
286        for (i, n) in self.nodes.iter().enumerate() {
287            for c in n.iter_children() {
288                if c.as_usize() >= l {
289                    return Err(Error::BadJson(format!(
290                        "Node {i} has child index {c} out of range",
291                    )));
292                }
293            }
294            if let Some(m) = n.mesh() {
295                if m.as_usize() > self.meshes.len() {
296                    return Err(Error::BadJson(format!(
297                        "Node {i} has mesh index {m} out of range",
298                    )));
299                }
300            }
301            if let Some(c) = n.camera() {
302                if c.as_usize() > self.cameras.len() {
303                    return Err(Error::BadJson(format!(
304                        "Node {i} has camera index {c} out of range",
305                    )));
306                }
307            }
308            if let Some(s) = n.skin() {
309                if s.as_usize() > self.skins.len() {
310                    return Err(Error::BadJson(format!(
311                        "Node {i} has skin index {s} out of range",
312                    )));
313                }
314            }
315            n.validate(i.into())?;
316        }
317        Ok(())
318    }
319
320    //mp validate
321    /// Validate the contents - check indices in range, etc
322    pub fn validate(&self) -> Result<()> {
323        dbg!(self);
324        self.validate_buffer_views()?;
325        self.validate_accessors()?;
326        self.validate_nodes()?;
327        Ok(())
328    }
329
330    //ap buffers
331    pub fn buffers(&self) -> &[GltfBuffer] {
332        &self.buffers
333    }
334
335    //ap accessors
336    /// Get a reference to the accessors
337    pub fn accessors(&self) -> &[GltfAccessor] {
338        &self.accessors
339    }
340
341    //ap node_hierarchy
342    /// Get a reference to the [Hierarchy] of nodes, as indices
343    pub fn node_hierarchy(&self) -> &Hierarchy<NodeIndex> {
344        &self.node_hierarchy
345    }
346
347    //ap get_node
348    /// Get the [NodeIndex] of a named node, a a node by its usize index (as a
349    /// string)
350    ///
351    /// If the node is not found then return None
352    pub fn get_node(&self, name: &str) -> Option<NodeIndex> {
353        GltfNode::get_named(self.nodes(), name)
354    }
355
356    //mp take_buffer_data
357    pub fn take_buffer_data(&mut self, buffer: BufferIndex) -> GltfBuffer {
358        self.buffers[buffer.as_usize()].take_buffer()
359    }
360
361    //ap buffer_views
362    pub fn buffer_views(&self) -> &[GltfBufferView] {
363        &self.buffer_views
364    }
365
366    //ap nodes
367    pub fn nodes(&self) -> &[GltfNode] {
368        &self.nodes
369    }
370
371    //ap meshes
372    pub fn meshes(&self) -> &[GltfMesh] {
373        &self.meshes
374    }
375
376    //ap nh_index
377    pub fn nh_index(&self, node: NodeIndex) -> NHIndex {
378        self.nh_index[node.as_usize()]
379    }
380
381    //cp of_json_value
382    /// Create a [GltfJsonValue] from a [serde::json::Value], doing
383    /// some validation
384    #[cfg(feature = "serde_json")]
385    pub fn of_json_value(json_value: JsonValue) -> Result<Self> {
386        let mut s: Self = serde_json::from_value(json_value)?;
387        s.validate()?;
388        s.gen_node_hierarchy();
389        s.derive();
390        Ok(s)
391    }
392
393    //mp gen_node_hierarchy
394    // Create nodes (componentts) and objects (somehow)
395    pub fn gen_node_hierarchy(&mut self) {
396        if !self.node_hierarchy.is_empty() {
397            return;
398        }
399        let n = self.nodes.len();
400        self.nh_index = vec![0.into(); n];
401        for i in 0..n {
402            let ni: NodeIndex = i.into();
403            self.nh_index[i] = self.node_hierarchy.add_node(ni).into();
404        }
405        for (i, n) in self.nodes.iter().enumerate() {
406            for c in n.iter_children() {
407                self.node_hierarchy.relate(i, c.as_usize());
408            }
409        }
410        self.node_hierarchy.find_roots();
411    }
412
413    //mp derive
414    /// Derive any extra state required
415    pub fn derive(&mut self) {
416        for r in self.node_hierarchy.borrow_roots() {
417            let mut stack = vec![Transformation::default()];
418            for x in self.node_hierarchy.enum_from(*r) {
419                let (is_push, n, has_children) = x.unpack();
420                if is_push {
421                    let t = self.nodes[*n].derive(stack.last().unwrap());
422                    if has_children {
423                        stack.push(*t);
424                    }
425                } else if has_children {
426                    stack.pop();
427                }
428            }
429        }
430    }
431}