1use crate::models::{Primitive, Mesh};
32use std::collections::HashMap;
33
34pub struct MeshBuilder {
36 builder: Option<Box<dyn FnMut(&[f32], &[u16], Option<&[f32]>, Option<Vec<Vec<f32>>>, Option<usize>) -> Primitive>>,
37 positions: Vec<f32>,
38 indices: Vec<u16>,
39 normals: Option<Vec<f32>>,
40 texcoords: Option<Vec<Vec<f32>>>,
41 material: Option<usize>,
42 name: Option<String>,
43}
44
45impl MeshBuilder {
46 pub fn new(name: Option<String>) -> Self {
48 Self {
49 builder: None,
50 positions: Vec::new(),
51 indices: Vec::new(),
52 normals: None,
53 texcoords: None,
54 material: None,
55 name,
56 }
57 }
58
59 pub fn with_positions(mut self, positions: Vec<f32>) -> Self {
61 self.positions = positions;
62 self
63 }
64
65 pub fn with_indices(mut self, indices: Vec<u16>) -> Self {
67 self.indices = indices;
68 self
69 }
70
71 pub fn with_normals(mut self, normals: Vec<f32>) -> Self {
73 self.normals = Some(normals);
74 self
75 }
76
77 pub fn with_texcoords(mut self, texcoords: Vec<f32>) -> Self {
79 let mut texcoord_sets = Vec::new();
80 texcoord_sets.push(texcoords);
81 self.texcoords = Some(texcoord_sets);
82 self
83 }
84
85 pub fn with_multiple_texcoords(mut self, texcoord_sets: Vec<Vec<f32>>) -> Self {
87 self.texcoords = Some(texcoord_sets);
88 self
89 }
90
91 pub fn with_material(mut self, material: usize) -> Self {
93 self.material = Some(material);
94 self
95 }
96
97 pub fn with_primitive_builder(
99 mut self,
100 builder: Box<dyn FnMut(&[f32], &[u16], Option<&[f32]>, Option<Vec<Vec<f32>>>, Option<usize>) -> Primitive>,
101 ) -> Self {
102 self.builder = Some(builder);
103 self
104 }
105
106 pub fn build(self) -> Mesh {
108 let mut mesh = Mesh::default();
109 mesh.name = self.name;
110
111 let normals_ref = self.normals.as_deref();
112
113 if let Some(mut builder) = self.builder {
114 let primitive = builder(
115 &self.positions,
116 &self.indices,
117 normals_ref,
118 self.texcoords,
119 self.material,
120 );
121 mesh.primitives.push(primitive);
122 } else {
123 let attributes = HashMap::new();
125 let primitive = Primitive {
128 attributes,
129 indices: None, material: self.material,
131 mode: None, };
133
134 mesh.primitives.push(primitive);
135 }
136
137 mesh
138 }
139}
140
141pub fn calculate_bounds(positions: &[f32]) -> (Vec<f32>, Vec<f32>) {
143 if positions.is_empty() {
144 return (vec![], vec![]);
145 }
146
147 let components_per_vertex = 3;
149
150 let mut min = vec![f32::MAX; components_per_vertex];
151 let mut max = vec![f32::MIN; components_per_vertex];
152
153 for i in (0..positions.len()).step_by(components_per_vertex) {
154 for j in 0..components_per_vertex {
155 if i + j < positions.len() {
156 min[j] = min[j].min(positions[i + j]);
157 max[j] = max[j].max(positions[i + j]);
158 }
159 }
160 }
161
162 (min, max)
163}
164
165pub fn create_attribute_mapping(
167 position_accessor: usize,
168 normal_accessor: Option<usize>,
169 texcoord_accessors: Option<Vec<usize>>,
170) -> HashMap<String, usize> {
171 let mut attributes = HashMap::new();
172
173 attributes.insert("POSITION".to_string(), position_accessor);
175
176 if let Some(normal_index) = normal_accessor {
178 attributes.insert("NORMAL".to_string(), normal_index);
179 }
180
181 if let Some(texcoord_indices) = texcoord_accessors {
183 for (i, texcoord_index) in texcoord_indices.iter().enumerate() {
184 attributes.insert(format!("TEXCOORD_{}", i), *texcoord_index);
185 }
186 }
187
188 attributes
189}