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 if acc.stride < 3 || acc.params.len() < 3 || acc.params.iter().any(|p| p.ty != "float")
65 {
66 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!()
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!()
90 }
91 }
92 },
93 None => return Positions(None),
94 };
95 let data = self.mesh.doc[&acc.source].as_float().unwrap();
96 if acc.stride < 3 || acc.params.len() < 3 || acc.params.iter().any(|p| p.ty != "float") {
98 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!()
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 if acc.stride < 2 || acc.params.len() < 2 || acc.params.iter().any(|p| p.ty != "float") {
129 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!()
151 }
152 }
153 },
154 None => return Positions(None),
155 };
156 let data = self.mesh.doc[&acc.source].as_float().unwrap();
157 if acc.stride < 3 || acc.params.len() < 3 || acc.params.iter().any(|p| p.ty != "float") {
159 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!()
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!()
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!()
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 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 *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<'_> {}