1use anyhow::Result;
10use std::io::Read;
11use super::prp::PlasmaRead;
12
13const K_POS_QUANTUM: f32 = 1.0 / (1 << 10) as f32;
15const K_WEIGHT_QUANTUM: f32 = 1.0 / (1 << 15) as f32;
16const K_UVW_QUANTUM: f32 = 1.0 / (1u32 << 16) as f32;
17
18const K_POSITION: usize = 0;
20const K_WEIGHT: usize = 1;
21const K_UVW: usize = 2;
22const K_NUM_FLOAT_FIELDS: usize = K_UVW + 8;
23
24const K_QUANTA: [f32; K_NUM_FLOAT_FIELDS] = [
26 K_POS_QUANTUM,
27 K_WEIGHT_QUANTUM,
28 K_UVW_QUANTUM, K_UVW_QUANTUM, K_UVW_QUANTUM, K_UVW_QUANTUM,
29 K_UVW_QUANTUM, K_UVW_QUANTUM, K_UVW_QUANTUM, K_UVW_QUANTUM,
30];
31
32const K_SAME_MASK: u16 = 0x8000;
34
35const K_UV_COUNT_MASK: u8 = 0x0f;
37const K_SKIN_WEIGHT_MASK: u8 = 0x30;
38const K_SKIN_INDICES: u8 = 0x40;
39
40struct FloatCode {
42 offset: f32,
43 all_same: bool,
44 count: u16,
45}
46
47struct ByteCode {
49 count: u16,
50 val: u8,
51 same: bool,
52}
53
54pub struct VertDecoder {
56 floats: [[FloatCode; 3]; K_NUM_FLOAT_FIELDS],
58 colors: [ByteCode; 4],
60}
61
62impl VertDecoder {
63 pub fn new() -> Self {
65 Self {
66 floats: std::array::from_fn(|_| std::array::from_fn(|_| FloatCode {
67 offset: 0.0, all_same: false, count: 0,
68 })),
69 colors: std::array::from_fn(|_| ByteCode {
70 count: 0, val: 0, same: false,
71 }),
72 }
73 }
74
75 fn i_read_float(reader: &mut impl Read, dst: &mut [u8], pos: &mut usize,
77 offset: f32, quantum: f32) -> Result<()> {
78 let ival = reader.read_u16()?;
79 let fval = ival as f32 * quantum + offset;
80 dst[*pos..*pos + 4].copy_from_slice(&fval.to_le_bytes());
81 *pos += 4;
82 Ok(())
83 }
84
85 fn i_decode_float(&mut self, reader: &mut impl Read, field: usize, chan: usize,
87 dst: &mut [u8], pos: &mut usize) -> Result<()> {
88 if self.floats[field][chan].count == 0 {
89 self.floats[field][chan].offset = reader.read_f32()?;
90 self.floats[field][chan].all_same = reader.read_u8()? != 0;
91 self.floats[field][chan].count = reader.read_u16()?;
92 }
93 if !self.floats[field][chan].all_same {
94 Self::i_read_float(reader, dst, pos, self.floats[field][chan].offset, K_QUANTA[field])?;
95 } else {
96 let bytes = self.floats[field][chan].offset.to_le_bytes();
97 dst[*pos..*pos + 4].copy_from_slice(&bytes);
98 *pos += 4;
99 }
100 self.floats[field][chan].count -= 1;
101 Ok(())
102 }
103
104 fn i_decode_normal(reader: &mut impl Read, dst: &mut [u8], pos: &mut usize) -> Result<()> {
106 for _ in 0..3 {
108 let ix = reader.read_u8()?;
109 let x = (ix as f32 / 255.9 - 0.5) * 2.0;
110 dst[*pos..*pos + 4].copy_from_slice(&x.to_le_bytes());
111 *pos += 4;
112 }
113 Ok(())
114 }
115
116 fn i_decode_byte(&mut self, reader: &mut impl Read, chan: usize,
118 dst: &mut [u8], pos: &mut usize) -> Result<()> {
119 if self.colors[chan].count == 0 {
120 let cnt = reader.read_u16()?;
121 if cnt & K_SAME_MASK != 0 {
122 self.colors[chan].same = true;
123 self.colors[chan].val = reader.read_u8()?;
124 self.colors[chan].count = cnt & !K_SAME_MASK;
125 } else {
126 self.colors[chan].same = false;
127 self.colors[chan].count = cnt;
128 }
129 }
130 if !self.colors[chan].same {
131 dst[*pos] = reader.read_u8()?;
132 } else {
133 dst[*pos] = self.colors[chan].val;
134 }
135 *pos += 1;
136 self.colors[chan].count -= 1;
137 Ok(())
138 }
139
140 fn i_decode_color(&mut self, reader: &mut impl Read,
142 dst: &mut [u8], pos: &mut usize) -> Result<()> {
143 self.i_decode_byte(reader, 0, dst, pos)?;
144 self.i_decode_byte(reader, 1, dst, pos)?;
145 self.i_decode_byte(reader, 2, dst, pos)?;
146 self.i_decode_byte(reader, 3, dst, pos)?;
147 Ok(())
148 }
149
150 fn i_num_weights(format: u8) -> usize {
152 ((format & K_SKIN_WEIGHT_MASK) >> 4) as usize
153 }
154
155 fn i_decode(&mut self, reader: &mut impl Read, dst: &mut [u8], pos: &mut usize,
157 format: u8) -> Result<()> {
158 self.i_decode_float(reader, K_POSITION, 0, dst, pos)?;
160 self.i_decode_float(reader, K_POSITION, 1, dst, pos)?;
161 self.i_decode_float(reader, K_POSITION, 2, dst, pos)?;
162
163 let num_weights = Self::i_num_weights(format);
165 for j in 0..num_weights {
166 self.i_decode_float(reader, K_WEIGHT, j, dst, pos)?;
167 }
168 if format & K_SKIN_INDICES != 0 {
170 let idx = reader.read_u32()?;
171 dst[*pos..*pos + 4].copy_from_slice(&idx.to_le_bytes());
172 *pos += 4;
173 }
174
175 Self::i_decode_normal(reader, dst, pos)?;
177
178 self.i_decode_color(reader, dst, pos)?;
180
181 dst[*pos..*pos + 4].copy_from_slice(&[0u8; 4]);
183 *pos += 4;
184
185 let num_uvws = (format & K_UV_COUNT_MASK) as usize;
187 for i in 0..num_uvws {
188 self.i_decode_float(reader, K_UVW + i, 0, dst, pos)?;
189 self.i_decode_float(reader, K_UVW + i, 1, dst, pos)?;
190 self.i_decode_float(reader, K_UVW + i, 2, dst, pos)?;
191 }
192
193 Ok(())
194 }
195
196 pub fn read(&mut self, reader: &mut impl Read, format: u8, stride: usize,
198 num_verts: u16) -> Result<Vec<u8>> {
199 let total_size = num_verts as usize * stride;
201 let mut data = vec![0u8; total_size];
202
203 for i in 0..num_verts as usize {
204 let mut pos = i * stride;
205 if let Err(e) = self.i_decode(reader, &mut data, &mut pos, format) {
206 if i == 0 {
207 return Err(e);
208 }
209 log::warn!("Vertex decode failed at vertex {}/{}: {}, returning partial data",
210 i, num_verts, e);
211 data.truncate(i * stride);
212 return Ok(data);
213 }
214 }
215
216 Ok(data)
217 }
218}
219
220pub fn calc_vertex_stride(format: u8) -> usize {
228 let mut size: usize = std::mem::size_of::<f32>() * (3 + 3); let num_uvs = (format & K_UV_COUNT_MASK) as usize;
233 size += std::mem::size_of::<f32>() * 3 * num_uvs;
234
235 let num_weights = ((format & K_SKIN_WEIGHT_MASK) >> 4) as usize;
237 if num_weights > 0 {
238 size += std::mem::size_of::<f32>() * num_weights;
239 if format & K_SKIN_INDICES != 0 {
240 size += std::mem::size_of::<u32>();
241 }
242 }
243
244 size += std::mem::size_of::<u32>() * 2;
248
249 size
250}