mesh_loader/collada/
iter.rs

1use std::{
2    iter::{self, FusedIterator},
3    ops::Range,
4    slice,
5};
6
7use crate::{collada as ast, Face, Vec2, Vec3};
8
9#[derive(Clone)]
10pub(super) struct Mesh<'a> {
11    pub(super) doc: &'a ast::Document<'a>,
12    pub(super) xml: &'a ast::Geometry<'a>,
13}
14
15impl<'a> Mesh<'a> {
16    pub(super) fn primitives(&self) -> Primitives<'a> {
17        Primitives {
18            mesh: self.clone(),
19            iter: self.xml.mesh.primitives.iter().enumerate(),
20        }
21    }
22}
23
24pub(super) struct Primitives<'a> {
25    mesh: Mesh<'a>,
26    iter: iter::Enumerate<slice::Iter<'a, ast::Primitive<'a>>>,
27}
28
29impl<'a> Iterator for Primitives<'a> {
30    type Item = Primitive<'a>;
31
32    fn next(&mut self) -> Option<Self::Item> {
33        self.iter.next().map(|(_index, xml)| Primitive {
34            mesh: self.mesh.clone(),
35            xml,
36        })
37    }
38
39    fn size_hint(&self) -> (usize, Option<usize>) {
40        self.iter.size_hint()
41    }
42}
43
44impl ExactSizeIterator for Primitives<'_> {}
45impl FusedIterator for Primitives<'_> {}
46
47#[derive(Clone)]
48pub(super) struct Primitive<'a> {
49    pub(super) mesh: Mesh<'a>,
50    pub(super) xml: &'a ast::Primitive<'a>,
51}
52
53impl<'a> Primitive<'a> {
54    pub(super) fn positions(&self) -> Positions<'a> {
55        let input = match &self.xml.input {
56            Some(input) => input,
57            None => return Positions(None),
58        };
59        if self.mesh.xml.mesh.vertices.id == input.vertex.source {
60            let position = &self.mesh.xml.mesh.vertices.input.position;
61            let acc = &self.mesh.doc[&position.source];
62            let data = self.mesh.doc[&acc.source].as_float().unwrap();
63            // ["X", "Y", "Z"]
64            if acc.stride < 3 || acc.params.len() < 3 || acc.params.iter().any(|p| p.ty != "float")
65            {
66                // TODO: error?
67                return Positions(None);
68            }
69            assert!((acc.count * acc.stride) as usize <= data.len());
70            Positions(Some((acc.count, data.chunks(acc.stride as usize))))
71        } else {
72            // TODO: search other mesh's vertices
73            todo!()
74        }
75    }
76
77    pub(super) fn normals(&self) -> Normals<'a> {
78        let acc = match &self.xml.input {
79            Some(input) => match &input.normal {
80                Some(normal) => &self.mesh.doc[&normal.source],
81                None => {
82                    if self.mesh.xml.mesh.vertices.id == input.vertex.source {
83                        match &self.mesh.xml.mesh.vertices.input.normal {
84                            Some(normal) => &self.mesh.doc[&normal.source],
85                            None => return Positions(None),
86                        }
87                    } else {
88                        // TODO: search other mesh's vertices
89                        todo!()
90                    }
91                }
92            },
93            None => return Positions(None),
94        };
95        let data = self.mesh.doc[&acc.source].as_float().unwrap();
96        // ["X", "Y", "Z"]
97        if acc.stride < 3 || acc.params.len() < 3 || acc.params.iter().any(|p| p.ty != "float") {
98            // TODO: error?
99            return Positions(None);
100        }
101        assert!((acc.count * acc.stride) as usize <= data.len());
102        Positions(Some((acc.count, data.chunks(acc.stride as usize))))
103    }
104
105    pub(super) fn texcoords(&self, set: usize) -> Texcoords<'a> {
106        let acc = match &self.xml.input {
107            Some(input) => {
108                if let Some(texcoord) = input.texcoord.get(set) {
109                    &self.mesh.doc[&texcoord.source]
110                } else if set == 0 {
111                    if self.mesh.xml.mesh.vertices.id == input.vertex.source {
112                        match &self.mesh.xml.mesh.vertices.input.texcoord {
113                            Some(texcoord) => &self.mesh.doc[&texcoord.source],
114                            None => return Texcoords(None),
115                        }
116                    } else {
117                        // TODO: search other mesh's vertices
118                        todo!()
119                    }
120                } else {
121                    return Texcoords(None);
122                }
123            }
124            None => return Texcoords(None),
125        };
126        let data = self.mesh.doc[&acc.source].as_float().unwrap();
127        // ["S", "T"] or ["S", "T", "P"]
128        if acc.stride < 2 || acc.params.len() < 2 || acc.params.iter().any(|p| p.ty != "float") {
129            // TODO: error?
130            return Texcoords(None);
131        }
132        assert!((acc.count * acc.stride) as usize <= data.len());
133        Texcoords(Some(TexcoordsInner {
134            iter: data.chunks(acc.stride as usize),
135        }))
136    }
137
138    pub(super) fn colors(&self) -> Colors<'a> {
139        let acc = match &self.xml.input {
140            Some(input) => match &input.color {
141                Some(color) => &self.mesh.doc[&color.source],
142                None => {
143                    if self.mesh.xml.mesh.vertices.id == input.vertex.source {
144                        match &self.mesh.xml.mesh.vertices.input.color {
145                            Some(color) => &self.mesh.doc[&color.source],
146                            None => return Positions(None),
147                        }
148                    } else {
149                        // TODO: search other mesh's vertices
150                        todo!()
151                    }
152                }
153            },
154            None => return Positions(None),
155        };
156        let data = self.mesh.doc[&acc.source].as_float().unwrap();
157        // ["R", "G", "B"] or ["R", "G", "B", "A"]
158        if acc.stride < 3 || acc.params.len() < 3 || acc.params.iter().any(|p| p.ty != "float") {
159            // TODO: error?
160            return Positions(None);
161        }
162        assert!((acc.count * acc.stride) as usize <= data.len());
163        Positions(Some((acc.count, data.chunks(acc.stride as usize))))
164    }
165
166    fn vertex_indices_inner(&self, offset: u32) -> IndicesInner<'a> {
167        match self.xml.ty {
168            ast::PrimitiveType::Lines | ast::PrimitiveType::LineStrips => IndicesInner::Skip,
169            ast::PrimitiveType::Polylist | ast::PrimitiveType::Polygons => IndicesInner::Polylist {
170                offset,
171                indices: &self.xml.p,
172                stride: self.xml.stride,
173                index: 0,
174                vcount: self.xml.vcount.iter(),
175                range: None,
176            },
177            ast::PrimitiveType::Triangles => IndicesInner::Triangles {
178                offset,
179                indices: self.xml.p.chunks(self.xml.stride as usize),
180            },
181            ast::PrimitiveType::TriStrips | ast::PrimitiveType::TriFans => {
182                IndicesInner::TriStrips {
183                    offset,
184                    indices: &self.xml.p,
185                    stride: self.xml.stride,
186                    index: 0,
187                    vcount: self.xml.vcount.iter(),
188                    range: None,
189                }
190            }
191        }
192    }
193
194    fn vertex_indices_size(&self) -> u32 {
195        match self.xml.ty {
196            ast::PrimitiveType::Polylist | ast::PrimitiveType::Polygons => self
197                .xml
198                .vcount
199                .iter()
200                .map(|count| if *count >= 3 { count - 2 } else { 0 })
201                .sum(),
202            ast::PrimitiveType::Triangles => self.xml.count,
203            ast::PrimitiveType::TriStrips | ast::PrimitiveType::TriFans => {
204                self.xml.vcount.iter().map(|&count| count - 2).sum()
205            }
206            ast::PrimitiveType::Lines => 0,
207            ast::PrimitiveType::LineStrips => 0,
208        }
209    }
210
211    pub(super) fn vertex_indices(&self) -> VertexIndices<'a> {
212        let offset = match &self.xml.input {
213            Some(input) => input.vertex.offset,
214            None => return VertexIndices::none(),
215        };
216        VertexIndices {
217            remaining: self.vertex_indices_size(),
218            inner: self.vertex_indices_inner(offset),
219        }
220    }
221
222    pub(super) fn normal_indices(&self) -> VertexIndices<'a> {
223        let offset = match &self.xml.input {
224            Some(input) => match &input.normal {
225                Some(normal) => normal.offset,
226                None => {
227                    if self.mesh.xml.mesh.vertices.id == input.vertex.source {
228                        if self.mesh.xml.mesh.vertices.input.normal.is_some() {
229                            input.vertex.offset
230                        } else {
231                            return VertexIndices::none();
232                        }
233                    } else {
234                        // TODO: search other mesh's vertices
235                        todo!()
236                    }
237                }
238            },
239            None => return VertexIndices::none(),
240        };
241        VertexIndices {
242            remaining: self.vertex_indices_size(),
243            inner: self.vertex_indices_inner(offset),
244        }
245    }
246
247    pub(super) fn texcoord_indices(&self, set: usize) -> VertexIndices<'a> {
248        let offset = match &self.xml.input {
249            Some(input) => match input.texcoord.get(set) {
250                Some(texcoord) => texcoord.offset,
251                None => {
252                    if self.mesh.xml.mesh.vertices.id == input.vertex.source {
253                        if self.mesh.xml.mesh.vertices.input.texcoord.is_some() {
254                            input.vertex.offset
255                        } else {
256                            return VertexIndices::none();
257                        }
258                    } else {
259                        // TODO: search other mesh's vertices
260                        todo!()
261                    }
262                }
263            },
264            None => return VertexIndices::none(),
265        };
266        VertexIndices {
267            remaining: self.vertex_indices_size(),
268            inner: self.vertex_indices_inner(offset),
269        }
270    }
271
272    pub(super) fn color_indices(&self) -> VertexIndices<'a> {
273        let offset = match &self.xml.input {
274            Some(input) => match &input.color {
275                Some(color) => color.offset,
276                None => {
277                    if self.mesh.xml.mesh.vertices.id == input.vertex.source {
278                        if self.mesh.xml.mesh.vertices.input.color.is_some() {
279                            input.vertex.offset
280                        } else {
281                            return VertexIndices::none();
282                        }
283                    } else {
284                        // TODO: search other mesh's vertices
285                        todo!()
286                    }
287                }
288            },
289            None => return VertexIndices::none(),
290        };
291        VertexIndices {
292            remaining: self.vertex_indices_size(),
293            inner: self.vertex_indices_inner(offset),
294        }
295    }
296}
297
298pub(super) struct Positions<'a>(Option<(u32, slice::Chunks<'a, f32>)>);
299
300impl Iterator for Positions<'_> {
301    type Item = Vec3;
302
303    fn next(&mut self) -> Option<Self::Item> {
304        let (count, iter) = self.0.as_mut()?;
305        let v = iter.next().unwrap();
306        *count -= 1;
307        if *count == 0 {
308            self.0 = None;
309        }
310        Some([v[0], v[1], v[2]])
311    }
312
313    fn size_hint(&self) -> (usize, Option<usize>) {
314        match &self.0 {
315            Some((_, iter)) => iter.size_hint(),
316            None => (0, Some(0)),
317        }
318    }
319}
320
321impl ExactSizeIterator for Positions<'_> {}
322impl FusedIterator for Positions<'_> {}
323
324pub(super) type Normals<'a> = Positions<'a>;
325pub(super) type Colors<'a> = Positions<'a>;
326
327pub(super) struct Texcoords<'a>(Option<TexcoordsInner<'a>>);
328
329struct TexcoordsInner<'a> {
330    iter: slice::Chunks<'a, f32>,
331}
332
333impl Iterator for Texcoords<'_> {
334    type Item = Vec2;
335
336    fn next(&mut self) -> Option<Self::Item> {
337        let inner = self.0.as_mut()?;
338        match inner.iter.next() {
339            Some(v) => Some([v[0], v[1]]),
340            None => {
341                self.0 = None;
342                None
343            }
344        }
345    }
346
347    fn size_hint(&self) -> (usize, Option<usize>) {
348        match &self.0 {
349            Some(inner) => inner.iter.size_hint(),
350            None => (0, Some(0)),
351        }
352    }
353}
354
355impl ExactSizeIterator for Texcoords<'_> {}
356impl FusedIterator for Texcoords<'_> {}
357
358pub(super) struct VertexIndices<'a> {
359    remaining: u32,
360    inner: IndicesInner<'a>,
361}
362
363enum IndicesInner<'a> {
364    Polylist {
365        offset: u32,
366        indices: &'a [u32],
367        stride: u32,
368        vcount: slice::Iter<'a, u32>,
369        index: usize,
370        range: Option<Range<u32>>,
371    },
372    Triangles {
373        offset: u32,
374        indices: slice::Chunks<'a, u32>,
375    },
376    TriStrips {
377        offset: u32,
378        indices: &'a [u32],
379        stride: u32,
380        vcount: slice::Iter<'a, u32>,
381        index: usize,
382        range: Option<Range<u32>>,
383    },
384    Skip,
385    None,
386}
387
388impl VertexIndices<'_> {
389    const fn none() -> Self {
390        Self {
391            remaining: 0,
392            inner: IndicesInner::None,
393        }
394    }
395}
396
397impl Iterator for VertexIndices<'_> {
398    type Item = Face;
399
400    fn next(&mut self) -> Option<Self::Item> {
401        if self.remaining == 0 {
402            return None;
403        }
404        self.remaining -= 1;
405
406        match &mut self.inner {
407            IndicesInner::Polylist {
408                offset,
409                indices,
410                stride,
411                index,
412                vcount,
413                range,
414            }
415            | IndicesInner::TriStrips {
416                offset,
417                indices,
418                stride,
419                index,
420                vcount,
421                range,
422            } => {
423                let offset = *offset as usize;
424                let stride = *stride as usize;
425                if let Some(r) = range {
426                    if let Some(k) = r.next() {
427                        let x = *index + offset;
428                        let y = *index + offset + stride * k as usize;
429                        let z = *index + offset + stride * (k as usize + 1);
430                        let value = [indices[x], indices[y], indices[z]];
431                        // NOTE: Do *not* increment index until range ends.
432                        return Some(value);
433                    }
434                    let vc = r.end + 1;
435                    *index += stride * vc as usize;
436                    *range = None;
437                }
438                let vc = *vcount.next()?;
439                match vc {
440                    3 => {
441                        let x = *index + offset;
442                        let y = *index + offset + stride;
443                        let z = *index + offset + stride * 2;
444                        let value = [indices[x], indices[y], indices[z]];
445                        *index += stride * vc as usize;
446                        Some(value)
447                    }
448                    1..=2 => self.next(),
449                    0 => unreachable!(),
450                    _ => {
451                        let mut ri = 1..vc - 1;
452                        let k = ri.next().unwrap();
453                        let x = *index + offset;
454                        let y = *index + offset + stride * k as usize;
455                        let z = *index + offset + stride * (k as usize + 1);
456                        let value = [indices[x], indices[y], indices[z]];
457                        // Set range for next call.
458                        // NOTE: Do *not* increment index until range ends.
459                        *range = Some(ri);
460                        Some(value)
461                    }
462                }
463            }
464            IndicesInner::Triangles { offset, indices } => {
465                let indices1 = indices.next().unwrap();
466                let indices2 = indices.next().unwrap();
467                let indices3 = indices.next().unwrap();
468                Some([
469                    indices1[*offset as usize],
470                    indices2[*offset as usize],
471                    indices3[*offset as usize],
472                ])
473            }
474            IndicesInner::Skip => self.next(),
475            IndicesInner::None => unreachable!(),
476        }
477    }
478
479    fn size_hint(&self) -> (usize, Option<usize>) {
480        (self.remaining as usize, Some(self.remaining as usize))
481    }
482}
483
484impl ExactSizeIterator for VertexIndices<'_> {}
485impl FusedIterator for VertexIndices<'_> {}