easy_gltf/scene/model/
mod.rs1mod material;
2mod mode;
3mod vertex;
4
5use crate::utils::*;
6use cgmath::*;
7use std::sync::Arc;
8
9pub use material::*;
10pub use mode::*;
11pub use vertex::*;
12
13#[derive(Clone, Debug, Default)]
65pub struct Model {
66 #[cfg(feature = "names")]
67 pub(crate) mesh_name: Option<String>,
68 #[cfg(feature = "extras")]
69 pub(crate) mesh_extras: gltf::json::extras::Extras,
70 #[cfg(feature = "extras")]
71 pub(crate) primitive_extras: gltf::json::extras::Extras,
72
73 pub(crate) primitive_index: usize,
74 pub(crate) vertices: Vec<Vertex>,
75 pub(crate) indices: Option<Vec<u32>>,
76 pub(crate) mode: Mode,
77 pub(crate) material: Arc<Material>,
78 pub(crate) has_normals: bool,
79 pub(crate) has_tangents: bool,
80 pub(crate) has_tex_coords: bool,
81 #[cfg(feature = "vertex-color")]
82 pub(crate) has_colors: bool,
83}
84
85impl Model {
86 #[cfg(feature = "names")]
87 pub fn mesh_name(&self) -> Option<&str> {
93 self.mesh_name.as_deref()
94 }
95
96 pub fn primitive_index(&self) -> usize {
98 self.primitive_index
99 }
100
101 #[cfg(feature = "extras")]
102 pub fn mesh_extras(&self) -> &gltf::json::extras::Extras {
104 &self.mesh_extras
105 }
106
107 #[cfg(feature = "extras")]
108 pub fn primitive_extras(&self) -> &gltf::json::extras::Extras {
110 &self.primitive_extras
111 }
112
113 pub fn material(&self) -> Arc<Material> {
115 self.material.clone()
116 }
117
118 pub fn vertices(&self) -> &Vec<Vertex> {
124 &self.vertices
125 }
126
127 pub fn indices(&self) -> Option<&Vec<u32>> {
132 self.indices.as_ref()
133 }
134
135 pub fn mode(&self) -> Mode {
142 self.mode.clone()
143 }
144
145 pub fn triangles(&self) -> Result<Vec<Triangle>, BadMode> {
150 let mut triangles = vec![];
151 let indices = (0..self.vertices.len() as u32).collect();
152 let indices = self.indices().unwrap_or(&indices);
153
154 match self.mode {
155 Mode::Triangles => {
156 for i in (0..indices.len()).step_by(3) {
157 triangles.push([
158 self.vertices[indices[i] as usize],
159 self.vertices[indices[i + 1] as usize],
160 self.vertices[indices[i + 2] as usize],
161 ]);
162 }
163 }
164 Mode::TriangleStrip => {
165 for i in 0..(indices.len() - 2) {
166 triangles.push([
167 self.vertices[indices[i] as usize + i % 2],
168 self.vertices[indices[i + 1 - i % 2] as usize],
169 self.vertices[indices[i + 2] as usize],
170 ]);
171 }
172 }
173 Mode::TriangleFan => {
174 for i in 1..(indices.len() - 1) {
175 triangles.push([
176 self.vertices[indices[0] as usize],
177 self.vertices[indices[i] as usize],
178 self.vertices[indices[i + 1] as usize],
179 ]);
180 }
181 }
182 _ => return Err(BadMode { mode: self.mode() }),
183 }
184 Ok(triangles)
185 }
186
187 pub fn lines(&self) -> Result<Vec<Line>, BadMode> {
192 let mut lines = vec![];
193 let indices = (0..self.vertices.len() as u32).collect();
194 let indices = self.indices().unwrap_or(&indices);
195 match self.mode {
196 Mode::Lines => {
197 for i in (0..indices.len()).step_by(2) {
198 lines.push([
199 self.vertices[indices[i] as usize],
200 self.vertices[indices[i + 1] as usize],
201 ]);
202 }
203 }
204 Mode::LineStrip | Mode::LineLoop => {
205 for i in 0..(indices.len() - 1) {
206 lines.push([
207 self.vertices[indices[i] as usize],
208 self.vertices[indices[i + 1] as usize],
209 ]);
210 }
211 }
212 _ => return Err(BadMode { mode: self.mode() }),
213 }
214 if self.mode == Mode::LineLoop {
215 lines.push([
216 self.vertices[indices[0] as usize],
217 self.vertices[indices[indices.len() - 1] as usize],
218 ]);
219 }
220
221 Ok(lines)
222 }
223
224 pub fn points(&self) -> Result<&Vec<Vertex>, BadMode> {
228 match self.mode {
229 Mode::Points => Ok(&self.vertices),
230 _ => Err(BadMode { mode: self.mode() }),
231 }
232 }
233
234 pub fn has_normals(&self) -> bool {
239 self.has_normals
240 }
241
242 pub fn has_tangents(&self) -> bool {
247 self.has_tangents
248 }
249
250 pub fn has_tex_coords(&self) -> bool {
255 self.has_tex_coords
256 }
257
258 #[cfg(feature = "vertex-color")]
264 pub fn has_colors(&self) -> bool {
265 self.has_colors
266 }
267
268 fn apply_transform_position(pos: [f32; 3], transform: &Matrix4<f32>) -> Vector3<f32> {
269 let pos = Vector4::new(pos[0], pos[1], pos[2], 1.);
270 let res = transform * pos;
271 Vector3::new(res.x / res.w, res.y / res.w, res.z / res.w)
272 }
273
274 fn apply_transform_vector(vec: [f32; 3], transform: &Matrix4<f32>) -> Vector3<f32> {
275 let vec = Vector4::new(vec[0], vec[1], vec[2], 0.);
276 (transform * vec).truncate()
277 }
278
279 fn apply_transform_tangent(tangent: [f32; 4], transform: &Matrix4<f32>) -> Vector4<f32> {
280 let tang = Vector4::new(tangent[0], tangent[1], tangent[2], 0.);
281 let mut tang = transform * tang;
282 tang[3] = tangent[3];
283 tang
284 }
285
286 pub(crate) fn load(
287 mesh: &gltf::Mesh,
288 primitive_index: usize,
289 primitive: gltf::Primitive,
290 transform: &Matrix4<f32>,
291 data: &mut GltfData,
292 ) -> Self {
293 #[cfg(not(feature = "names"))]
294 {
295 let _ = mesh;
296 }
297
298 let buffers = &data.buffers;
299 let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
300 let indices = reader
301 .read_indices()
302 .map(|indices| indices.into_u32().collect());
303
304 let mut vertices: Vec<_> = reader
306 .read_positions()
307 .unwrap_or_else(|| panic!("The model primitive doesn't contain positions"))
308 .map(|pos| Vertex {
309 position: Self::apply_transform_position(pos, transform),
310 ..Default::default()
311 })
312 .collect();
313
314 let has_normals = if let Some(normals) = reader.read_normals() {
316 for (i, normal) in normals.enumerate() {
317 vertices[i].normal = Self::apply_transform_vector(normal, transform).normalize();
318 }
319 true
320 } else {
321 false
322 };
323
324 let has_tangents = if let Some(tangents) = reader.read_tangents() {
326 for (i, tangent) in tangents.enumerate() {
327 let tangent = Self::apply_transform_tangent(tangent, transform);
328 vertices[i].tangent = tangent.truncate().normalize().extend(tangent.w);
329 }
330 true
331 } else {
332 false
333 };
334
335 let has_tex_coords = if let Some(tex_coords) = reader.read_tex_coords(0) {
337 for (i, tex_coords) in tex_coords.into_f32().enumerate() {
338 vertices[i].tex_coords = Vector2::from(tex_coords);
339 }
340 true
341 } else {
342 false
343 };
344
345 #[cfg(feature = "vertex-color")]
347 let has_colors = if let Some(colors) = reader.read_colors(0) {
348 for (i, color) in colors.into_rgba_u16().enumerate() {
349 vertices[i].color = Vector4::from(color);
350 }
351 true
352 } else {
353 false
354 };
355
356 Model {
357 #[cfg(feature = "names")]
358 mesh_name: mesh.name().map(String::from),
359 #[cfg(feature = "extras")]
360 mesh_extras: mesh.extras().clone(),
361 #[cfg(feature = "extras")]
362 primitive_extras: primitive.extras().clone(),
363 primitive_index,
364 vertices,
365 indices,
366 material: Material::load(primitive.material(), data),
367 mode: primitive.mode().into(),
368 has_normals,
369 has_tangents,
370 has_tex_coords,
371 #[cfg(feature = "vertex-color")]
372 has_colors,
373 }
374 }
375}