1use crate::asset::core::math::TriangleDefinition;
22use crate::core::algebra::{Vector2, Vector3, Vector4};
23
24use crate::fxhash::FxHashMap;
25use crate::scene::mesh;
26use crate::scene::mesh::buffer::{
27 self, TriangleBuffer, ValidationError, VertexBuffer, VertexTrait,
28};
29use crate::scene::mesh::surface::{InputBlendShapeData, SurfaceData};
30use crate::scene::mesh::vertex::{AnimatedVertex, SimpleVertex, StaticVertex};
31use gltf::buffer::Buffer;
32use gltf::mesh::util::ReadJoints;
33use gltf::mesh::Mode;
34use gltf::mesh::Semantic;
35use gltf::Primitive;
36use half::f16;
37
38#[cfg(feature = "mesh_analysis")]
39use crate::{
40 core::math::Vector3Ext,
41 scene::mesh::buffer::{VertexAttributeUsage, VertexReadTrait},
42};
43
44use std::fmt::Display;
45use std::num::TryFromIntError;
46
47#[derive(Debug)]
49pub enum SurfaceDataError {
50 CountMismatch,
53 MissingPosition,
55 MissingNormal,
57 MissingTexCoords,
59 MissingBoneWeight,
61 MissingBoneIndex,
63 InvalidBoneIndex,
67 InvalidMode,
70 InvalidIndex,
74 Int(TryFromIntError),
76 InvalidVertexCount(GeometryType, u32),
81 Validation(ValidationError),
83 Fetch(buffer::VertexFetchError),
85}
86
87impl std::error::Error for SurfaceDataError {}
88
89impl Display for SurfaceDataError {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 SurfaceDataError::CountMismatch => f.write_str("Count mismatch"),
93 SurfaceDataError::MissingPosition => f.write_str("Missing position"),
94 SurfaceDataError::MissingNormal => f.write_str("Missing normal"),
95 SurfaceDataError::MissingTexCoords => f.write_str("Missing texcoords"),
96 SurfaceDataError::MissingBoneWeight => f.write_str("Missing bone weight"),
97 SurfaceDataError::MissingBoneIndex => f.write_str("Missing bone index"),
98 SurfaceDataError::InvalidBoneIndex => f.write_str("Invalid bone index"),
99 SurfaceDataError::InvalidMode => f.write_str("Invalid mode"),
100 SurfaceDataError::InvalidIndex => f.write_str("Invalid index"),
101 SurfaceDataError::Int(error) => Display::fmt(error, f),
102 SurfaceDataError::InvalidVertexCount(geometry_type, count) => {
103 write!(f, "Cannot have {count} vertices {geometry_type}.")
104 }
105 SurfaceDataError::Validation(error) => Display::fmt(error, f),
106 SurfaceDataError::Fetch(error) => Display::fmt(error, f),
107 }
108 }
109}
110
111impl From<ValidationError> for SurfaceDataError {
112 fn from(error: ValidationError) -> Self {
113 SurfaceDataError::Validation(error)
114 }
115}
116
117impl From<TryFromIntError> for SurfaceDataError {
118 fn from(error: TryFromIntError) -> Self {
119 SurfaceDataError::Int(error)
120 }
121}
122
123impl From<buffer::VertexFetchError> for SurfaceDataError {
124 fn from(error: buffer::VertexFetchError) -> Self {
125 SurfaceDataError::Fetch(error)
126 }
127}
128
129#[derive(Debug)]
130pub enum GeometryType {
131 Triangles,
132 TriangleStrip,
133 TriangleFan,
134}
135
136impl Display for GeometryType {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 match self {
139 GeometryType::Triangles => f.write_str("triangles"),
140 GeometryType::TriangleStrip => f.write_str("triangle strip"),
141 GeometryType::TriangleFan => f.write_str("triangle fan"),
142 }
143 }
144}
145
146#[derive(Debug, Default, Clone)]
147pub struct BlendShapeInfo {
148 pub name: String,
149 pub default_weight: f32,
150}
151
152#[derive(Debug, Default, Clone)]
153pub struct BlendShapeInfoContainer {
154 names: Vec<String>,
155 weights: Vec<f32>,
156}
157
158impl BlendShapeInfoContainer {
159 pub fn new(names: Vec<String>, weights: Vec<f32>) -> Self {
160 BlendShapeInfoContainer { names, weights }
161 }
162 pub fn get(&self, index: usize) -> BlendShapeInfo {
163 BlendShapeInfo {
164 name: self
165 .names
166 .get(index)
167 .cloned()
168 .unwrap_or_else(|| index.to_string()),
169 default_weight: self.weights.get(index).cloned().unwrap_or(0.0),
170 }
171 }
172}
173
174#[derive(Debug, Copy, Clone)]
175pub struct GeometryStatistics {
176 pub min_edge_length_squared: f32,
177 pub repeated_index_count: usize,
178}
179
180impl GeometryStatistics {
181 #[cfg(feature = "mesh_analysis")]
182 pub fn update_length(&mut self, len: f32) {
183 if len < self.min_edge_length_squared {
184 self.min_edge_length_squared = len;
185 }
186 }
187 pub fn min_edge_length(&self) -> f32 {
188 self.min_edge_length_squared.sqrt()
189 }
190}
191
192impl Default for GeometryStatistics {
193 fn default() -> Self {
194 GeometryStatistics {
195 min_edge_length_squared: f32::INFINITY,
196 repeated_index_count: 0,
197 }
198 }
199}
200
201type Result<T> = std::result::Result<T, SurfaceDataError>;
202const DEFAULT_TANGENT: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 0.0);
203
204#[derive(Debug)]
205enum IndexData {
206 Buffer(Vec<u32>),
207 Direct(u32),
208}
209
210impl IndexData {
211 fn get_tri(&self, a: u32, b: u32, c: u32) -> Result<[u32; 3]> {
212 Ok([self.get(a)?, self.get(b)?, self.get(c)?])
213 }
214 fn get(&self, source_index: u32) -> Result<u32> {
215 match self {
216 IndexData::Buffer(data) => Ok(*data
217 .get(usize::try_from(source_index)?)
218 .ok_or(SurfaceDataError::InvalidIndex)?),
219 IndexData::Direct(size) if source_index < *size => Ok(source_index),
220 _ => Err(SurfaceDataError::InvalidIndex),
221 }
222 }
223 fn len(&self) -> Result<u32> {
224 match self {
225 IndexData::Buffer(data) => Ok(u32::try_from(data.len())?),
226 IndexData::Direct(size) => Ok(*size),
227 }
228 }
229}
230
231pub fn build_surface_data(
232 primitive: &Primitive,
233 morph_info: &BlendShapeInfoContainer,
234 buffers: &[Vec<u8>],
235 #[allow(unused_variables)] stats: &mut GeometryStatistics,
236) -> Result<Option<SurfaceData>> {
237 match primitive.mode() {
238 Mode::Points => {
239 return Ok(None);
240 }
241 Mode::Lines => {
242 return Ok(None);
243 }
244 Mode::LineLoop => {
245 return Ok(None);
246 }
247 Mode::LineStrip => {
248 return Ok(None);
249 }
250 Mode::Triangles => (),
251 Mode::TriangleStrip => (),
252 Mode::TriangleFan => (),
253 }
254 let vs: VertexBuffer = build_vertex_data(primitive, buffers)?;
255 let tris: TriangleBuffer = build_triangle_data(primitive, vs.vertex_count(), buffers)?;
256 #[cfg(feature = "mesh_analysis")]
257 update_statistics(&vs, &tris, stats)?;
258 let morphs: Vec<InputBlendShapeData> = build_morph_data(primitive, morph_info, buffers)?;
259 let mut surf = if !morphs.is_empty() {
260 let shapes = mesh::surface::BlendShapesContainer::from_lists(&vs, morphs.as_slice());
261 let mut surf = SurfaceData::new(vs, tris);
262 surf.blend_shapes_container = Some(shapes);
263 surf
264 } else {
265 SurfaceData::new(vs, tris)
266 };
267 let has_tex = primitive.get(&Semantic::TexCoords(0)).is_some();
268 let has_norm = primitive.get(&Semantic::Normals).is_some();
269 let has_tang = primitive.get(&Semantic::Tangents).is_some();
270 if has_tex && !has_norm {
271 surf.calculate_normals()?;
272 surf.calculate_tangents()?;
273 } else if has_tex && has_norm && !has_tang {
274 surf.calculate_tangents()?;
275 }
276 Ok(Some(surf))
277}
278
279#[cfg(feature = "mesh_analysis")]
280fn update_statistics(
281 vs: &VertexBuffer,
282 tris: &TriangleBuffer,
283 stats: &mut GeometryStatistics,
284) -> Result<()> {
285 for tri in tris.iter() {
286 if tri[0] == tri[1] || tri[1] == tri[2] || tri[0] == tri[2] {
287 stats.repeated_index_count += 1;
288 }
289 stats.update_length(edge_length_squared(tri[0], tri[1], vs)?);
290 stats.update_length(edge_length_squared(tri[1], tri[2], vs)?);
291 stats.update_length(edge_length_squared(tri[0], tri[2], vs)?);
292 }
293 Ok(())
294}
295
296#[cfg(feature = "mesh_analysis")]
297fn edge_length_squared(a: u32, b: u32, vs: &VertexBuffer) -> Result<f32> {
298 let a = usize::try_from(a)?;
299 let b = usize::try_from(b)?;
300 let a = vs.get(a).ok_or(SurfaceDataError::InvalidIndex)?;
301 let b = vs.get(b).ok_or(SurfaceDataError::InvalidIndex)?;
302 let a = a.read_3_f32(VertexAttributeUsage::Position)?;
303 let b = b.read_3_f32(VertexAttributeUsage::Position)?;
304 Ok(a.sqr_distance(&b))
305}
306
307fn build_morph_data(
308 primitive: &Primitive,
309 morph_info: &BlendShapeInfoContainer,
310 buffers: &[Vec<u8>],
311) -> Result<Vec<InputBlendShapeData>> {
312 inner_build_morph_data(primitive, morph_info, buffers)
313}
314
315fn inner_build_morph_data(
316 primitive: &Primitive,
317 morph_info: &BlendShapeInfoContainer,
318 buffers: &[Vec<u8>],
319) -> Result<Vec<InputBlendShapeData>> {
320 let reader = primitive.reader(|buf: Buffer| buffers.get(buf.index()).map(Vec::as_slice));
321 let reader = reader.read_morph_targets();
322 let mut result: Vec<InputBlendShapeData> = Vec::new();
323 for (i, (pos, norm, tang)) in reader.enumerate() {
324 let info = morph_info.get(i);
325 let positions = if let Some(iter) = pos {
326 iter_to_map(iter)
327 } else {
328 FxHashMap::default()
329 };
330 let normals = if let Some(iter) = norm {
331 iter_to_map(iter)
332 } else {
333 FxHashMap::default()
334 };
335 let tangents = if let Some(iter) = tang {
336 iter_to_map(iter)
337 } else {
338 FxHashMap::default()
339 };
340 result.push(InputBlendShapeData {
341 default_weight: info.default_weight,
342 name: info.name,
343 positions,
344 normals,
345 tangents,
346 });
347 }
348 Ok(result)
349}
350
351fn iter_to_map<I>(iter: I) -> FxHashMap<u32, Vector3<f16>>
352where
353 I: Iterator<Item = [f32; 3]>,
354{
355 let mut map: FxHashMap<u32, Vector3<f16>> = FxHashMap::default();
356 for (i, v) in iter.enumerate() {
357 if v == [0.0; 3] {
358 continue;
359 }
360 if let Ok(index) = u32::try_from(i) {
361 let v: [f16; 3] = v.map(f16::from_f32);
362 map.insert(index, Vector3::<f16>::from(v));
363 }
364 }
365 map
366}
367
368fn build_vertex_data(primitive: &Primitive, buffers: &[Vec<u8>]) -> Result<VertexBuffer> {
369 build_vertex_data_with(primitive, |buf: Buffer| {
370 buffers.get(buf.index()).map(Vec::as_slice)
371 })
372}
373
374fn build_triangle_data(
375 primitive: &Primitive,
376 vertex_count: u32,
377 buffers: &[Vec<u8>],
378) -> Result<TriangleBuffer> {
379 let reader = primitive.reader(|buf: Buffer| buffers.get(buf.index()).map(Vec::as_slice));
380 let index_data = match reader.read_indices() {
381 Some(index_reader) => IndexData::Buffer(index_reader.into_u32().collect()),
382 None => IndexData::Direct(vertex_count),
383 };
384 let tris: Vec<TriangleDefinition> = (match primitive.mode() {
385 Mode::Points => Err(SurfaceDataError::InvalidMode),
386 Mode::Lines => Err(SurfaceDataError::InvalidMode),
387 Mode::LineLoop => Err(SurfaceDataError::InvalidMode),
388 Mode::LineStrip => Err(SurfaceDataError::InvalidMode),
389 Mode::Triangles => build_triangles(&index_data),
390 Mode::TriangleStrip => build_triangle_strip(&index_data),
391 Mode::TriangleFan => build_triangle_fan(&index_data),
392 })?;
393 Ok(TriangleBuffer::new(tris))
394}
395
396fn build_triangles(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
397 let vertex_count = data.len()?;
398 if vertex_count == 0 || vertex_count % 3 != 0 {
399 return Err(SurfaceDataError::InvalidVertexCount(
400 GeometryType::Triangles,
401 vertex_count,
402 ));
403 }
404 let tri_count: u32 = vertex_count / 3;
405 let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
406 for i in 0..tri_count {
407 let v: u32 = i * 3;
408 tris.push(TriangleDefinition(data.get_tri(v, v + 1, v + 2)?));
409 }
410 Ok(tris)
411}
412fn build_triangle_strip(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
413 let vertex_count = data.len()?;
414 if vertex_count < 3 {
415 return Err(SurfaceDataError::InvalidVertexCount(
416 GeometryType::TriangleStrip,
417 vertex_count,
418 ));
419 }
420 let tri_count: u32 = vertex_count - 2;
421 let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
422 for i in 0..tri_count {
423 let odd = i % 2;
424 tris.push(TriangleDefinition(data.get_tri(
425 i,
426 i + 1 + odd,
427 i + 2 - odd,
428 )?));
429 }
430 Ok(tris)
431}
432fn build_triangle_fan(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
433 let vertex_count = data.len()?;
434 if vertex_count < 3 {
435 return Err(SurfaceDataError::InvalidVertexCount(
436 GeometryType::TriangleFan,
437 vertex_count,
438 ));
439 }
440 let tri_count: u32 = vertex_count - 2;
441 let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
442 for i in 0..tri_count {
443 tris.push(TriangleDefinition(data.get_tri(i + 1, i + 2, 0)?));
444 }
445 Ok(tris)
446}
447
448fn build_vertex_data_with<'a, 's, F>(
449 primitive: &'a Primitive,
450 get_buffer_data: F,
451) -> Result<VertexBuffer>
452where
453 F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
454{
455 let reader = primitive.reader(get_buffer_data.clone());
456 if reader.read_weights(0).is_some() {
457 let vs: Vec<AnimatedVertex> = AnimatedVertex::convert(primitive, get_buffer_data)?;
458 Ok(VertexBuffer::new(vs.len(), vs)?)
459 } else if reader.read_normals().is_some() {
460 let vs: Vec<StaticVertex> = StaticVertex::convert(primitive, get_buffer_data)?;
461 Ok(VertexBuffer::new(vs.len(), vs)?)
462 } else {
463 let vs: Vec<SimpleVertex> = SimpleVertex::convert(primitive, get_buffer_data)?;
464 Ok(VertexBuffer::new(vs.len(), vs)?)
465 }
466}
467
468trait GltfVertexConvert: VertexTrait {
469 fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
470 where
471 F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>;
472}
473
474impl GltfVertexConvert for SimpleVertex {
475 fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
476 where
477 F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
478 {
479 let reader = primitive.reader(get_buffer_data);
480 if let Some(iter) = reader.read_positions() {
481 Ok(iter
482 .map(Vector3::from)
483 .map(|v| SimpleVertex { position: v })
484 .collect())
485 } else {
486 Err(SurfaceDataError::MissingPosition)
487 }
488 }
489}
490
491impl GltfVertexConvert for StaticVertex {
492 fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
493 where
494 F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
495 {
496 let reader = primitive.reader(get_buffer_data);
497 let pos_iter = reader
498 .read_positions()
499 .ok_or(SurfaceDataError::MissingPosition)?;
500 let mut norm_iter = reader
501 .read_normals()
502 .ok_or(SurfaceDataError::MissingNormal)?;
503 let mut tang_iter = reader.read_tangents();
504 let mut uv_iter = reader
505 .read_tex_coords(0)
506 .ok_or(SurfaceDataError::MissingTexCoords)?
507 .into_f32();
508 let mut result: Vec<StaticVertex> = Vec::with_capacity(pos_iter.len());
509 for pos in pos_iter {
510 let pos: Vector3<f32> = Vector3::from(pos);
511 let norm: Option<Vector3<f32>> = norm_iter.next().map(Vector3::from);
512 let uv: Option<Vector2<f32>> = uv_iter.next().map(Vector2::from);
513 let tang: Option<Vector4<f32>> = if let Some(iter) = tang_iter.as_mut() {
514 iter.next().map(Vector4::from)
515 } else {
516 Some(DEFAULT_TANGENT)
517 };
518 if let (Some(normal), Some(tex_coord), Some(tangent)) = (norm, uv, tang) {
519 result.push(StaticVertex {
520 position: pos,
521 normal,
522 tex_coord,
523 tangent,
524 });
525 } else {
526 return Err(SurfaceDataError::CountMismatch);
527 }
528 }
529 Ok(result)
530 }
531}
532
533impl GltfVertexConvert for AnimatedVertex {
534 fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
535 where
536 F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
537 {
538 let reader = primitive.reader(get_buffer_data);
539 let pos_iter = reader
540 .read_positions()
541 .ok_or(SurfaceDataError::MissingPosition)?;
542 let mut norm_iter = reader
543 .read_normals()
544 .ok_or(SurfaceDataError::MissingNormal)?;
545 let mut tang_iter = reader.read_tangents();
546 let mut uv_iter = reader
547 .read_tex_coords(0)
548 .ok_or(SurfaceDataError::MissingTexCoords)?
549 .into_f32();
550 let mut wgt_iter = reader
551 .read_weights(0)
552 .ok_or(SurfaceDataError::MissingBoneWeight)?
553 .into_f32();
554 let mut jnt_iter = reader
555 .read_joints(0)
556 .ok_or(SurfaceDataError::MissingBoneIndex)?;
557 let mut result: Vec<AnimatedVertex> = Vec::with_capacity(pos_iter.len());
558 for pos in pos_iter {
559 let pos: Vector3<f32> = Vector3::from(pos);
560 let norm: Option<Vector3<f32>> = norm_iter.next().map(Vector3::from);
561 let uv: Option<Vector2<f32>> = uv_iter.next().map(Vector2::from);
562 let bone_weights: Option<[f32; 4]> = wgt_iter.next();
563 let bone_indices: Option<[u8; 4]> = read_valid_index(&mut jnt_iter)?;
564 let tang: Option<Vector4<f32>> = if let Some(iter) = tang_iter.as_mut() {
565 iter.next().map(Vector4::from)
566 } else {
567 Some(DEFAULT_TANGENT)
568 };
569 if let (
570 Some(normal),
571 Some(tex_coord),
572 Some(tangent),
573 Some(bone_weights),
574 Some(bone_indices),
575 ) = (norm, uv, tang, bone_weights, bone_indices)
576 {
577 result.push(AnimatedVertex {
578 position: pos,
579 normal,
580 tex_coord,
581 tangent,
582 bone_weights,
583 bone_indices,
584 });
585 } else {
586 return Err(SurfaceDataError::CountMismatch);
587 }
588 }
589 Ok(result)
590 }
591}
592
593fn read_valid_index(reader: &mut ReadJoints) -> Result<Option<[u8; 4]>> {
594 match reader {
595 ReadJoints::U8(iter) => Ok(iter.next()),
596 ReadJoints::U16(iter) => {
597 if let Some(value) = iter.next() {
598 let mut result: [u8; 4] = [0; 4];
599 for (i, v) in value.iter().enumerate() {
600 result[i] = u8::try_from(*v).or(Err(SurfaceDataError::InvalidBoneIndex))?;
601 }
602 Ok(Some(result))
603 } else {
604 Ok(None)
605 }
606 }
607 }
608}