1use crate::types::Bone;
12
13#[derive(Debug, Clone, Copy, PartialEq)]
15pub struct Transform {
16 pub rotation: [f32; 4],
18 pub translation: [f32; 3],
20}
21
22fn qmul(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
23 let [ax, ay, az, aw] = a;
24 let [bx, by, bz, bw] = b;
25 [
26 aw * bx + ax * bw + ay * bz - az * by,
27 aw * by - ax * bz + ay * bw + az * bx,
28 aw * bz + ax * by - ay * bx + az * bw,
29 aw * bw - ax * bx - ay * by - az * bz,
30 ]
31}
32
33fn conj(q: [f32; 4]) -> [f32; 4] {
34 [-q[0], -q[1], -q[2], q[3]]
35}
36
37fn rotate(q: [f32; 4], v: [f32; 3]) -> [f32; 3] {
38 let p = qmul(qmul(q, [v[0], v[1], v[2], 0.0]), conj(q));
39 [p[0], p[1], p[2]]
40}
41
42impl Transform {
43 pub const IDENTITY: Transform = Transform {
45 rotation: [0.0, 0.0, 0.0, 1.0],
46 translation: [0.0; 3],
47 };
48
49 pub fn mul(&self, other: &Transform) -> Transform {
51 let t = rotate(self.rotation, other.translation);
52 Transform {
53 rotation: qmul(self.rotation, other.rotation),
54 translation: [
55 t[0] + self.translation[0],
56 t[1] + self.translation[1],
57 t[2] + self.translation[2],
58 ],
59 }
60 }
61
62 pub fn apply(&self, v: [f32; 3]) -> [f32; 3] {
64 let r = rotate(self.rotation, v);
65 [
66 r[0] + self.translation[0],
67 r[1] + self.translation[1],
68 r[2] + self.translation[2],
69 ]
70 }
71
72 pub fn to_matrix(&self) -> [f32; 16] {
74 let [x, y, z, w] = self.rotation;
75 let [tx, ty, tz] = self.translation;
76 [
77 1.0 - 2.0 * (y * y + z * z),
78 2.0 * (x * y + z * w),
79 2.0 * (x * z - y * w),
80 0.0,
81 2.0 * (x * y - z * w),
82 1.0 - 2.0 * (x * x + z * z),
83 2.0 * (y * z + x * w),
84 0.0,
85 2.0 * (x * z + y * w),
86 2.0 * (y * z - x * w),
87 1.0 - 2.0 * (x * x + y * y),
88 0.0,
89 tx,
90 ty,
91 tz,
92 1.0,
93 ]
94 }
95}
96
97pub fn local_bind(bone: &Bone) -> Transform {
99 Transform {
100 rotation: conj(bone.rotation),
101 translation: bone.translation,
102 }
103}
104
105pub fn inverse_bind(bone: &Bone) -> Transform {
107 Transform {
108 rotation: conj(bone.inv_rotation),
109 translation: bone.inv_translation,
110 }
111}
112
113pub fn world_transforms(bones: &[Bone], locals: &[Transform]) -> Vec<Transform> {
115 let mut world: Vec<Transform> = Vec::with_capacity(bones.len());
116 for (bone, local) in bones.iter().zip(locals) {
117 let w = match usize::try_from(bone.parent).ok().and_then(|p| world.get(p)) {
118 Some(parent) => parent.mul(local),
119 None => *local,
120 };
121 world.push(w);
122 }
123 world
124}
125
126pub fn palette(bones: &[Bone], locals: &[Transform]) -> Vec<Transform> {
128 world_transforms(bones, locals)
129 .iter()
130 .zip(bones)
131 .map(|(w, b)| w.mul(&inverse_bind(b)))
132 .collect()
133}
134
135pub fn bind_palette(bones: &[Bone]) -> Vec<Transform> {
137 let locals: Vec<Transform> = bones.iter().map(local_bind).collect();
138 palette(bones, &locals)
139}
140
141pub fn skin_to_static(vertices: &[u8], palette: &[Transform]) -> Vec<u8> {
146 use crate::types::{SKINNED_STRIDE, STATIC_STRIDE};
147 let mut out = Vec::with_capacity(vertices.len() / SKINNED_STRIDE * STATIC_STRIDE);
148 for v in vertices.chunks_exact(SKINNED_STRIDE) {
149 let i16_at = |o: usize| i16::from_le_bytes([v[o], v[o + 1]]) as f32;
150 let p = [i16_at(0) / 512.0, i16_at(2) / 512.0, i16_at(4) / 512.0];
151 let n = [
152 v[16] as f32 / 127.5 - 1.0,
153 v[17] as f32 / 127.5 - 1.0,
154 v[18] as f32 / 127.5 - 1.0,
155 ];
156 let (mut sp, mut sn) = ([0.0f32; 3], [0.0f32; 3]);
157 for k in 0..4 {
158 let w = v[24 + k] as f32 / 255.0;
159 if w == 0.0 {
160 continue;
161 }
162 let t = palette
163 .get(v[28 + k] as usize)
164 .copied()
165 .unwrap_or(Transform::IDENTITY);
166 let q = t.apply(p);
167 let r = t.apply([0.0; 3]);
168 let m = t.apply(n);
169 for a in 0..3 {
170 sp[a] += q[a] * w;
171 sn[a] += (m[a] - r[a]) * w;
172 }
173 }
174 let len = (sn[0] * sn[0] + sn[1] * sn[1] + sn[2] * sn[2])
175 .sqrt()
176 .max(1e-6);
177 for value in sp {
178 out.extend_from_slice(&((value * 512.0).round() as i16).to_le_bytes());
179 }
180 out.extend_from_slice(&v[6..16]);
181 for value in sn {
182 out.push(((value / len * 0.5 + 0.5) * 255.0).round() as u8);
183 }
184 out.push(v[19]);
185 out.extend_from_slice(&[0; 4]);
186 }
187 out
188}