mod3d_gltf/
object_data.rs

1//a Imports
2use mod3d_base::hierarchy::NodeEnumOp;
3use mod3d_base::{
4    BufferData, BufferDataAccessor, BufferDescriptor, BufferIndexAccessor, ByteBuffer, Renderable,
5    VertexDesc,
6};
7
8use crate::try_buf_parse_base64;
9use crate::Gltf;
10use crate::{
11    AccessorIndex, BufferIndex, BufferUsage, ImageIndex, MaterialIndex, MeshIndex, NodeIndex,
12    PrimitiveIndex, SamplerIndex, TextureIndex, ViewIndex,
13};
14use crate::{Error, Result};
15use crate::{
16    Indexable, ODAccIndex, ODBufDescIndex, ODImagesIndex, ODMaterialsIndex, ODTexturesIndex,
17    ODUses, ODVerticesIndex,
18};
19
20//a ObjectData
21//tp ObjectData
22/// The type that is used to construct mod3d_base from a Gltf
23///
24/// The objects from the Gltf that are required by the client must be added to this, so that
25/// the node hierarchy can be interrogated to determine which buffers,
26/// views, accessors, meshes, images, samples, and textures are
27/// required
28///
29/// Once the objects are added the uses must be derived (no more objects can be added at this point).
30///
31/// Once derived the mod3d_base::Buffer required must be generated;
32/// then the mod3d_base::BufferData; then the
33/// mod3d_base::BufferDataAccessor. These generate Vec of the relevant
34/// types, which must remain live until any object is made into an
35/// Instantiable; the [ObjectData] maintains indiices into these Vec
36/// for the Gltf buffers (etc) that are used by the required objects.
37///
38/// Then the Vertices are created; these borrow from the previous Vec
39/// of Buffer-related structures
40///
41/// Finally a mod3d_base::Object can be created, from which the
42/// client can create a mod3d_base::Instantiable; at this point the
43/// buffer data and vertices can be dropped (if the
44/// mod3d_base::Renderable permits it)
45#[derive(Debug)]
46pub struct ObjectData {
47    /// Nodes used in the object; this must contain all the mesh nodes (but not
48    /// the joint nodes)
49    nodes_used: Vec<NodeIndex>,
50    /// Nodes used in skeletons for the object
51    ///
52    /// There is no support (as yet) for unskinned meshes that are children of
53    /// joints; if a joint appears anywhere in the ancestors of an unskinned
54    /// mesh node then *unlike* the GLTF specification (which says the joint
55    /// pose should be used) the mesh is not posed, but placed at its static
56    /// positioning given by the hierarchy of nodes from its root node
57    #[allow(dead_code)]
58    joints_used: Vec<NodeIndex>,
59    materials_used: ODUses<MaterialIndex, ODMaterialsIndex>,
60
61    /// For each image in the Gltf, the index into the Vec<> array (if used and it
62    /// created the image without error)
63    images_used: ODUses<ImageIndex, ODImagesIndex>,
64
65    /// For each sampler in the Gltf, the index into the Vec<> array (if used and it
66    /// created the image without error)
67    ///
68    /// Actually currently unused
69    samplers_used: ODUses<SamplerIndex, ()>,
70
71    /// For each sampler in the Gltf, the index into the Vec<> array (if used and it
72    /// created the texture without error)
73    textures_used: ODUses<TextureIndex, ODTexturesIndex>,
74
75    /// A vec the same size as
76    /// json_value. which maps a Json buffer to
77    /// the range of it that is used
78    buffer_usage: Vec<BufferUsage>,
79
80    /// For each buffer descriptor, the index into the Vec<BufferDescriptor> (if used and it
81    /// worked); same size as gltf.buffer_views
82    buffer_descriptors: Vec<Option<ODBufDescIndex>>,
83
84    /// For each accessor (used by a primitive), the index into the
85    /// Vec<BufferDescriptor> and the vertex attr number within that
86    ///
87    /// Same size as gltf.accessors
88    accessors_as_bd: Vec<Option<(ODBufDescIndex, u8)>>,
89
90    /// For each accessor (used by a primitive), the index into the
91    /// Vec<BufferDataAccessor>
92    ///
93    /// Same size as gltf.accessors
94    accessors: Vec<Option<ODAccIndex>>,
95
96    /// For all meshes, if used Some(array of possible Vertices index for each
97    /// primitive); same size as gltf.meshes
98    ///
99    /// This maps each primitive that is used in each mesh that is
100    /// used (in the order of the Gltf fiile itself) to a client
101    /// Vertices index (which must be the same index as in the mod3d_base::Object
102    meshes: Vec<Option<Vec<Option<ODVerticesIndex>>>>,
103}
104
105//ip Index<BufferIndex> for ObjectData
106impl std::ops::Index<BufferIndex> for ObjectData {
107    type Output = BufferUsage;
108    fn index(&self, index: BufferIndex) -> &Self::Output {
109        &self.buffer_usage[index.as_usize()]
110    }
111}
112
113//ip IndexMut<BufferIndex> for ObjectData
114impl std::ops::IndexMut<BufferIndex> for ObjectData {
115    fn index_mut(&mut self, index: BufferIndex) -> &mut Self::Output {
116        &mut self.buffer_usage[index.as_usize()]
117    }
118}
119
120//ip Index<ViewIndex> for ObjectData
121impl std::ops::Index<ViewIndex> for ObjectData {
122    type Output = Option<ODBufDescIndex>;
123    fn index(&self, index: ViewIndex) -> &Self::Output {
124        &self.buffer_descriptors[index.as_usize()]
125    }
126}
127
128//ip IndexMut<ViewIndex> for ObjectData
129impl std::ops::IndexMut<ViewIndex> for ObjectData {
130    fn index_mut(&mut self, index: ViewIndex) -> &mut Self::Output {
131        &mut self.buffer_descriptors[index.as_usize()]
132    }
133}
134
135//ip Index<AccessorIndex> for ObjectData
136impl std::ops::Index<AccessorIndex> for ObjectData {
137    type Output = Option<ODAccIndex>;
138    fn index(&self, index: AccessorIndex) -> &Self::Output {
139        &self.accessors[index.as_usize()]
140    }
141}
142
143//ip IndexMut<AccessorIndex> for ObjectData
144impl std::ops::IndexMut<AccessorIndex> for ObjectData {
145    fn index_mut(&mut self, index: AccessorIndex) -> &mut Self::Output {
146        &mut self.accessors[index.as_usize()]
147    }
148}
149
150//ip Index<MeshIndex> for ObjectData
151impl std::ops::Index<MeshIndex> for ObjectData {
152    type Output = Option<Vec<Option<ODVerticesIndex>>>;
153    fn index(&self, index: MeshIndex) -> &Self::Output {
154        &self.meshes[index.as_usize()]
155    }
156}
157
158//ip IndexMut<MeshIndex> for ObjectData
159impl std::ops::IndexMut<MeshIndex> for ObjectData {
160    fn index_mut(&mut self, index: MeshIndex) -> &mut Self::Output {
161        &mut self.meshes[index.as_usize()]
162    }
163}
164
165//ip ObjectData
166impl ObjectData {
167    //cp new
168    /// Create a new [ObjectData]
169    pub fn new(gltf: &Gltf) -> Self {
170        let num_buffers = gltf.buffers().len();
171        let num_views = gltf.buffer_views().len();
172        let num_meshes = gltf.meshes().len();
173        let num_accessors = gltf.accessors().len();
174
175        let nodes_used = vec![];
176        let joints_used = vec![];
177        let materials_used = ODUses::new();
178        let textures_used = ODUses::new();
179        let images_used = ODUses::new();
180        let samplers_used = ODUses::new();
181        let buffer_usage = vec![Default::default(); num_buffers];
182        let buffer_descriptors = vec![Default::default(); num_views];
183        let meshes = vec![Default::default(); num_meshes];
184        let accessors_as_bd = vec![Default::default(); num_accessors];
185        let accessors = vec![Default::default(); num_accessors];
186        Self {
187            nodes_used,
188            joints_used,
189            materials_used,
190            textures_used,
191            buffer_usage,
192            buffer_descriptors,
193            meshes,
194            accessors_as_bd,
195            accessors,
196            images_used,
197            samplers_used,
198        }
199    }
200
201    //ap first_buffer
202    fn first_buffer(&mut self) -> Option<&mut BufferUsage> {
203        self.buffer_usage.get_mut(0)
204    }
205
206    //mi add_joint_node
207    /// Add a joint node to the set of nodes used by this Object
208    #[allow(dead_code)]
209    fn add_joint_node(&mut self, node: NodeIndex) {
210        if !self.joints_used.contains(&node) {
211            self.joints_used.push(node);
212        }
213    }
214
215    //mi add_node
216    /// Add a node index to the set of nodes used by this Object
217    fn add_node(&mut self, node: NodeIndex) {
218        if !self.nodes_used.contains(&node) {
219            self.nodes_used.push(node);
220        }
221    }
222
223    //mp add_object
224    /// Add an object to the ObjectData; adds all the nodes in the hierarchy of
225    /// the specified node
226    pub fn add_object(&mut self, gltf: &Gltf, node: NodeIndex) {
227        let nh_index = gltf.nh_index(node);
228        for eo in gltf.node_hierarchy().iter_from(nh_index.as_usize()) {
229            if let NodeEnumOp::Push((_, n), _) = eo {
230                self.add_node(*n);
231            }
232        }
233    }
234
235    //mi use_buffer
236    /// Record the use of a portion of a buffer in its Usage
237    ///
238    /// The buffer records the extents of its usage for both index and vertex
239    /// data, so that a client can map that data onto (e.g.) a GPU at a later
240    /// date
241    fn use_buffer(
242        &mut self,
243        as_index: bool,
244        buffer: BufferIndex,
245        byte_start: usize,
246        byte_length: usize,
247    ) {
248        self[buffer].use_buffer(as_index, byte_start, byte_length);
249    }
250
251    //mi derive_uses_of_meshes
252    /// Fill out the meshes and buffer regions that are used
253    fn derive_uses_of_meshes(&mut self, gltf: &Gltf) {
254        for n in 0..self.nodes_used.len() {
255            let ni: NodeIndex = n.into();
256            let node = &gltf[ni];
257            if let Some(node_mesh) = node.mesh() {
258                let mesh = &mut self[node_mesh];
259                if mesh.is_none() {
260                    let num_primitives = gltf[node_mesh].primitives().len();
261                    *mesh = Some(vec![None; num_primitives]);
262                }
263            }
264        }
265    }
266
267    //mi derive_uses_of_materials
268    /// Fill out the materials and generate list of accessors used
269    fn derive_uses_of_materials(&mut self, gltf: &Gltf) -> Vec<(bool, AccessorIndex)> {
270        let mut accessors = vec![];
271        for m in 0..self.meshes.len() {
272            let mi: MeshIndex = m.into();
273            if self[mi].is_some() {
274                let mesh = &gltf[mi];
275                for p in mesh.primitives() {
276                    if let Some(a) = p.indices() {
277                        accessors.push((true, a));
278                    }
279                    for (_, a) in p.attributes() {
280                        accessors.push((false, *a));
281                    }
282                    if let Some(m) = p.material() {
283                        self.materials_used.set_required(m);
284                    }
285                }
286            }
287        }
288        accessors
289    }
290
291    //mi derive_uses_of_accessors
292    /// Fill out the meshes and buffer regions that are used
293    fn derive_uses_of_accessors(&mut self, gltf: &Gltf, accessors: Vec<(bool, AccessorIndex)>) {
294        for (as_index, a) in accessors {
295            if let Some(bv) = gltf[a].buffer_view() {
296                let buffer = gltf[bv].buffer();
297                let byte_start = gltf[bv].byte_offset();
298                let byte_length = gltf[bv].byte_length();
299                self.use_buffer(as_index, buffer, byte_start, byte_length);
300            }
301        }
302    }
303
304    //mi derive_uses_of_textures
305    /// Fill out the texture usage
306    fn derive_uses_of_textures(&mut self, gltf: &Gltf) {
307        for (mi, _use) in self.materials_used.iter_required() {
308            let material = &gltf[mi];
309            if let Some(ti) = material.normal_texture() {
310                self.textures_used.set_required(ti.index());
311            }
312            if let Some(ti) = material.occlusion_texture() {
313                self.textures_used.set_required(ti.index());
314            }
315            if let Some(ti) = material.emissive_texture() {
316                self.textures_used.set_required(ti.index());
317            }
318            if let Some(pbr) = material.pbr_metallic_roughness() {
319                if let Some(ti) = pbr.base_color_texture() {
320                    self.textures_used.set_required(ti.index());
321                }
322                if let Some(ti) = pbr.metallic_roughness_texture() {
323                    self.textures_used.set_required(ti.index());
324                }
325            }
326        }
327    }
328
329    //mi derive_uses_of_images_and_samplers
330    /// Fill out the image usage
331    fn derive_uses_of_images_and_samplers(&mut self, gltf: &Gltf) {
332        for (ti, _use) in self.textures_used.iter_required() {
333            let texture = &gltf[ti];
334            self.images_used.set_required(texture.image());
335            self.samplers_used.set_required(texture.sampler());
336        }
337    }
338
339    //mp derive_uses
340    /// Derive which parts of the Gltf (and which parts of its
341    /// buffers) are required for the selected objects
342    pub fn derive_uses(&mut self, gltf: &Gltf) {
343        self.derive_uses_of_meshes(gltf);
344        let accessors = self.derive_uses_of_materials(gltf);
345        self.derive_uses_of_accessors(gltf, accessors);
346        self.derive_uses_of_textures(gltf);
347        self.derive_uses_of_images_and_samplers(gltf);
348        eprintln!("gltf : object_data : does not yet derive buffer uses of images - it won't gen_buffers for them");
349        // derive buffer uses of images
350        self.images_used.complete_uses();
351    }
352
353    //mp uses_buffer_zero
354    /// Returns true if buffer index 0 is used by the objects
355    ///
356    /// This is only valid after *derive_uses* has been invoked
357    pub fn uses_buffer_zero(&self) -> bool {
358        if let Some(b) = self.buffer_usage.first() {
359            b.is_used()
360        } else {
361            false
362        }
363    }
364
365    //mp gen_buffers
366    /// Generate a Vec of all the buffers required for the objects used in Gltf
367    ///
368    /// Drop the buffer descriptors in the GltfJsonValue as we go
369    ///
370    /// The first comes from opt_buffer_0 if Some; this may come from
371    /// a Glb file binary chunk, for example.
372    ///
373    /// The rest are created by invoking buf_parse on the Uri and
374    /// byte_length specified in the [GltfJsonValue]
375    pub fn gen_buffers<B, BP>(
376        &mut self,
377        gltf: &mut Gltf,
378        buf_parse: &BP,
379        opt_buffer_0: Option<B>,
380    ) -> Result<Vec<B>>
381    where
382        BP: Fn(&str, usize) -> Result<B>,
383    {
384        let mut result = vec![];
385        let mut used_opt_0 = false;
386        if let Some(b) = self.first_buffer() {
387            if b.is_used() && opt_buffer_0.is_some() {
388                result.push(opt_buffer_0.unwrap());
389                used_opt_0 = true;
390                b.set_buffer_index(0.into());
391            }
392        }
393        for i in 0..self.buffer_usage.len() {
394            let bi: BufferIndex = i.into();
395            let buffer = gltf.take_buffer_data(bi);
396            if !self[bi].is_used() {
397                continue;
398            }
399            if i > 0 || !used_opt_0 {
400                self[bi].set_buffer_index(result.len().into());
401                result.push(buf_parse(buffer.uri(), buffer.byte_length())?);
402            }
403        }
404        Ok(result)
405    }
406
407    //mp gen_byte_buffers
408    /// Generate a Vec of all the Vec<u8> buffers required for the objects used
409    /// in the Gltf
410    ///
411    /// This is the same as [gen_buffers] except that it requires the buffer
412    /// type by Vec<u8>, and it also implicitly supports base64 decode of data:
413    /// URIs
414    pub fn gen_byte_buffers<BP>(
415        &mut self,
416        gltf: &mut Gltf,
417        buf_parse: &BP,
418        opt_buffer_0: Option<Vec<u8>>,
419    ) -> Result<Vec<Vec<u8>>>
420    where
421        BP: Fn(&str, usize) -> Result<Vec<u8>>,
422    {
423        let bp = |uri: &str, byte_length: usize| {
424            if let Some(buf) = try_buf_parse_base64(uri, byte_length)? {
425                Ok(buf)
426            } else {
427                buf_parse(uri, byte_length)
428            }
429        };
430        self.gen_buffers(gltf, &bp, opt_buffer_0)
431    }
432
433    //mp gen_buffer_data
434    /// Generate [BufferData] from all of the buffer views (one BufferData per
435    /// view)
436    ///
437    /// Should be invoked after gen_buffers has returned a Vec<> of the buffers
438    /// used by the data
439    pub fn gen_buffer_data<'buffers, B, F, R>(&mut self, buffer: &F) -> Vec<BufferData<'buffers, R>>
440    where
441        B: ByteBuffer + ?Sized + 'buffers,
442        F: Fn(usize) -> &'buffers B,
443        R: Renderable,
444    {
445        let mut buffer_data = vec![];
446        for i in 0..self.buffer_usage.len() {
447            let bi: BufferIndex = i.into();
448            if !self[bi].is_used() {
449                continue;
450            }
451            let b = buffer(self[bi].buffer_index().as_usize());
452            if self[bi].has_index_data() {
453                self[bi].set_buffer_data(true, buffer_data.len().into());
454                let byte_offset = self[bi].index_data().start;
455                let byte_length = self[bi].index_data().end - byte_offset;
456                let bd = mod3d_base::BufferData::new(b, byte_offset as u32, byte_length as u32);
457                buffer_data.push(bd);
458            }
459            if self[bi].has_vertex_data() {
460                self[bi].set_buffer_data(false, buffer_data.len().into());
461                let byte_offset = self[bi].vertex_data().start;
462                let byte_length = self[bi].vertex_data().end - byte_offset;
463                let bd = mod3d_base::BufferData::new(b, byte_offset as u32, byte_length as u32);
464                buffer_data.push(bd);
465            }
466        }
467        buffer_data
468    }
469
470    //mp gen_images
471    /// Generate a Vec of all the images
472    pub fn gen_images<Image, F>(&mut self, gltf: &Gltf, get_image: &F) -> Result<Vec<Image>>
473    where
474        F: for<'a> Fn((usize, usize, usize), &'a str) -> std::result::Result<Image, String>,
475    {
476        let mut result = vec![];
477        for (ii, image_use) in self.images_used.iter_mut_required() {
478            let image = &gltf[ii];
479            let od_image = {
480                if let Some(uri) = image.uri() {
481                    get_image((0, 0, 0), uri)
482                } else {
483                    let bv = &gltf[image.buffer_view()];
484                    // Note the use of self.buffer_usage rather than self[bv.buffer()] which would be safer
485                    //
486                    // This is because self is partially borrowed mutably
487                    let buffer = self.buffer_usage[bv.buffer().as_usize()].buffer_index();
488                    let byte_offset = bv.byte_offset();
489                    let byte_length = bv.byte_length();
490                    get_image(
491                        (buffer.as_usize(), byte_offset, byte_length),
492                        image.mime_type(),
493                    )
494                }
495            }
496            .map_err(|e| Error::ImageLoad { reason: e })?;
497            let n = result.len();
498            result.push(od_image);
499            image_use.set_use(n.into());
500        }
501        Ok(result)
502    }
503
504    //mi make_index_accessor
505    fn make_index_accessor<'buffers, F, R>(
506        &self,
507        gltf: &Gltf,
508        buffer_data: &F,
509        acc: AccessorIndex,
510    ) -> BufferIndexAccessor<'buffers, R>
511    where
512        F: Fn(usize) -> &'buffers BufferData<'buffers, R>,
513        R: Renderable,
514    {
515        let ba = &gltf[acc];
516        let bv = ba.buffer_view().unwrap();
517        let bv = &gltf[bv];
518        let buffer = &self[bv.buffer()];
519        let data = buffer.index_bd();
520        let data = buffer_data(data.as_usize());
521        let byte_offset = ba.byte_offset() + bv.byte_offset() - (data.byte_offset() as usize);
522        let count = ba.count();
523        eprintln!("make_index_accessor ba:? {data:?}, {count}, {byte_offset}");
524        BufferIndexAccessor::new(data, count as u32, ba.component_type(), byte_offset as u32)
525    }
526
527    //mi make_descriptor
528    fn make_descriptor<'buffers, F, R>(
529        &self,
530        gltf: &Gltf,
531        buffer_data: &F,
532        view: ViewIndex,
533    ) -> BufferDescriptor<'buffers, R>
534    where
535        F: Fn(usize) -> &'buffers BufferData<'buffers, R>,
536        R: Renderable,
537    {
538        let bv = &gltf[view];
539        let buffer = &self[bv.buffer()];
540        let data = buffer.vertex_bd();
541        let data = buffer_data(data.as_usize());
542
543        let byte_offset = bv.byte_offset() - (data.byte_offset() as usize);
544        let byte_stride = bv.byte_stride(0);
545        let byte_length = bv.byte_length();
546        eprintln!("make_descriptor {view:?} {data:?}, {byte_offset}+{byte_length}, {byte_stride}");
547        BufferDescriptor::new(
548            data,
549            byte_offset as u32,
550            byte_length as u32,
551            byte_stride as u32,
552            vec![],
553        )
554    }
555
556    //mp gen_descriptors
557    /// Generate [BufferDescriptor] from all of the GltfBufferView
558    ///
559    /// Should be invoked after gen_buffer_data has returned a Vec<> of the
560    /// BufferData
561    ///
562    /// This creates a vec of (ViewIndex, Vec[VertexDesc]), from which
563    /// an array of BufferDescriptor are created and returned
564    ///
565    /// It also creates the something array which is then
566    pub fn gen_descriptors<'buffers, F, R>(
567        &mut self,
568        gltf: &Gltf,
569        buffer_data: &F,
570    ) -> Vec<BufferDescriptor<'buffers, R>>
571    where
572        F: Fn(usize) -> &'buffers BufferData<'buffers, R>,
573        R: Renderable,
574    {
575        let mut buffer_descriptors = vec![];
576
577        for i in 0..self.meshes.len() {
578            let mi: MeshIndex = i.into();
579            if self[mi].is_none() {
580                continue;
581            }
582            let mesh = &gltf[mi];
583            for p in mesh.primitives() {
584                for (vertex_attr, va) in p.attributes() {
585                    if self[*va].is_some() {
586                        continue;
587                    }
588                    let ba = &gltf[*va];
589                    let bv = ba.buffer_view().unwrap();
590                    if self[bv].is_none() {
591                        let bd = self.make_descriptor(gltf, buffer_data, bv);
592                        self.buffer_descriptors[*bv] = Some(buffer_descriptors.len().into());
593                        buffer_descriptors.push(bd);
594                    }
595                    let n = self[bv].unwrap();
596                    let dims = {
597                        match ba.elements_per_data() {
598                            1 => [0, 0],
599                            9 => [3, 3],
600                            16 => [4, 4],
601                            n => [n as u8, 0],
602                        }
603                    };
604                    let vertex_desc = VertexDesc::new(
605                        *vertex_attr,
606                        ba.component_type(),
607                        dims,
608                        ba.byte_offset() as u16,
609                    );
610                    eprintln!(
611                        "add_data_accessor {} {vertex_desc:?}",
612                        buffer_descriptors[n.as_usize()]
613                    );
614                    let v = buffer_descriptors[n.as_usize()].add_vertex_desc(vertex_desc);
615                    self.accessors_as_bd[(*va).as_usize()] = Some((n, v))
616                }
617            }
618        }
619        buffer_descriptors
620    }
621
622    //mp gen_accessors
623    /// Generate [BufferAccessor] from all of the accessors used by the mesh
624    /// primitives used in the objects used in the Gltf
625    ///
626    /// Should be invoked after gen_buffer_data has returned a Vec<> of the
627    /// BufferData
628    pub fn gen_accessors<'buffers, F, G, R>(
629        &mut self,
630        gltf: &Gltf,
631        buffer_data: &F,
632        buffer_desc: &G,
633    ) -> (
634        Vec<BufferIndexAccessor<'buffers, R>>,
635        Vec<BufferDataAccessor<'buffers, R>>,
636    )
637    where
638        F: Fn(usize) -> &'buffers BufferData<'buffers, R>,
639        G: Fn(usize) -> &'buffers BufferDescriptor<'buffers, R>,
640        R: Renderable,
641    {
642        let mut buffer_index_accessors = vec![];
643        let mut buffer_data_accessors = vec![];
644        for i in 0..self.meshes.len() {
645            let mi: MeshIndex = i.into();
646            if self[mi].is_none() {
647                continue;
648            }
649            let mesh = &gltf[mi];
650            for p in mesh.primitives() {
651                if let Some(ia) = p.indices() {
652                    if self[ia].is_some() {
653                        continue;
654                    }
655                    let b = self.make_index_accessor(gltf, buffer_data, ia);
656                    self[ia] = Some(buffer_index_accessors.len().into());
657                    buffer_index_accessors.push(b);
658                }
659            }
660            for (i, opt_n_v) in self.accessors_as_bd.iter().enumerate() {
661                let Some((n, v)) = opt_n_v else {
662                    continue;
663                };
664                let acc = BufferDataAccessor::new(buffer_desc(n.as_usize()), *v);
665                let n = buffer_data_accessors.len();
666                self.accessors[i] = Some(n.into());
667                buffer_data_accessors.push(acc);
668            }
669        }
670        (buffer_index_accessors, buffer_data_accessors)
671    }
672
673    //mp gen_vertices
674    /// Generate vertices from the objects in the Gltf, given buffer accessors
675    /// that have been generated already
676    pub fn gen_vertices<'vertices, F, G, R>(
677        &mut self,
678        gltf: &Gltf,
679        buffer_index_accessor: &F,
680        buffer_data_accessor: &G,
681    ) -> Vec<mod3d_base::Vertices<'vertices, R>>
682    where
683        F: Fn(usize) -> &'vertices BufferIndexAccessor<'vertices, R>,
684        G: Fn(usize) -> &'vertices BufferDataAccessor<'vertices, R>,
685        R: Renderable,
686    {
687        let mut vertices = vec![];
688        for i in 0..self.meshes.len() {
689            let mi: MeshIndex = i.into();
690            if self[mi].is_none() {
691                continue;
692            }
693            let mesh = &gltf[mi];
694            for (pi, p) in mesh.primitives().iter().enumerate() {
695                let Some(ia) = p.indices() else {
696                    continue;
697                };
698                let mut pa = None;
699                for (va, vpa) in p.attributes() {
700                    if *va == mod3d_base::VertexAttr::Position {
701                        pa = Some(vpa);
702                        break;
703                    }
704                }
705                let Some(pa) = pa else {
706                    continue;
707                };
708                let Some(ia) = self[ia] else {
709                    continue;
710                };
711                let Some(pa) = self[*pa] else {
712                    continue;
713                };
714                let indices = buffer_index_accessor(ia.as_usize());
715                let positions = buffer_data_accessor(pa.as_usize());
716                let mut v = mod3d_base::Vertices::new(Some(indices), positions);
717                for (va, vpa) in p.attributes() {
718                    if *va == mod3d_base::VertexAttr::Position {
719                        continue;
720                    }
721                    if let Some(vpa) = self[*vpa] {
722                        v.add_attr(buffer_data_accessor(vpa.as_usize()));
723                    }
724                }
725                let primitve_v = vertices.len();
726                vertices.push(v);
727                self[mi].as_mut().unwrap()[pi] = Some(primitve_v.into());
728            }
729        }
730
731        vertices
732    }
733
734    //mp gen_textures
735    /// Generate textures from the objects in the Gltf, given images
736    /// that have been generated already
737    pub fn gen_textures<'call, 'textures, F, I, R, T>(
738        &mut self,
739        gltf: &Gltf,
740        image: F,
741        texture_of_image: T,
742    ) -> Vec<mod3d_base::Texture<'textures, R>>
743    where
744        F: Fn(usize) -> &'call I,
745        I: 'call,
746        T: Fn(&'call I) -> mod3d_base::Texture<'textures, R>,
747        R: Renderable,
748    {
749        let mut textures = vec![];
750        for (ti, texture_use) in self.textures_used.iter_mut_required() {
751            let texture = &gltf[ti];
752            let image = image(self.images_used[texture.image].data().unwrap().as_usize());
753            let model_texture = texture_of_image(image);
754            let n = textures.len();
755            textures.push(model_texture);
756            texture_use.set_use(n.into());
757        }
758        textures
759    }
760
761    //mp gen_materials
762    // Create materials
763    pub fn gen_materials(&mut self, gltf: &Gltf) -> Vec<mod3d_base::PbrMaterial> {
764        let mut materials = vec![];
765
766        for (mi, material_use) in self.materials_used.iter_mut_required() {
767            let material = &gltf[mi];
768            let mut pbr_mat = mod3d_base::PbrMaterial::of_rgba(0xff112233);
769            if let Some(ti) = material.normal_texture() {
770                if let Some(ti) = self.textures_used[ti.index()].data() {
771                    pbr_mat.set_texture(mod3d_base::MaterialAspect::Normal, ti.into());
772                }
773            }
774            if let Some(ti) = material.occlusion_texture() {
775                if let Some(ti) = self.textures_used[ti.index()].data() {
776                    pbr_mat.set_texture(mod3d_base::MaterialAspect::Occlusion, ti.into());
777                }
778            }
779            if let Some(ti) = material.emissive_texture() {
780                if let Some(ti) = self.textures_used[ti.index()].data() {
781                    pbr_mat.set_texture(mod3d_base::MaterialAspect::Emission, ti.into());
782                }
783            }
784            pbr_mat.set_rgba((255, 255, 255, 255));
785            if let Some(pbr) = material.pbr_metallic_roughness() {
786                if let Some(ti) = pbr.base_color_texture() {
787                    if let Some(ti) = self.textures_used[ti.index()].data() {
788                        pbr_mat.set_texture(mod3d_base::MaterialAspect::Color, ti.into());
789                    }
790                }
791                if let Some(ti) = pbr.metallic_roughness_texture() {
792                    if let Some(ti) = self.textures_used[ti.index()].data() {
793                        pbr_mat
794                            .set_texture(mod3d_base::MaterialAspect::MetallicRoughness, ti.into());
795                    }
796                }
797                if let Some(color) = pbr.base_color_factor.as_ref() {
798                    // by spec there must be 4 entries of 0.0 to 1.0 inclusive
799                    if color.len() == 4 {
800                        let r = (color[0] * 255.0) as u8;
801                        let g = (color[1] * 255.0) as u8;
802                        let b = (color[2] * 255.0) as u8;
803                        let a = (color[3] * 255.0) as u8;
804                        pbr_mat.set_rgba((r, g, b, a));
805                    }
806                }
807                pbr_mat.set_mr(pbr.metallic_factor, pbr.roughness_factor);
808            }
809            {
810                let r = (material.emissive_factor[0] * 255.0) as u8;
811                let g = (material.emissive_factor[1] * 255.0) as u8;
812                let b = (material.emissive_factor[2] * 255.0) as u8;
813                pbr_mat.set_emissive_rgb((r, g, b));
814            }
815            let n = materials.len();
816            materials.push(pbr_mat);
817            material_use.set_use(n.into());
818        }
819
820        materials
821    }
822
823    //mp gen_object
824    /// Create object
825    pub fn gen_object<'object, M, R>(
826        &mut self,
827        gltf: &Gltf,
828        vertices: &'object [mod3d_base::Vertices<'object, R>],
829        textures: &'object [mod3d_base::Texture<'object, R>],
830        materials: &'object [M],
831    ) -> mod3d_base::Object<'object, M, R>
832    where
833        M: mod3d_base::Material + 'object,
834        R: Renderable,
835    {
836        let mut object = mod3d_base::Object::new();
837        for v in vertices {
838            object.add_vertices(v);
839        }
840        for t in textures {
841            object.add_texture(t);
842        }
843        for m in materials {
844            object.add_material(m);
845        }
846
847        for n in &self.nodes_used {
848            let node = &gltf[*n];
849            let Some(mi) = node.mesh() else {
850                continue;
851            };
852            let gltf_mesh = &gltf[mi];
853            let Some(od_mesh_prims) = &self[mi] else {
854                continue;
855            };
856            let mut mesh = mod3d_base::Mesh::default();
857            for (m_pi, opt_od_vi) in od_mesh_prims.iter().enumerate() {
858                let m_pi: PrimitiveIndex = m_pi.into();
859                let Some(od_vi) = *opt_od_vi else {
860                    continue;
861                };
862                let gltf_prim = &gltf_mesh[m_pi];
863                let ia = gltf_prim.indices().unwrap();
864                let index_count = gltf[ia].count() as u32;
865                let mat_ind: Option<usize> = Some(0);
866                let primitive = mod3d_base::Primitive::new(
867                    gltf_prim.primitive_type(),
868                    od_vi.into(),
869                    0,
870                    index_count,
871                    mat_ind.into(),
872                );
873                eprintln!("Add mesh {mesh:?} {m_pi} {primitive:?}");
874                mesh.add_primitive(primitive);
875            }
876            object.add_component(None, Some(*node.global_transformation()), mesh);
877        }
878        object
879    }
880}