1use crate::math::IsVector;
3use crabslab::SlabItem;
4
5#[cfg(cpu)]
6mod cpu;
7#[cfg(cpu)]
8pub use cpu::*;
9use glam::{Vec2, Vec3, Vec4};
10
11pub mod shader;
12
13#[derive(Clone, Copy, Default, PartialEq, SlabItem, core::fmt::Debug)]
20pub struct MorphTarget {
21 pub position: Vec3,
22 pub normal: Vec3,
23 pub tangent: Vec3,
24 }
27
28#[derive(Clone, Copy, core::fmt::Debug, PartialEq, SlabItem)]
30pub struct Vertex {
31 pub position: Vec3,
32 pub color: Vec4,
33 pub uv0: Vec2,
34 pub uv1: Vec2,
35 pub normal: Vec3,
36 pub tangent: Vec4,
37 pub joints: [u32; 4],
39 pub weights: [f32; 4],
41}
42
43impl Default for Vertex {
44 fn default() -> Self {
45 Self {
46 position: Default::default(),
47 color: Vec4::ONE,
48 uv0: Vec2::ZERO,
49 uv1: Vec2::ZERO,
50 normal: Vec3::Z,
51 tangent: Vec4::Y,
52 joints: [0; 4],
53 weights: [0.0; 4],
54 }
55 }
56}
57
58impl Vertex {
59 pub fn with_position(mut self, p: impl Into<Vec3>) -> Self {
60 self.position = p.into();
61 self
62 }
63
64 pub fn with_color(mut self, c: impl Into<Vec4>) -> Self {
65 self.color = c.into();
66 self
67 }
68
69 pub fn with_uv0(mut self, uv: impl Into<Vec2>) -> Self {
70 self.uv0 = uv.into();
71 self
72 }
73
74 pub fn with_uv1(mut self, uv: impl Into<Vec2>) -> Self {
75 self.uv1 = uv.into();
76 self
77 }
78
79 pub fn with_normal(mut self, n: impl Into<Vec3>) -> Self {
80 self.normal = n.into();
81 self
82 }
83
84 pub fn with_tangent(mut self, t: impl Into<Vec4>) -> Self {
85 self.tangent = t.into();
86 self
87 }
88
89 pub fn generate_normal(a: Vec3, b: Vec3, c: Vec3) -> Vec3 {
90 let ab = a - b;
91 let ac = a - c;
92 ab.cross(ac).normalize()
93 }
94
95 pub fn generate_tangent(a: Vec3, a_uv: Vec2, b: Vec3, b_uv: Vec2, c: Vec3, c_uv: Vec2) -> Vec4 {
96 let ab = b - a;
97 let ac = c - a;
98 let n = ab.cross(ac);
99 let d_uv1 = b_uv - a_uv;
100 let d_uv2 = c_uv - a_uv;
101 let denom = d_uv1.x * d_uv2.y - d_uv2.x * d_uv1.y;
102 let denom_sign = if denom >= 0.0 { 1.0 } else { -1.0 };
103 let denom = denom.abs().max(f32::EPSILON) * denom_sign;
104 let f = 1.0 / denom;
105 let s = f * Vec3::new(
106 d_uv2.y * ab.x - d_uv1.y * ac.x,
107 d_uv2.y * ab.y - d_uv1.y * ac.y,
108 d_uv2.y * ab.z - d_uv1.y * ac.z,
109 );
110 let t = f * Vec3::new(
111 d_uv1.x * ac.x - d_uv2.x * ab.x,
112 d_uv1.x * ac.y - d_uv2.x * ab.y,
113 d_uv1.x * ac.z - d_uv2.x * ab.z,
114 );
115 let n_cross_t_dot_s_sign = if n.cross(t).dot(s) >= 0.0 { 1.0 } else { -1.0 };
116 (s - s.dot(n) * n)
117 .alt_norm_or_zero()
118 .extend(n_cross_t_dot_s_sign)
119 }
120
121 #[cfg(cpu)]
122 pub fn cube_mesh() -> [Vertex; 36] {
124 let mut mesh = [Vertex::default(); 36];
125 let unit_cube = crate::math::unit_cube();
126 debug_assert_eq!(36, unit_cube.len());
127 for (i, (position, normal)) in unit_cube.into_iter().enumerate() {
128 mesh[i].position = position;
129 mesh[i].normal = normal;
130 }
131 mesh
132 }
133}