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