easy_gltf/scene/model/
mod.rs

1mod 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/// Geometry to be rendered with the given material.
14///
15/// # Examples
16///
17/// ### Classic rendering
18///
19/// In most cases you want to use `triangles()`, `lines()` and `points()`
20/// to get the geometry of the model.
21///
22/// ```
23/// # use easy_gltf::*;
24/// # use easy_gltf::model::Mode;
25/// # let model = Model::default();
26/// match model.mode() {
27///   Mode::Triangles | Mode::TriangleFan | Mode::TriangleStrip => {
28///     let triangles = model.triangles().unwrap();
29///     // Render triangles...
30///   },
31///   Mode::Lines | Mode::LineLoop | Mode::LineStrip => {
32///     let lines = model.lines().unwrap();
33///     // Render lines...
34///   }
35///   Mode::Points => {
36///     let points = model.points().unwrap();
37///     // Render points...
38///   }
39/// }
40/// ```
41///
42/// ### OpenGL style rendering
43///
44/// You will need the vertices and the indices if existing.
45///
46/// ```
47/// # use easy_gltf::*;
48/// # use easy_gltf::model::Mode;
49/// # let model = Model::default();
50/// let vertices = model. vertices();
51/// let indices = model.indices();
52/// match model.mode() {
53///   Mode::Triangles => {
54///     if let Some(indices) = indices.as_ref() {
55///       // glDrawElements(GL_TRIANGLES, indices.len(), GL_UNSIGNED_INT, 0);
56///     } else {
57///       // glDrawArrays(GL_TRIANGLES, 0, vertices.len());
58///     }
59///   },
60///   // ...
61/// # _ => unimplemented!(),
62/// }
63/// ```
64#[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    /// Mesh name. Requires the `names` feature.
88    ///
89    /// A `Model` in easy-gltf represents a primitive in gltf, so if a mesh has multiple primitives, you will
90    /// get multiple `Model`s with the same name. You can use `primitive_index` to get which primitive the `Model`
91    /// corresponds to.
92    pub fn mesh_name(&self) -> Option<&str> {
93        self.mesh_name.as_deref()
94    }
95
96    /// Index of the Primitive of the Mesh that this `Model` corresponds to.
97    pub fn primitive_index(&self) -> usize {
98        self.primitive_index
99    }
100
101    #[cfg(feature = "extras")]
102    /// Mesh extra data. Requires the `extras` feature.
103    pub fn mesh_extras(&self) -> &gltf::json::extras::Extras {
104        &self.mesh_extras
105    }
106
107    #[cfg(feature = "extras")]
108    /// Primitive extra data. Requires the `extras` feature.
109    pub fn primitive_extras(&self) -> &gltf::json::extras::Extras {
110        &self.primitive_extras
111    }
112
113    /// Material to apply to the whole model.
114    pub fn material(&self) -> Arc<Material> {
115        self.material.clone()
116    }
117
118    /// List of raw `vertices` of the model. You might have to use the `indices`
119    /// to render the model.
120    ///
121    /// **Note**: If you're not rendering with **OpenGL** you probably want to use
122    /// `triangles()`, `lines()` or `points()` instead.
123    pub fn vertices(&self) -> &Vec<Vertex> {
124        &self.vertices
125    }
126
127    /// Potential list of `indices` to render the model using raw `vertices`.
128    ///
129    /// **Note**: If you're **not** rendering with **OpenGL** you probably want to use
130    /// `triangles()`, `lines()` or `points()` instead.
131    pub fn indices(&self) -> Option<&Vec<u32>> {
132        self.indices.as_ref()
133    }
134
135    /// The type of primitive to render.
136    /// You have to check the `mode` to render the model correctly.
137    ///
138    /// Then you can either use:
139    /// * `vertices()` and `indices()` to arrange the data yourself (useful for **OpenGL**).
140    /// * `triangles()` or `lines()` or `points()` according to the returned mode.
141    pub fn mode(&self) -> Mode {
142        self.mode.clone()
143    }
144
145    /// List of triangles ready to be rendered.
146    ///
147    /// **Note**: This function will return an error if the mode isn't `Triangles`, `TriangleFan`
148    /// or `TriangleStrip`.
149    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    /// List of lines ready to be rendered.
188    ///
189    /// **Note**: This function will return an error if the mode isn't `Lines`, `LineLoop`
190    /// or `LineStrip`.
191    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    /// List of points ready to be renderer.
225    ///
226    /// **Note**: This function will return an error if the mode isn't `Points`.
227    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    /// Indicate if the vertices contains normal information.
235    ///
236    /// **Note**: If this function return `false` all vertices has a normal field
237    /// initialized to `zero`.
238    pub fn has_normals(&self) -> bool {
239        self.has_normals
240    }
241
242    /// Indicate if the vertices contains tangents information.
243    ///
244    /// **Note**: If this function return `false` all vertices has a tangent field
245    /// initialized to `zero`.
246    pub fn has_tangents(&self) -> bool {
247        self.has_tangents
248    }
249
250    /// Indicate if the vertices contains texture coordinates information.
251    ///
252    /// **Note**: If this function return `false` all vertices has a tex_coord field
253    /// initialized to `zero`.
254    pub fn has_tex_coords(&self) -> bool {
255        self.has_tex_coords
256    }
257
258    /// Indicate if the vertices contains color information.
259    /// Requires the `vertex-color` feature.
260    ///
261    /// **Note**: If this function return `false` all vertices has a color field
262    /// initialized to `1`.
263    #[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        // Init vertices with the position
305        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        // Fill normals
315        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        // Fill tangents
325        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        // Texture coordinates
336        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        // Colors
346        #[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}