Skip to main content

fyrox_impl/scene/mesh/
vertex.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Contains most common vertex formats and their layouts.
22
23use crate::{
24    core::algebra::{Vector2, Vector3, Vector4},
25    scene::mesh::buffer::{
26        VertexAttributeDataType, VertexAttributeDescriptor, VertexAttributeUsage, VertexTrait,
27    },
28};
29use bytemuck::{Pod, Zeroable};
30use std::hash::{Hash, Hasher};
31
32/// A vertex for static meshes.
33#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
34#[repr(C)] // OpenGL expects this structure packed as in C
35pub struct StaticVertex {
36    /// Position of vertex in local coordinates.
37    pub position: Vector3<f32>,
38    /// Texture coordinates.
39    pub tex_coord: Vector2<f32>,
40    /// Normal in local coordinates.
41    pub normal: Vector3<f32>,
42    /// Tangent vector in local coordinates.
43    pub tangent: Vector4<f32>,
44}
45
46impl StaticVertex {
47    /// Creates new vertex from given position and texture coordinates.
48    pub fn from_pos_uv(position: Vector3<f32>, tex_coord: Vector2<f32>) -> Self {
49        Self {
50            position,
51            tex_coord,
52            normal: Vector3::new(0.0, 1.0, 0.0),
53            tangent: Vector4::default(),
54        }
55    }
56
57    /// Creates new vertex from given position and texture coordinates.
58    pub fn from_pos_uv_normal(
59        position: Vector3<f32>,
60        tex_coord: Vector2<f32>,
61        normal: Vector3<f32>,
62    ) -> Self {
63        Self {
64            position,
65            tex_coord,
66            normal,
67            tangent: Vector4::default(),
68        }
69    }
70}
71
72impl VertexTrait for StaticVertex {
73    fn layout() -> &'static [VertexAttributeDescriptor] {
74        static LAYOUT: [VertexAttributeDescriptor; 4] = [
75            VertexAttributeDescriptor {
76                usage: VertexAttributeUsage::Position,
77                data_type: VertexAttributeDataType::F32,
78                size: 3,
79                divisor: 0,
80                shader_location: 0,
81                normalized: false,
82            },
83            VertexAttributeDescriptor {
84                usage: VertexAttributeUsage::TexCoord0,
85                data_type: VertexAttributeDataType::F32,
86                size: 2,
87                divisor: 0,
88                shader_location: 1,
89                normalized: false,
90            },
91            VertexAttributeDescriptor {
92                usage: VertexAttributeUsage::Normal,
93                data_type: VertexAttributeDataType::F32,
94                size: 3,
95                divisor: 0,
96                shader_location: 2,
97                normalized: false,
98            },
99            VertexAttributeDescriptor {
100                usage: VertexAttributeUsage::Tangent,
101                data_type: VertexAttributeDataType::F32,
102                size: 4,
103                divisor: 0,
104                shader_location: 3,
105                normalized: false,
106            },
107        ];
108        &LAYOUT
109    }
110}
111
112impl PartialEq for StaticVertex {
113    fn eq(&self, other: &Self) -> bool {
114        self.position == other.position
115            && self.tex_coord == other.tex_coord
116            && self.normal == other.normal
117            && self.tangent == other.tangent
118    }
119}
120
121// This is safe because Vertex is tightly packed struct with C representation
122// there is no padding bytes which may contain garbage data. This is strictly
123// required because vertices will be directly passed on GPU.
124impl Hash for StaticVertex {
125    fn hash<H: Hasher>(&self, state: &mut H) {
126        #[allow(unsafe_code)]
127        unsafe {
128            let bytes = self as *const Self as *const u8;
129            state.write(std::slice::from_raw_parts(
130                bytes,
131                std::mem::size_of::<Self>(),
132            ))
133        }
134    }
135}
136
137/// A vertex for animated (via skinning) mesh.
138#[derive(Copy, Clone, Debug, Default)]
139#[repr(C)] // OpenGL expects this structure packed as in C
140pub struct AnimatedVertex {
141    /// Position of vertex in local coordinates.
142    pub position: Vector3<f32>,
143    /// Texture coordinates.
144    pub tex_coord: Vector2<f32>,
145    /// Normal in local coordinates.
146    pub normal: Vector3<f32>,
147    /// Tangent vector in local coordinates.
148    pub tangent: Vector4<f32>,
149    /// Array of bone weights. Unused bones will have 0.0 weight so they won't
150    /// impact the shape of mesh.
151    pub bone_weights: [f32; 4],
152    /// Array of bone indices. It has indices of bones in array of bones of a
153    /// surface.
154    pub bone_indices: [u8; 4],
155}
156
157impl VertexTrait for AnimatedVertex {
158    fn layout() -> &'static [VertexAttributeDescriptor] {
159        &[
160            VertexAttributeDescriptor {
161                usage: VertexAttributeUsage::Position,
162                data_type: VertexAttributeDataType::F32,
163                size: 3,
164                divisor: 0,
165                shader_location: 0,
166                normalized: false,
167            },
168            VertexAttributeDescriptor {
169                usage: VertexAttributeUsage::TexCoord0,
170                data_type: VertexAttributeDataType::F32,
171                size: 2,
172                divisor: 0,
173                shader_location: 1,
174                normalized: false,
175            },
176            VertexAttributeDescriptor {
177                usage: VertexAttributeUsage::Normal,
178                data_type: VertexAttributeDataType::F32,
179                size: 3,
180                divisor: 0,
181                shader_location: 2,
182                normalized: false,
183            },
184            VertexAttributeDescriptor {
185                usage: VertexAttributeUsage::Tangent,
186                data_type: VertexAttributeDataType::F32,
187                size: 4,
188                divisor: 0,
189                shader_location: 3,
190                normalized: false,
191            },
192            VertexAttributeDescriptor {
193                usage: VertexAttributeUsage::BoneWeight,
194                data_type: VertexAttributeDataType::F32,
195                size: 4,
196                divisor: 0,
197                shader_location: 4,
198                normalized: false,
199            },
200            VertexAttributeDescriptor {
201                usage: VertexAttributeUsage::BoneIndices,
202                data_type: VertexAttributeDataType::U8,
203                size: 4,
204                divisor: 0,
205                shader_location: 5,
206                normalized: false,
207            },
208        ]
209    }
210}
211
212impl PartialEq for AnimatedVertex {
213    fn eq(&self, other: &Self) -> bool {
214        self.position == other.position
215            && self.tex_coord == other.tex_coord
216            && self.normal == other.normal
217            && self.tangent == other.tangent
218            && self.bone_weights == other.bone_weights
219            && self.bone_indices == other.bone_indices
220    }
221}
222
223// This is safe because Vertex is tightly packed struct with C representation
224// there is no padding bytes which may contain garbage data. This is strictly
225// required because vertices will be directly passed on GPU.
226impl Hash for AnimatedVertex {
227    fn hash<H: Hasher>(&self, state: &mut H) {
228        #[allow(unsafe_code)]
229        unsafe {
230            let bytes = self as *const Self as *const u8;
231            state.write(std::slice::from_raw_parts(
232                bytes,
233                std::mem::size_of::<Self>(),
234            ))
235        }
236    }
237}
238
239/// Simple vertex with position.
240#[derive(Copy, Clone, Debug, Default)]
241#[repr(C)] // OpenGL expects this structure packed as in C
242pub struct SimpleVertex {
243    /// Position of vertex in local coordinates.
244    pub position: Vector3<f32>,
245}
246
247impl SimpleVertex {
248    /// Creates a new simple vertex using given coordinates.
249    pub fn new(x: f32, y: f32, z: f32) -> Self {
250        Self {
251            position: Vector3::new(x, y, z),
252        }
253    }
254}
255
256impl VertexTrait for SimpleVertex {
257    fn layout() -> &'static [VertexAttributeDescriptor] {
258        &[VertexAttributeDescriptor {
259            usage: VertexAttributeUsage::Position,
260            data_type: VertexAttributeDataType::F32,
261            size: 3,
262            divisor: 0,
263            shader_location: 0,
264            normalized: false,
265        }]
266    }
267}
268
269impl PartialEq for SimpleVertex {
270    fn eq(&self, other: &Self) -> bool {
271        self.position == other.position
272    }
273}
274
275// This is safe because Vertex is tightly packed struct with C representation
276// there is no padding bytes which may contain garbage data. This is strictly
277// required because vertices will be directly passed on GPU.
278impl Hash for SimpleVertex {
279    fn hash<H: Hasher>(&self, state: &mut H) {
280        #[allow(unsafe_code)]
281        unsafe {
282            let bytes = self as *const Self as *const u8;
283            state.write(std::slice::from_raw_parts(
284                bytes,
285                std::mem::size_of::<Self>(),
286            ))
287        }
288    }
289}