rend3_types/
lib.rs

1//! Type declarations for the rend3 3D rendering crate.
2//!
3//! This is reexported in the rend3 crate proper and includes all the "surface"
4//! api arguments.
5
6use glam::{Mat4, UVec2, Vec2, Vec3, Vec3A, Vec4};
7use std::{
8    fmt::Debug,
9    hash::Hash,
10    marker::PhantomData,
11    mem,
12    num::NonZeroU32,
13    sync::{Arc, Weak},
14};
15use thiserror::Error;
16
17/// Reexport of the glam version rend3 is using.
18pub use glam;
19
20/// Non-owning resource handle.
21///
22/// Not part of rend3's external interface, but needed to interface with rend3's
23/// internal datastructures if writing your own structures or render routines.
24pub struct RawResourceHandle<T> {
25    /// Underlying value of the handle.
26    pub idx: usize,
27    _phantom: PhantomData<T>,
28}
29
30// Need Debug/Copy/Clone impls that don't require T: Trait.
31impl<T> Debug for RawResourceHandle<T> {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        f.debug_struct("RawResourceHandle").field("idx", &self.idx).finish()
34    }
35}
36
37impl<T> Copy for RawResourceHandle<T> {}
38
39impl<T> Clone for RawResourceHandle<T> {
40    fn clone(&self) -> Self {
41        Self {
42            idx: self.idx,
43            _phantom: PhantomData,
44        }
45    }
46}
47
48impl<T> PartialEq for RawResourceHandle<T> {
49    fn eq(&self, other: &Self) -> bool {
50        self.idx == other.idx
51    }
52}
53
54impl<T> Eq for RawResourceHandle<T> {}
55
56/// Owning resource handle. Used as part of rend3's interface.
57pub struct ResourceHandle<T> {
58    refcount: Arc<()>,
59    idx: usize,
60    _phantom: PhantomData<T>,
61}
62
63impl<T> Debug for ResourceHandle<T> {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        f.debug_struct("ResourceHandle")
66            .field("refcount", &Arc::strong_count(&self.refcount))
67            .field("idx", &self.idx)
68            .finish()
69    }
70}
71
72impl<T> Clone for ResourceHandle<T> {
73    fn clone(&self) -> Self {
74        Self {
75            refcount: self.refcount.clone(),
76            idx: self.idx,
77            _phantom: self._phantom,
78        }
79    }
80}
81
82impl<T> PartialEq for ResourceHandle<T> {
83    fn eq(&self, other: &Self) -> bool {
84        self.idx == other.idx
85    }
86}
87
88impl<T> Eq for ResourceHandle<T> {}
89
90impl<T> Hash for ResourceHandle<T> {
91    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
92        self.idx.hash(state);
93    }
94}
95
96impl<T> ResourceHandle<T> {
97    /// Create a new resource handle from an index.
98    ///
99    /// Part of rend3's internal interface, use `Renderer::add_*` instead.
100    pub fn new(idx: usize) -> Self {
101        Self {
102            refcount: Arc::new(()),
103            idx,
104            _phantom: PhantomData,
105        }
106    }
107
108    /// Gets the equivalent raw handle for this owning handle.
109    ///
110    /// Part of rend3's internal interface for accessing internal resrouces
111    pub fn get_raw(&self) -> RawResourceHandle<T> {
112        RawResourceHandle {
113            idx: self.idx,
114            _phantom: PhantomData,
115        }
116    }
117
118    /// Get the weak refcount for this owned handle.
119    ///
120    /// Part of rend3's internal interface.
121    pub fn get_weak_refcount(&self) -> Weak<()> {
122        Arc::downgrade(&self.refcount)
123    }
124}
125
126#[macro_export]
127#[doc(hidden)]
128macro_rules! declare_handle {
129    ($($name:ident<$ty:ty>),*) => {$(
130        #[doc = concat!("Refcounted handle to a ", stringify!($ty) ,".")]
131        pub type $name = ResourceHandle<$ty>;
132    )*};
133}
134
135declare_handle!(
136    MeshHandle<Mesh>,
137    TextureHandle<Texture>,
138    MaterialHandle<MaterialTag>,
139    ObjectHandle<Object>,
140    DirectionalLightHandle<DirectionalLight>,
141    SkeletonHandle<Skeleton>
142);
143
144#[macro_export]
145#[doc(hidden)]
146macro_rules! declare_raw_handle {
147    ($($name:ident<$ty:ty>),*) => {$(
148        #[doc = concat!("Internal non-owning handle to a ", stringify!($ty) ,".")]
149        pub type $name = RawResourceHandle<$ty>;
150    )*};
151}
152
153declare_raw_handle!(
154    RawMeshHandle<Mesh>,
155    RawTextureHandle<Texture>,
156    RawMaterialHandle<MaterialTag>,
157    RawObjectHandle<Object>,
158    RawDirectionalLightHandle<DirectionalLight>,
159    RawSkeletonHandle<Skeleton>
160);
161
162macro_rules! changeable_struct {
163    ($(#[$outer:meta])* pub struct $name:ident <- $name_change:ident { $($(#[$inner:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)? } ) => {
164        $(#[$outer])*
165        #[derive(Debug, Clone)]
166        pub struct $name {
167            $(
168                $(#[$inner])* $field_vis $field_name : $field_type
169            ),*
170        }
171        impl $name {
172            pub fn update_from_changes(&mut self, change: $name_change) {
173                $(
174                    if let Some(inner) = change.$field_name {
175                        self.$field_name = inner;
176                    }
177                );*
178            }
179        }
180        #[doc = concat!("Describes a modification to a ", stringify!($name), ".")]
181        #[derive(Debug, Default, Clone)]
182        pub struct $name_change {
183            $(
184                $field_vis $field_name : Option<$field_type>
185            ),*
186        }
187    };
188}
189
190// WGPU REEXPORTS
191#[doc(inline)]
192pub use wgt::{Backend, Backends, Color, DeviceType, PresentMode, TextureFormat, TextureUsages};
193
194/// The maximum amount of vertices any one object can have.
195///
196/// The value allows for 8 bits of information packed in the high 8 bits of the
197/// index for object recombination.
198pub const MAX_VERTEX_COUNT: usize = 1 << 24;
199
200/// Identifies the semantic use of a vertex buffer.
201#[derive(Debug, Copy, Clone)]
202pub enum VertexBufferType {
203    Position,
204    Normal,
205    Tangent,
206    Uv0,
207    Uv1,
208    Colors,
209}
210
211/// Error returned from mesh validation.
212#[derive(Debug, Error)]
213pub enum MeshValidationError {
214    #[error("Mesh's {ty:?} buffer has {actual} vertices but the position buffer has {expected}")]
215    MismatchedVertexCount {
216        ty: VertexBufferType,
217        expected: usize,
218        actual: usize,
219    },
220    #[error("Mesh has {count} vertices when the vertex limit is {}", MAX_VERTEX_COUNT)]
221    ExceededMaxVertexCount { count: usize },
222    #[error("Mesh has {count} indices which is not a multiple of three. Meshes are always composed of triangles")]
223    IndexCountNotMultipleOfThree { count: usize },
224    #[error(
225        "Index at position {index} has the value {value} which is out of bounds for vertex buffers of {max} length"
226    )]
227    IndexOutOfBounds { index: usize, value: u32, max: usize },
228}
229
230/// Easy to use builder for a [`Mesh`] that deals with common operations for
231/// you.
232#[derive(Debug, Default)]
233pub struct MeshBuilder {
234    vertex_positions: Vec<Vec3>,
235    vertex_normals: Option<Vec<Vec3>>,
236    vertex_tangents: Option<Vec<Vec3>>,
237    vertex_uv0: Option<Vec<Vec2>>,
238    vertex_uv1: Option<Vec<Vec2>>,
239    vertex_colors: Option<Vec<[u8; 4]>>,
240    vertex_joint_indices: Option<Vec<[u16; 4]>>,
241    vertex_joint_weights: Option<Vec<Vec4>>,
242    vertex_count: usize,
243
244    indices: Option<Vec<u32>>,
245    without_validation: bool,
246
247    handedness: Handedness,
248    flip_winding_order: bool,
249    double_sided: bool,
250}
251impl MeshBuilder {
252    /// Create a new [`MeshBuilder`] with a given set of positions.
253    ///
254    /// All vertices must have positions.
255    pub fn new(vertex_positions: Vec<Vec3>, handedness: Handedness) -> Self {
256        Self {
257            vertex_count: vertex_positions.len(),
258            vertex_positions,
259            handedness,
260            ..Self::default()
261        }
262    }
263
264    /// Add vertex normals to the given mesh.
265    ///
266    /// # Panic
267    ///
268    /// Will panic if the length is different from the position buffer length.
269    pub fn with_vertex_normals(mut self, normals: Vec<Vec3>) -> Self {
270        self.vertex_normals = Some(normals);
271        self
272    }
273
274    /// Add vertex tangents to the given mesh.
275    ///
276    /// # Panic
277    ///
278    /// Will panic if the length is different from the position buffer length.
279    pub fn with_vertex_tangents(mut self, tangents: Vec<Vec3>) -> Self {
280        self.vertex_tangents = Some(tangents);
281        self
282    }
283
284    /// Add the first set of texture coordinates to the given mesh.
285    ///
286    /// # Panic
287    ///
288    /// Will panic if the length is different from the position buffer length.
289    pub fn with_vertex_uv0(mut self, uvs: Vec<Vec2>) -> Self {
290        self.vertex_uv0 = Some(uvs);
291        self
292    }
293
294    /// Add the second set of texture coordinates to the given mesh.
295    ///
296    /// # Panic
297    ///
298    /// Will panic if the length is different from the position buffer length.
299    pub fn with_vertex_uv1(mut self, uvs: Vec<Vec2>) -> Self {
300        self.vertex_uv1 = Some(uvs);
301        self
302    }
303
304    /// Add vertex colors to the given mesh.
305    ///
306    /// # Panic
307    ///
308    /// Will panic if the length is different from the position buffer length.
309    pub fn with_vertex_colors(mut self, colors: Vec<[u8; 4]>) -> Self {
310        self.vertex_colors = Some(colors);
311        self
312    }
313
314    /// Add vertex joint indices to the given mesh.
315    ///
316    /// # Panic
317    ///
318    /// Will panic if the length is different from the position buffer length.
319    pub fn with_vertex_joint_indices(mut self, joint_indices: Vec<[u16; 4]>) -> Self {
320        self.vertex_joint_indices = Some(joint_indices);
321        self
322    }
323
324    /// Add vertex joint weights to the given mesh.
325    ///
326    /// # Panic
327    ///
328    /// Will panic if the length is different from the position buffer length.
329    pub fn with_vertex_joint_weights(mut self, joint_weights: Vec<Vec4>) -> Self {
330        self.vertex_joint_weights = Some(joint_weights);
331        self
332    }
333
334    /// Add indices to the given mesh.
335    ///
336    /// # Panic
337    ///
338    /// Will panic if the length is zero.
339    pub fn with_indices(mut self, indices: Vec<u32>) -> Self {
340        self.indices = Some(indices);
341        self
342    }
343
344    /// Flip the winding order
345    ///
346    /// See [`Mesh::flip_winding_order`] for more information.
347    pub fn with_flip_winding_order(mut self) -> Self {
348        self.flip_winding_order = true;
349        self
350    }
351
352    /// Mark this mesh as needing to be double sided. This will duplicate all
353    /// faces with the opposite winding order. This acts as if backface culling
354    /// was disabled.
355    pub fn with_double_sided(mut self) -> Self {
356        self.double_sided = true;
357        self
358    }
359
360    /// Doesn't run validation on the mesh.
361    ///
362    /// # Safety
363    ///
364    /// This asserts the following are true about the mesh:
365    /// - All vertex arrays are the same length.
366    /// - There is a non-zero count of vertices.
367    /// - The count of vertices is less than [`MAX_VERTEX_COUNT`].
368    /// - All indexes are in bounds for the given vertex arrays.
369    /// - There is a non-zero count of indices.
370    /// - There is a multiple-of-three count of indices.
371    pub unsafe fn without_validation(mut self) -> Self {
372        self.without_validation = true;
373        self
374    }
375
376    /// Build a mesh, adding whatever components weren't provided.
377    ///
378    /// If normals weren't provided, they will be calculated. If mesh
379    /// is right handed, will be converted to left handed.
380    ///
381    /// All others will be filled with defaults.
382    pub fn build(self) -> Result<Mesh, MeshValidationError> {
383        let length = self.vertex_count;
384
385        let has_normals = self.vertex_normals.is_some();
386        let has_tangents = self.vertex_tangents.is_some();
387        let has_uvs = self.vertex_uv0.is_some();
388
389        let mut mesh = Mesh {
390            vertex_positions: self.vertex_positions,
391            vertex_normals: self.vertex_normals.unwrap_or_else(|| vec![Vec3::ZERO; length]),
392            vertex_tangents: self.vertex_tangents.unwrap_or_else(|| vec![Vec3::ZERO; length]),
393            vertex_uv0: self.vertex_uv0.unwrap_or_else(|| vec![Vec2::ZERO; length]),
394            vertex_uv1: self.vertex_uv1.unwrap_or_else(|| vec![Vec2::ZERO; length]),
395            vertex_colors: self.vertex_colors.unwrap_or_else(|| vec![[255; 4]; length]),
396            vertex_joint_indices: self.vertex_joint_indices.unwrap_or_else(|| vec![[0; 4]; length]),
397            vertex_joint_weights: self.vertex_joint_weights.unwrap_or_else(|| vec![Vec4::ZERO; length]),
398            indices: self.indices.unwrap_or_else(|| (0..length as u32).collect()),
399        };
400
401        if !self.without_validation {
402            mesh.validate()?;
403        }
404
405        // We need to flip winding order first, so the normals will be facing the right
406        // direction.
407        if self.flip_winding_order {
408            mesh.flip_winding_order();
409        }
410
411        if !has_normals {
412            // SAFETY: We've validated this mesh or had its validity unsafely asserted.
413            unsafe { mesh.calculate_normals(self.handedness, true) };
414        }
415
416        // Don't need to bother with tangents if there are no meaningful UVs
417        if !has_tangents && has_uvs {
418            // SAFETY: We've validated this mesh or had its validity unsafely asserted.
419            unsafe { mesh.calculate_tangents(true) };
420        }
421
422        Ok(mesh)
423    }
424}
425
426/// A mesh that may be used by many objects.
427///
428/// Meshes are in Structure of Array format and must have all the vertex_*
429/// arrays be the same length. This condition can be checked with the
430/// [`Mesh::validate`] function.
431///
432/// These can be annoying to construct, so use the [`MeshBuilder`] to make it
433/// easier.
434#[derive(Debug)]
435pub struct Mesh {
436    pub vertex_positions: Vec<Vec3>,
437    pub vertex_normals: Vec<Vec3>,
438    pub vertex_tangents: Vec<Vec3>,
439    pub vertex_uv0: Vec<Vec2>,
440    pub vertex_uv1: Vec<Vec2>,
441    pub vertex_colors: Vec<[u8; 4]>,
442    pub vertex_joint_indices: Vec<[u16; 4]>,
443    pub vertex_joint_weights: Vec<Vec4>,
444
445    pub indices: Vec<u32>,
446}
447
448impl Clone for Mesh {
449    fn clone(&self) -> Self {
450        Self {
451            vertex_positions: self.vertex_positions.clone(),
452            vertex_normals: self.vertex_normals.clone(),
453            vertex_tangents: self.vertex_tangents.clone(),
454            vertex_uv0: self.vertex_uv0.clone(),
455            vertex_uv1: self.vertex_uv1.clone(),
456            vertex_colors: self.vertex_colors.clone(),
457            vertex_joint_indices: self.vertex_joint_indices.clone(),
458            vertex_joint_weights: self.vertex_joint_weights.clone(),
459            indices: self.indices.clone(),
460        }
461    }
462}
463
464impl Mesh {
465    /// Validates that all vertex attributes have the same length.
466    pub fn validate(&self) -> Result<(), MeshValidationError> {
467        let position_length = self.vertex_positions.len();
468        let indices_length = self.indices.len();
469
470        if position_length > MAX_VERTEX_COUNT {
471            return Err(MeshValidationError::ExceededMaxVertexCount { count: position_length });
472        }
473
474        let first_different_length = [
475            (self.vertex_normals.len(), VertexBufferType::Normal),
476            (self.vertex_tangents.len(), VertexBufferType::Tangent),
477            (self.vertex_uv0.len(), VertexBufferType::Uv0),
478            (self.vertex_uv1.len(), VertexBufferType::Uv1),
479            (self.vertex_colors.len(), VertexBufferType::Colors),
480        ]
481        .iter()
482        .find_map(|&(len, ty)| if len != position_length { Some((len, ty)) } else { None });
483
484        if let Some((len, ty)) = first_different_length {
485            return Err(MeshValidationError::MismatchedVertexCount {
486                ty,
487                actual: len,
488                expected: position_length,
489            });
490        }
491
492        if indices_length % 3 != 0 {
493            return Err(MeshValidationError::IndexCountNotMultipleOfThree { count: indices_length });
494        }
495
496        let first_oob_index = self.indices.iter().enumerate().find_map(|(idx, &i)| {
497            if (i as usize) >= position_length {
498                Some((idx, i))
499            } else {
500                None
501            }
502        });
503
504        if let Some((index, value)) = first_oob_index {
505            return Err(MeshValidationError::IndexOutOfBounds {
506                index,
507                value,
508                max: position_length,
509            });
510        }
511
512        Ok(())
513    }
514
515    /// Calculate normals for the given mesh, assuming smooth shading and
516    /// per-vertex normals.
517    ///
518    /// It is sound to call this function with the wrong handedness, it will
519    /// just result in flipped normals.
520    ///
521    /// If zeroed is true, the normals will not be zeroed before hand. If this
522    /// is falsely set, it is sound, just returns incorrect results.
523    ///
524    /// # Safety
525    ///
526    /// The following must be true:
527    /// - Normals and positions must be the same length.
528    /// - All indices must be in-bounds for the buffers.
529    ///
530    /// If a mesh has passed a call to validate, it is sound to call this
531    /// function.
532    pub unsafe fn calculate_normals(&mut self, handedness: Handedness, zeroed: bool) {
533        if handedness == Handedness::Left {
534            Self::calculate_normals_for_buffers::<true>(
535                &mut self.vertex_normals,
536                &self.vertex_positions,
537                &self.indices,
538                zeroed,
539            )
540        } else {
541            Self::calculate_normals_for_buffers::<false>(
542                &mut self.vertex_normals,
543                &self.vertex_positions,
544                &self.indices,
545                zeroed,
546            )
547        }
548    }
549
550    /// Calculate normals for the given buffers representing a mesh, assuming
551    /// smooth shading and per-vertex normals.
552    ///
553    /// It is sound to call this function with the wrong handedness, it will
554    /// just result in flipped normals.
555    ///
556    /// If zeroed is true, the normals will not be zeroed before hand. If this
557    /// is falsely set, it is safe, just returns incorrect results.
558    ///
559    /// # Safety
560    ///
561    /// The following must be true:
562    /// - Normals and positions must be the same length.
563    /// - All indices must be in-bounds for the buffers.
564    ///
565    /// If a mesh has passed a call to validate, it is sound to call this
566    /// function.
567    pub unsafe fn calculate_normals_for_buffers<const LEFT_HANDED: bool>(
568        normals: &mut [Vec3],
569        positions: &[Vec3],
570        indices: &[u32],
571        zeroed: bool,
572    ) {
573        debug_assert_eq!(normals.len(), positions.len());
574
575        if !zeroed {
576            for norm in normals.iter_mut() {
577                *norm = Vec3::ZERO;
578            }
579        }
580
581        for idx in indices.chunks_exact(3) {
582            let (idx0, idx1, idx2) = match *idx {
583                [idx0, idx1, idx2] => (idx0, idx1, idx2),
584                // SAFETY: This is guaranteed by chunks_exact(3)
585                _ => std::hint::unreachable_unchecked(),
586            };
587
588            // SAFETY: The conditions of this function assert all thes indices are in-bounds
589            let pos1 = *positions.get_unchecked(idx0 as usize);
590            let pos2 = *positions.get_unchecked(idx1 as usize);
591            let pos3 = *positions.get_unchecked(idx2 as usize);
592
593            let edge1 = pos2 - pos1;
594            let edge2 = pos3 - pos1;
595
596            let normal = if LEFT_HANDED {
597                edge1.cross(edge2)
598            } else {
599                edge2.cross(edge1)
600            };
601
602            // SAFETY: The conditions of this function assert all thes indices are in-bounds
603            *normals.get_unchecked_mut(idx0 as usize) += normal;
604            *normals.get_unchecked_mut(idx1 as usize) += normal;
605            *normals.get_unchecked_mut(idx2 as usize) += normal;
606        }
607
608        for normal in normals.iter_mut() {
609            *normal = normal.normalize_or_zero();
610        }
611    }
612
613    /// Calculate tangents for the given mesh, based on normals and texture
614    /// coordinates.
615    ///
616    /// If zeroed is true, the normals will not be zeroed before hand. If this
617    /// is falsely set, it is safe, just returns incorrect results.
618    ///
619    /// # Safety
620    ///
621    /// The following must be true:
622    /// - Tangents, positions, normals, and uvs must be the same length.
623    /// - All indices must be in-bounds for the buffers.
624    ///
625    /// If a mesh has passed a call to validate, it is sound to call this
626    /// function.
627    pub unsafe fn calculate_tangents(&mut self, zeroed: bool) {
628        // SAFETY: The mesh unconditionally has a validation token, so it must be valid.
629        Self::calculate_tangents_for_buffers(
630            &mut self.vertex_tangents,
631            &self.vertex_positions,
632            &self.vertex_normals,
633            &self.vertex_uv0,
634            &self.indices,
635            zeroed,
636        )
637    }
638
639    /// Calculate tangents for the given set of buffers, based on normals and
640    /// texture coordinates.
641    ///
642    /// If zeroed is true, the normals will not be zeroed before hand. If this
643    /// is falsely set, it is safe, just returns incorrect results.
644    ///
645    /// # Safety
646    ///
647    /// The following must be true:
648    /// - Tangents, positions, normals, and uvs must be the same length.
649    /// - All indices must be in-bounds for the buffers.
650    pub unsafe fn calculate_tangents_for_buffers(
651        tangents: &mut [Vec3],
652        positions: &[Vec3],
653        normals: &[Vec3],
654        uvs: &[Vec2],
655        indices: &[u32],
656        zeroed: bool,
657    ) {
658        debug_assert_eq!(tangents.len(), positions.len());
659        debug_assert_eq!(uvs.len(), positions.len());
660
661        if !zeroed {
662            for tan in tangents.iter_mut() {
663                *tan = Vec3::ZERO;
664            }
665        }
666
667        for idx in indices.chunks_exact(3) {
668            let (idx0, idx1, idx2) = match *idx {
669                [idx0, idx1, idx2] => (idx0, idx1, idx2),
670                // SAFETY: This is guaranteed by chunks_exact(3)
671                _ => std::hint::unreachable_unchecked(),
672            };
673
674            // SAFETY: The conditions of this function assert all thes indices are in-bounds
675            let pos1 = *positions.get_unchecked(idx0 as usize);
676            let pos2 = *positions.get_unchecked(idx1 as usize);
677            let pos3 = *positions.get_unchecked(idx2 as usize);
678
679            let tex1 = *uvs.get_unchecked(idx0 as usize);
680            let tex2 = *uvs.get_unchecked(idx1 as usize);
681            let tex3 = *uvs.get_unchecked(idx2 as usize);
682
683            let edge1 = pos2 - pos1;
684            let edge2 = pos3 - pos1;
685
686            let uv1 = tex2 - tex1;
687            let uv2 = tex3 - tex1;
688
689            let r = 1.0 / (uv1.x * uv2.y - uv1.y * uv2.x);
690
691            let tangent = Vec3::new(
692                ((edge1.x * uv2.y) - (edge2.x * uv1.y)) * r,
693                ((edge1.y * uv2.y) - (edge2.y * uv1.y)) * r,
694                ((edge1.z * uv2.y) - (edge2.z * uv1.y)) * r,
695            );
696
697            // SAFETY: The conditions of this function assert all thes indices are in-bounds
698            *tangents.get_unchecked_mut(idx0 as usize) += tangent;
699            *tangents.get_unchecked_mut(idx1 as usize) += tangent;
700            *tangents.get_unchecked_mut(idx2 as usize) += tangent;
701        }
702
703        for (tan, norm) in tangents.iter_mut().zip(normals) {
704            let t = *tan - (*norm * norm.dot(*tan));
705            *tan = t.normalize_or_zero();
706        }
707    }
708
709    /// Converts the mesh from single sided to double sided.
710    pub fn double_side(&mut self) {
711        let starting_len = self.indices.len();
712        // This floors, so the following unsafe is in-bounds.
713        let primative_count = starting_len / 3;
714        // reserve additional space -- this "doubles" the capasity
715        self.indices.reserve(starting_len);
716
717        let ptr = self.indices.as_mut_ptr();
718
719        #[allow(clippy::identity_op)]
720        unsafe {
721            // Iterate in reverse as to not stomp on ourself
722            for prim in (0..primative_count).rev() {
723                let i1 = *ptr.add(prim * 3 + 0);
724                let i2 = *ptr.add(prim * 3 + 1);
725                let i3 = *ptr.add(prim * 3 + 2);
726
727                // One triangle forward.
728                ptr.add(prim * 6 + 0).write(i1);
729                ptr.add(prim * 6 + 1).write(i2);
730                ptr.add(prim * 6 + 2).write(i3);
731
732                // One triangle reverse.
733                ptr.add(prim * 6 + 3).write(i3);
734                ptr.add(prim * 6 + 4).write(i2);
735                ptr.add(prim * 6 + 5).write(i1);
736            }
737
738            self.indices.set_len(starting_len * 2);
739        }
740    }
741
742    /// Inverts the winding order of a mesh. This is useful if you have meshes
743    /// which are designed for right-handed (Counter-Clockwise) winding
744    /// order for use in OpenGL or VK.
745    ///
746    /// This does not change vertex location, so does not change coordinate
747    /// system. This will also not change the vertex normals. Calling
748    /// [`Mesh::calculate_normals`] is advised after calling this function.
749    pub fn flip_winding_order(&mut self) {
750        for indices in self.indices.chunks_exact_mut(3) {
751            if let [left, _, right] = indices {
752                mem::swap(left, right);
753            } else {
754                // SAFETY: chunks_exact(3) guarantees us 3 value long slices
755                unsafe { std::hint::unreachable_unchecked() }
756            }
757        }
758    }
759}
760
761/// The count of mipmap levels a texture should have.
762#[derive(Debug, Clone)]
763pub enum MipmapCount {
764    /// Specifies a texture with the tiven mipmap count. Must not be greater
765    /// than the maximum.
766    Specific(NonZeroU32),
767    /// Specifies a texture with the maximum mipmap count.
768    Maximum,
769}
770
771impl MipmapCount {
772    pub const ONE: Self = Self::Specific(unsafe { NonZeroU32::new_unchecked(1) });
773}
774
775/// How texture mipmaps get generated.
776#[derive(Debug, Clone)]
777pub enum MipmapSource {
778    /// The user will provide all of the mipmaps in the data texture. Upload all
779    /// mip levels.
780    Uploaded,
781    /// rend3 will generate the mipmaps for you. Upload only mip level 0.
782    Generated,
783}
784
785/// A bitmap image used as a data source for a texture.
786#[derive(Debug, Clone)]
787pub struct Texture {
788    pub label: Option<String>,
789    pub data: Vec<u8>,
790    pub format: TextureFormat,
791    pub size: UVec2,
792    pub mip_count: MipmapCount,
793    pub mip_source: MipmapSource,
794}
795
796/// Describes a texture made from the mipmaps of another texture.
797#[derive(Debug, Clone)]
798pub struct TextureFromTexture {
799    pub label: Option<String>,
800    pub src: TextureHandle,
801    pub start_mip: u32,
802    pub mip_count: Option<NonZeroU32>,
803}
804
805#[doc(hidden)]
806pub struct MaterialTag;
807
808/// Interface that all materials must use.
809///
810/// The material will provide a set of textures, and a pile of bytes. It will
811/// then, as part of the material bind group, present the following abi:
812///
813/// ### CpuDriven Profile
814///
815/// - A uniform binding with:
816///   - The data provided, with padding up to 16 byte alignment.
817///   - A u32 bitflag telling which textures are null. To check if texture N is
818///     enabled, do `(texture_bitflag >> N) & 0x1 == 1`.
819/// - One Texture2D binding per texture, provided in the order given. If given a
820///   `None`, will bind a null texture (1x1 texture with a (0, 0, 0, 255)
821///   pixel).
822///
823/// ### GpuDriven Profile
824/// - A material array indexed by the material index. Each material has:
825///   - One u32 per texture. If this value is 0, the texture doesn't exist. If
826///     this value is non-zero, subtract one and index into the texture array to
827///     ge thte texture.
828///   - Padding to 16 byte alignemnet.
829///   - The data provided by the material.
830pub trait Material: Send + Sync + 'static {
831    /// The texture count that will be provided to `to_textures`.
832    const TEXTURE_COUNT: u32;
833    /// The amount of data that will be provided to `to_data`.
834    const DATA_SIZE: u32;
835
836    /// u64 key that determine's an object's archetype. When you query for
837    /// objects from the object manager, you must provide this key to get all
838    /// objects with this key.
839    fn object_key(&self) -> u64;
840
841    /// Fill up the given slice with textures.
842    fn to_textures<'a>(&'a self, slice: &mut [Option<&'a TextureHandle>]);
843
844    /// Fill up the given slice with binary material data. This can be whatever
845    /// data a shader expects.
846    fn to_data(&self, slice: &mut [u8]);
847}
848
849/// Source of a mesh for an object.
850#[derive(Clone, Debug)]
851pub enum ObjectMeshKind {
852    Animated(SkeletonHandle),
853    Static(MeshHandle),
854}
855
856changeable_struct! {
857    /// An object in the world that is composed of a [`Mesh`] and [`Material`].
858    pub struct Object <- ObjectChange {
859        pub mesh_kind: ObjectMeshKind,
860        pub material: MaterialHandle,
861        pub transform: Mat4,
862    }
863}
864
865/// Describes how the camera should look at the scene.
866#[derive(Debug, Default, Copy, Clone)]
867pub struct Camera {
868    pub projection: CameraProjection,
869    /// View matrix
870    pub view: Mat4,
871}
872
873/// Describes how the world should be projected into the camera.
874#[derive(Debug, Copy, Clone)]
875pub enum CameraProjection {
876    Orthographic {
877        /// Size assumes the location is at the center of the camera area.
878        size: Vec3A,
879    },
880    Perspective {
881        /// Vertical field of view in degrees.
882        vfov: f32,
883        /// Near plane distance. All projection uses a infinite far plane.
884        near: f32,
885    },
886    Raw(Mat4),
887}
888
889impl Default for CameraProjection {
890    fn default() -> Self {
891        Self::Perspective { vfov: 60.0, near: 0.1 }
892    }
893}
894
895changeable_struct! {
896    /// Describes how directional lights (sun lights) and their shadows should be processed.
897    pub struct DirectionalLight <- DirectionalLightChange {
898        /// Color of the light.
899        pub color: Vec3,
900        /// Constant multiplier for the light.
901        pub intensity: f32,
902        /// Direction of the sun.
903        pub direction: Vec3,
904        /// Distance from the camera that shadows should be calculated.
905        pub distance: f32,
906    }
907}
908
909/// The sample count when doing multisampling.
910#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
911#[repr(u8)]
912pub enum SampleCount {
913    One = 1,
914    Four = 4,
915}
916
917impl Default for SampleCount {
918    fn default() -> Self {
919        Self::One
920    }
921}
922
923impl TryFrom<u8> for SampleCount {
924    type Error = u8;
925
926    fn try_from(value: u8) -> Result<Self, Self::Error> {
927        Ok(match value {
928            1 => Self::One,
929            4 => Self::Four,
930            v => return Err(v),
931        })
932    }
933}
934
935impl SampleCount {
936    /// Determines if a resolve texture is needed for this texture.
937    pub fn needs_resolve(self) -> bool {
938        self != Self::One
939    }
940}
941
942/// Describes the "Handedness" of a given coordinate system. Affects math done
943/// in the space.
944///
945/// While a weird term, if you make your thumb X, your pointer Y,
946/// and your middle finger Z, the handedness can be determined by which hand can
947/// contort to represent the coordinate system.
948///
949/// For example  
950/// +X right, +Y up, +Z _into_ the screen is left handed.  
951/// +X right, +Y up, +Z _out of_ the screen is right handed.
952#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
953pub enum Handedness {
954    Left,
955    Right,
956}
957
958impl Default for Handedness {
959    fn default() -> Self {
960        Self::Left
961    }
962}
963
964/// A Skeleton stores the necessary data to do vertex skinning for an [Object].
965#[derive(Debug, Clone)]
966pub struct Skeleton {
967    /// Stores one transformation matrix for each joint. These are the
968    /// transformations that will be applied to the vertices affected by the
969    /// corresponding joint. Not to be confused with the transform matrix of the
970    /// joint itself.
971    ///
972    /// The `Skeleton::form_joint_transforms` constructor can be used to create
973    /// a Skeleton with the joint transform matrices instead.
974    pub joint_matrices: Vec<Mat4>,
975    pub mesh: MeshHandle,
976}
977
978impl Skeleton {
979    /// Creates a skeleton with the list of global transforms and inverse bind
980    /// transforms for each joint
981    pub fn from_joint_transforms(
982        mesh: MeshHandle,
983        joint_global_transforms: &[Mat4],
984        inverse_bind_transforms: &[Mat4],
985    ) -> Skeleton {
986        let joint_matrices = Self::compute_joint_matrices(joint_global_transforms, inverse_bind_transforms);
987        Skeleton { joint_matrices, mesh }
988    }
989
990    /// Given a list of joint global positions and another one with inverse bind
991    /// matrices, multiplies them together to return the list of joint matrices.
992    pub fn compute_joint_matrices(joint_global_transforms: &[Mat4], inverse_bind_transforms: &[Mat4]) -> Vec<Mat4> {
993        joint_global_transforms
994            .iter()
995            .zip(inverse_bind_transforms.iter())
996            .map(|(global_pos, inv_bind_pos)| (*global_pos) * (*inv_bind_pos))
997            .collect()
998    }
999}