1use serde_json::Value;
4
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7 #[error("Accessor {0} not found")]
8 AccessorNotFound(u64),
9 #[error("BufferView {0} not found")]
10 BufferViewNotFound(u64),
11 #[error("Accessor {0} has no bufferView (may be Draco-compressed)")]
12 NoBufferView(u64),
13 #[error("Buffer index {0} out of range")]
14 BufferOutOfRange(u64),
15 #[error("Buffer read out of bounds: offset {offset}, size {size}, buffer len {buffer_len}")]
16 OutOfBounds {
17 offset: usize,
18 size: usize,
19 buffer_len: usize,
20 },
21 #[error("Unsupported component type: {0}")]
22 UnsupportedComponentType(u32),
23 #[error("Unsupported accessor type: {0}")]
24 UnsupportedAccessorType(String),
25 #[error("Missing required field: {0}")]
26 MissingField(String),
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum ComponentType {
31 Byte = 5120,
32 UnsignedByte = 5121,
33 Short = 5122,
34 UnsignedShort = 5123,
35 UnsignedInt = 5125,
36 Float = 5126,
37}
38
39impl ComponentType {
40 pub fn from_u32(value: u32) -> Result<Self, Error> {
41 match value {
42 5120 => Ok(Self::Byte),
43 5121 => Ok(Self::UnsignedByte),
44 5122 => Ok(Self::Short),
45 5123 => Ok(Self::UnsignedShort),
46 5125 => Ok(Self::UnsignedInt),
47 5126 => Ok(Self::Float),
48 _ => Err(Error::UnsupportedComponentType(value)),
49 }
50 }
51
52 pub fn byte_size(self) -> usize {
53 match self {
54 Self::Byte | Self::UnsignedByte => 1,
55 Self::Short | Self::UnsignedShort => 2,
56 Self::UnsignedInt | Self::Float => 4,
57 }
58 }
59}
60
61#[derive(Debug, Clone)]
62pub struct AccessorInfo {
63 pub buffer_view_idx: u64,
64 pub byte_offset: usize,
65 pub component_type: ComponentType,
66 pub count: usize,
67 pub accessor_type: String,
68}
69
70#[derive(Debug, Clone)]
71pub struct BufferViewInfo {
72 pub buffer_idx: u64,
73 pub byte_offset: usize,
74 pub byte_length: usize,
75 pub byte_stride: Option<usize>,
76}
77
78pub fn get_accessor_info(json: &Value, accessor_idx: u64) -> Result<AccessorInfo, Error> {
79 let accessor = json
80 .get("accessors")
81 .and_then(|a| a.get(accessor_idx as usize))
82 .ok_or(Error::AccessorNotFound(accessor_idx))?;
83
84 let buffer_view_idx = accessor
85 .get("bufferView")
86 .and_then(|v| v.as_u64())
87 .ok_or(Error::NoBufferView(accessor_idx))?;
88
89 let byte_offset = accessor
90 .get("byteOffset")
91 .and_then(|v| v.as_u64())
92 .unwrap_or(0) as usize;
93 let component_type_raw = accessor
94 .get("componentType")
95 .and_then(|v| v.as_u64())
96 .ok_or_else(|| Error::MissingField("accessor.componentType".into()))?
97 as u32;
98 let component_type = ComponentType::from_u32(component_type_raw)?;
99 let count = accessor
100 .get("count")
101 .and_then(|v| v.as_u64())
102 .ok_or_else(|| Error::MissingField("accessor.count".into()))? as usize;
103 let accessor_type = accessor
104 .get("type")
105 .and_then(|v| v.as_str())
106 .ok_or_else(|| Error::MissingField("accessor.type".into()))?
107 .to_string();
108
109 Ok(AccessorInfo {
110 buffer_view_idx,
111 byte_offset,
112 component_type,
113 count,
114 accessor_type,
115 })
116}
117
118pub fn get_buffer_view_info(json: &Value, buffer_view_idx: u64) -> Result<BufferViewInfo, Error> {
119 let bv = json
120 .get("bufferViews")
121 .and_then(|b| b.get(buffer_view_idx as usize))
122 .ok_or(Error::BufferViewNotFound(buffer_view_idx))?;
123
124 let buffer_idx = bv
125 .get("buffer")
126 .and_then(|v| v.as_u64())
127 .ok_or_else(|| Error::MissingField("bufferView.buffer".into()))?;
128 let byte_offset = bv.get("byteOffset").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
129 let byte_length =
130 bv.get("byteLength")
131 .and_then(|v| v.as_u64())
132 .ok_or_else(|| Error::MissingField("bufferView.byteLength".into()))? as usize;
133 let byte_stride = bv
134 .get("byteStride")
135 .and_then(|v| v.as_u64())
136 .map(|v| v as usize);
137
138 Ok(BufferViewInfo {
139 buffer_idx,
140 byte_offset,
141 byte_length,
142 byte_stride,
143 })
144}
145
146fn component_count(accessor_type: &str) -> Result<usize, Error> {
147 match accessor_type {
148 "SCALAR" => Ok(1),
149 "VEC2" => Ok(2),
150 "VEC3" => Ok(3),
151 "VEC4" => Ok(4),
152 "MAT2" => Ok(4),
153 "MAT3" => Ok(9),
154 "MAT4" => Ok(16),
155 _ => Err(Error::UnsupportedAccessorType(accessor_type.to_string())),
156 }
157}
158
159pub fn read_accessor_as_f32(
160 json: &Value,
161 buffer: &[u8],
162 accessor_idx: u64,
163) -> Result<Vec<f32>, Error> {
164 let accessor = get_accessor_info(json, accessor_idx)?;
165 let buffer_view = get_buffer_view_info(json, accessor.buffer_view_idx)?;
166
167 if buffer_view.buffer_idx != 0 {
168 return Err(Error::BufferOutOfRange(buffer_view.buffer_idx));
169 }
170
171 let num_components = component_count(&accessor.accessor_type)?;
172 let element_size = accessor.component_type.byte_size() * num_components;
173 let stride = buffer_view.byte_stride.unwrap_or(element_size);
174 let base_offset = buffer_view.byte_offset + accessor.byte_offset;
175
176 let mut result = Vec::with_capacity(accessor.count * num_components);
177
178 for i in 0..accessor.count {
179 let element_offset = base_offset + i * stride;
180 for c in 0..num_components {
181 let offset = element_offset + c * accessor.component_type.byte_size();
182 let value = read_component_as_f32(buffer, offset, accessor.component_type)?;
183 result.push(value);
184 }
185 }
186
187 Ok(result)
188}
189
190pub fn read_accessor_as_u32(
191 json: &Value,
192 buffer: &[u8],
193 accessor_idx: u64,
194) -> Result<Vec<u32>, Error> {
195 let accessor = get_accessor_info(json, accessor_idx)?;
196 let buffer_view = get_buffer_view_info(json, accessor.buffer_view_idx)?;
197
198 if buffer_view.buffer_idx != 0 {
199 return Err(Error::BufferOutOfRange(buffer_view.buffer_idx));
200 }
201
202 let element_size = accessor.component_type.byte_size();
203 let stride = buffer_view.byte_stride.unwrap_or(element_size);
204 let base_offset = buffer_view.byte_offset + accessor.byte_offset;
205
206 let mut result = Vec::with_capacity(accessor.count);
207
208 for i in 0..accessor.count {
209 let offset = base_offset + i * stride;
210 let value = read_component_as_u32(buffer, offset, accessor.component_type)?;
211 result.push(value);
212 }
213
214 Ok(result)
215}
216
217fn read_component_as_f32(buffer: &[u8], offset: usize, ct: ComponentType) -> Result<f32, Error> {
218 let size = ct.byte_size();
219 if offset + size > buffer.len() {
220 return Err(Error::OutOfBounds {
221 offset,
222 size,
223 buffer_len: buffer.len(),
224 });
225 }
226
227 Ok(match ct {
228 ComponentType::Byte => buffer[offset] as i8 as f32,
229 ComponentType::UnsignedByte => buffer[offset] as f32,
230 ComponentType::Short => i16::from_le_bytes([buffer[offset], buffer[offset + 1]]) as f32,
231 ComponentType::UnsignedShort => {
232 u16::from_le_bytes([buffer[offset], buffer[offset + 1]]) as f32
233 }
234 ComponentType::UnsignedInt => u32::from_le_bytes([
235 buffer[offset],
236 buffer[offset + 1],
237 buffer[offset + 2],
238 buffer[offset + 3],
239 ]) as f32,
240 ComponentType::Float => f32::from_le_bytes([
241 buffer[offset],
242 buffer[offset + 1],
243 buffer[offset + 2],
244 buffer[offset + 3],
245 ]),
246 })
247}
248
249fn read_component_as_u32(buffer: &[u8], offset: usize, ct: ComponentType) -> Result<u32, Error> {
250 let size = ct.byte_size();
251 if offset + size > buffer.len() {
252 return Err(Error::OutOfBounds {
253 offset,
254 size,
255 buffer_len: buffer.len(),
256 });
257 }
258
259 Ok(match ct {
260 ComponentType::Byte => buffer[offset] as i8 as u32,
261 ComponentType::UnsignedByte => buffer[offset] as u32,
262 ComponentType::Short => i16::from_le_bytes([buffer[offset], buffer[offset + 1]]) as u32,
263 ComponentType::UnsignedShort => {
264 u16::from_le_bytes([buffer[offset], buffer[offset + 1]]) as u32
265 }
266 ComponentType::UnsignedInt => u32::from_le_bytes([
267 buffer[offset],
268 buffer[offset + 1],
269 buffer[offset + 2],
270 buffer[offset + 3],
271 ]),
272 ComponentType::Float => f32::from_le_bytes([
273 buffer[offset],
274 buffer[offset + 1],
275 buffer[offset + 2],
276 buffer[offset + 3],
277 ]) as u32,
278 })
279}
280
281pub fn read_accessor_as_vec3(
282 json: &Value,
283 buffer: &[u8],
284 accessor_idx: u64,
285) -> Result<Vec<[f32; 3]>, Error> {
286 let flat = read_accessor_as_f32(json, buffer, accessor_idx)?;
287 Ok(flat.chunks(3).map(|c| [c[0], c[1], c[2]]).collect())
288}
289
290pub fn read_accessor_as_vec2(
291 json: &Value,
292 buffer: &[u8],
293 accessor_idx: u64,
294) -> Result<Vec<[f32; 2]>, Error> {
295 let flat = read_accessor_as_f32(json, buffer, accessor_idx)?;
296 Ok(flat.chunks(2).map(|c| [c[0], c[1]]).collect())
297}
298
299pub fn read_accessor_as_vec4(
300 json: &Value,
301 buffer: &[u8],
302 accessor_idx: u64,
303) -> Result<Vec<[f32; 4]>, Error> {
304 let flat = read_accessor_as_f32(json, buffer, accessor_idx)?;
305 Ok(flat.chunks(4).map(|c| [c[0], c[1], c[2], c[3]]).collect())
306}
307
308pub fn read_accessor_as_scalar_f32(
309 json: &Value,
310 buffer: &[u8],
311 accessor_idx: u64,
312) -> Result<Vec<f32>, Error> {
313 let accessor = get_accessor_info(json, accessor_idx)?;
314 let buffer_view = get_buffer_view_info(json, accessor.buffer_view_idx)?;
315
316 if buffer_view.buffer_idx != 0 {
317 return Err(Error::BufferOutOfRange(buffer_view.buffer_idx));
318 }
319
320 let element_size = accessor.component_type.byte_size();
321 let stride = buffer_view.byte_stride.unwrap_or(element_size);
322 let base_offset = buffer_view.byte_offset + accessor.byte_offset;
323
324 let mut result = Vec::with_capacity(accessor.count);
325
326 for i in 0..accessor.count {
327 let offset = base_offset + i * stride;
328 let value = read_component_as_f32(buffer, offset, accessor.component_type)?;
329 result.push(value);
330 }
331
332 Ok(result)
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338 use serde_json::json;
339
340 #[test]
341 fn test_read_vec3() {
342 let json = json!({
343 "accessors": [{ "bufferView": 0, "byteOffset": 0, "componentType": 5126, "count": 3, "type": "VEC3" }],
344 "bufferViews": [{ "buffer": 0, "byteOffset": 0, "byteLength": 36 }]
345 });
346
347 let mut buffer = Vec::new();
348 for v in [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] {
349 buffer.extend_from_slice(&v.to_le_bytes());
350 }
351
352 let positions = read_accessor_as_vec3(&json, &buffer, 0).unwrap();
353 assert_eq!(positions.len(), 3);
354 assert_eq!(positions[0], [1.0, 2.0, 3.0]);
355 assert_eq!(positions[1], [4.0, 5.0, 6.0]);
356 }
357}