1use 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
17pub use glam;
19
20pub struct RawResourceHandle<T> {
25 pub idx: usize,
27 _phantom: PhantomData<T>,
28}
29
30impl<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
56pub 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 pub fn new(idx: usize) -> Self {
101 Self {
102 refcount: Arc::new(()),
103 idx,
104 _phantom: PhantomData,
105 }
106 }
107
108 pub fn get_raw(&self) -> RawResourceHandle<T> {
112 RawResourceHandle {
113 idx: self.idx,
114 _phantom: PhantomData,
115 }
116 }
117
118 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#[doc(inline)]
192pub use wgt::{Backend, Backends, Color, DeviceType, PresentMode, TextureFormat, TextureUsages};
193
194pub const MAX_VERTEX_COUNT: usize = 1 << 24;
199
200#[derive(Debug, Copy, Clone)]
202pub enum VertexBufferType {
203 Position,
204 Normal,
205 Tangent,
206 Uv0,
207 Uv1,
208 Colors,
209}
210
211#[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#[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 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 pub fn with_vertex_normals(mut self, normals: Vec<Vec3>) -> Self {
270 self.vertex_normals = Some(normals);
271 self
272 }
273
274 pub fn with_vertex_tangents(mut self, tangents: Vec<Vec3>) -> Self {
280 self.vertex_tangents = Some(tangents);
281 self
282 }
283
284 pub fn with_vertex_uv0(mut self, uvs: Vec<Vec2>) -> Self {
290 self.vertex_uv0 = Some(uvs);
291 self
292 }
293
294 pub fn with_vertex_uv1(mut self, uvs: Vec<Vec2>) -> Self {
300 self.vertex_uv1 = Some(uvs);
301 self
302 }
303
304 pub fn with_vertex_colors(mut self, colors: Vec<[u8; 4]>) -> Self {
310 self.vertex_colors = Some(colors);
311 self
312 }
313
314 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 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 pub fn with_indices(mut self, indices: Vec<u32>) -> Self {
340 self.indices = Some(indices);
341 self
342 }
343
344 pub fn with_flip_winding_order(mut self) -> Self {
348 self.flip_winding_order = true;
349 self
350 }
351
352 pub fn with_double_sided(mut self) -> Self {
356 self.double_sided = true;
357 self
358 }
359
360 pub unsafe fn without_validation(mut self) -> Self {
372 self.without_validation = true;
373 self
374 }
375
376 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 if self.flip_winding_order {
408 mesh.flip_winding_order();
409 }
410
411 if !has_normals {
412 unsafe { mesh.calculate_normals(self.handedness, true) };
414 }
415
416 if !has_tangents && has_uvs {
418 unsafe { mesh.calculate_tangents(true) };
420 }
421
422 Ok(mesh)
423 }
424}
425
426#[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 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 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 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 _ => std::hint::unreachable_unchecked(),
586 };
587
588 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 *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 pub unsafe fn calculate_tangents(&mut self, zeroed: bool) {
628 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 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 _ => std::hint::unreachable_unchecked(),
672 };
673
674 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 *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 pub fn double_side(&mut self) {
711 let starting_len = self.indices.len();
712 let primative_count = starting_len / 3;
714 self.indices.reserve(starting_len);
716
717 let ptr = self.indices.as_mut_ptr();
718
719 #[allow(clippy::identity_op)]
720 unsafe {
721 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 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 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 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 unsafe { std::hint::unreachable_unchecked() }
756 }
757 }
758 }
759}
760
761#[derive(Debug, Clone)]
763pub enum MipmapCount {
764 Specific(NonZeroU32),
767 Maximum,
769}
770
771impl MipmapCount {
772 pub const ONE: Self = Self::Specific(unsafe { NonZeroU32::new_unchecked(1) });
773}
774
775#[derive(Debug, Clone)]
777pub enum MipmapSource {
778 Uploaded,
781 Generated,
783}
784
785#[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#[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
808pub trait Material: Send + Sync + 'static {
831 const TEXTURE_COUNT: u32;
833 const DATA_SIZE: u32;
835
836 fn object_key(&self) -> u64;
840
841 fn to_textures<'a>(&'a self, slice: &mut [Option<&'a TextureHandle>]);
843
844 fn to_data(&self, slice: &mut [u8]);
847}
848
849#[derive(Clone, Debug)]
851pub enum ObjectMeshKind {
852 Animated(SkeletonHandle),
853 Static(MeshHandle),
854}
855
856changeable_struct! {
857 pub struct Object <- ObjectChange {
859 pub mesh_kind: ObjectMeshKind,
860 pub material: MaterialHandle,
861 pub transform: Mat4,
862 }
863}
864
865#[derive(Debug, Default, Copy, Clone)]
867pub struct Camera {
868 pub projection: CameraProjection,
869 pub view: Mat4,
871}
872
873#[derive(Debug, Copy, Clone)]
875pub enum CameraProjection {
876 Orthographic {
877 size: Vec3A,
879 },
880 Perspective {
881 vfov: f32,
883 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 pub struct DirectionalLight <- DirectionalLightChange {
898 pub color: Vec3,
900 pub intensity: f32,
902 pub direction: Vec3,
904 pub distance: f32,
906 }
907}
908
909#[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 pub fn needs_resolve(self) -> bool {
938 self != Self::One
939 }
940}
941
942#[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#[derive(Debug, Clone)]
966pub struct Skeleton {
967 pub joint_matrices: Vec<Mat4>,
975 pub mesh: MeshHandle,
976}
977
978impl Skeleton {
979 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 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}