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