1use crate::{Document, Error, ResourceStore, Result};
2use draco_core::draco_types::DataType;
3use draco_io::{AccessorSource, DecodedAccessor, GltfError};
4
5pub struct DocumentAccessorSource<'a> {
7 document: &'a Document,
8 resources: &'a ResourceStore,
9}
10
11#[derive(Clone, Debug)]
13pub struct AccessorData {
14 pub count: usize,
16 pub accessor_type: String,
18 pub components: u8,
20 pub component_type: u32,
22 pub data_type: DataType,
24 pub normalized: bool,
26 pub bytes: Vec<u8>,
31}
32
33#[derive(Clone, Copy)]
34struct AccessorLayout {
35 tight_width: usize,
36 source_width: usize,
37 columns: usize,
38 column_width: usize,
39 column_stride: usize,
40}
41
42impl<'a> DocumentAccessorSource<'a> {
43 pub fn new(document: &'a Document, resources: &'a ResourceStore) -> Self {
45 Self {
46 document,
47 resources,
48 }
49 }
50
51 pub fn read_buffer_view(&self, index: usize) -> Result<Vec<u8>> {
57 let view = self
58 .document
59 .as_value()
60 .get("bufferViews")
61 .and_then(|value| value.as_array())
62 .and_then(|values| values.get(index))
63 .ok_or_else(|| Error::Extension("bufferView out of range".into()))?;
64 let buffer = view
65 .get("buffer")
66 .and_then(|value| value.as_u64())
67 .and_then(|value| usize::try_from(value).ok())
68 .and_then(|index| self.resources.buffers.get(index))
69 .ok_or_else(|| Error::Extension("buffer is not resolved".into()))?;
70 let start = view
71 .get("byteOffset")
72 .and_then(|value| value.as_u64())
73 .unwrap_or(0);
74 let length = view
75 .get("byteLength")
76 .and_then(|value| value.as_u64())
77 .ok_or_else(|| Error::Extension("bufferView byteLength is invalid".into()))?;
78 let end = start
79 .checked_add(length)
80 .ok_or_else(|| Error::ResourceLimit("bufferView range overflow".into()))?;
81 let start = usize::try_from(start).map_err(|_| {
82 Error::ResourceLimit("bufferView offset exceeds platform limits".into())
83 })?;
84 let end = usize::try_from(end)
85 .map_err(|_| Error::ResourceLimit("bufferView end exceeds platform limits".into()))?;
86 let bytes = buffer
87 .get(start..end)
88 .ok_or_else(|| Error::Extension("bufferView range is out of bounds".into()))?;
89 let mut output = Vec::new();
90 output.try_reserve_exact(bytes.len()).map_err(|_| {
91 Error::ResourceLimit("bufferView materialization allocation failed".into())
92 })?;
93 output.extend_from_slice(bytes);
94 Ok(output)
95 }
96
97 fn read<const MATRICES: bool>(
98 &self,
99 index: usize,
100 ) -> Result<(usize, u8, u32, DataType, bool, Vec<u8>)> {
101 let accessor = self
102 .document
103 .as_value()
104 .get("accessors")
105 .and_then(|v| v.as_array())
106 .and_then(|v| v.get(index))
107 .ok_or_else(|| Error::Extension("accessor out of range".into()))?;
108 let count = accessor
109 .get("count")
110 .and_then(|v| v.as_u64())
111 .and_then(|v| usize::try_from(v).ok())
112 .ok_or_else(|| Error::Extension("accessor count is invalid".into()))?;
113 let accessor_type = accessor
114 .get("type")
115 .and_then(|value| value.as_str())
116 .ok_or_else(|| Error::Extension("accessor type is invalid".into()))?;
117 let components = match accessor_type {
118 "SCALAR" => 1,
119 "VEC2" => 2,
120 "VEC3" => 3,
121 "VEC4" => 4,
122 "MAT2" if MATRICES => 4,
123 "MAT3" if MATRICES => 9,
124 "MAT4" if MATRICES => 16,
125 _ => return Err(Error::Extension("accessor type is invalid".into())),
126 };
127 let component = accessor
128 .get("componentType")
129 .and_then(|v| v.as_u64())
130 .ok_or_else(|| Error::Extension("accessor componentType is invalid".into()))?;
131 let data_type = match component {
132 5120 => DataType::Int8,
133 5121 => DataType::Uint8,
134 5122 => DataType::Int16,
135 5123 => DataType::Uint16,
136 5125 => DataType::Uint32,
137 5126 => DataType::Float32,
138 5124 => DataType::Int32,
139 5131 => DataType::Uint16,
142 5130 => DataType::Float64,
143 5134 => DataType::Int64,
144 5135 => DataType::Uint64,
145 _ => {
146 return Err(Error::Extension(
147 "unsupported accessor component type".into(),
148 ))
149 }
150 };
151 let layout = accessor_layout::<MATRICES>(accessor_type, data_type.byte_length())?;
152 let width = layout.tight_width;
153 let byte_len = count
154 .checked_mul(width)
155 .ok_or_else(|| Error::ResourceLimit("accessor byte size overflow".into()))?;
156 let mut bytes = if let Some(view) = accessor
157 .get("bufferView")
158 .and_then(|value| value.as_u64())
159 .and_then(|value| usize::try_from(value).ok())
160 {
161 let accessor_offset = accessor
162 .get("byteOffset")
163 .and_then(|value| value.as_u64())
164 .unwrap_or(0);
165 let (buffer, offset, stride) =
166 self.buffer_view_layout(view, accessor_offset, layout.source_width)?;
167 let mut dense = Vec::new();
168 dense.try_reserve_exact(byte_len).map_err(|_| {
169 Error::ResourceLimit("accessor materialization allocation failed".into())
170 })?;
171 for row in 0..count {
172 let start =
173 offset
174 .checked_add(row.checked_mul(stride).ok_or_else(|| {
175 Error::ResourceLimit("accessor stride overflow".into())
176 })?)
177 .ok_or_else(|| Error::ResourceLimit("accessor offset overflow".into()))?;
178 copy_accessor_element(buffer, start, layout, &mut dense)?;
179 }
180 dense
181 } else if accessor.get("sparse").is_some() {
182 vec![0; byte_len]
183 } else {
184 return Err(Error::Extension(
185 "accessor has neither bufferView nor sparse values".into(),
186 ));
187 };
188 if let Some(sparse) = accessor.get("sparse") {
189 self.apply_sparse(sparse, count, layout, &mut bytes)?;
190 }
191 Ok((
192 count,
193 components,
194 component as u32,
195 data_type,
196 accessor
197 .get("normalized")
198 .and_then(|v| {
199 if let crate::JsonValue::Bool(v) = v {
200 Some(*v)
201 } else {
202 None
203 }
204 })
205 .unwrap_or(false),
206 bytes,
207 ))
208 }
209
210 fn buffer_view_layout(
211 &self,
212 view_index: usize,
213 additional_offset: u64,
214 default_stride: usize,
215 ) -> Result<(&[u8], usize, usize)> {
216 let view = self
217 .document
218 .as_value()
219 .get("bufferViews")
220 .and_then(|value| value.as_array())
221 .and_then(|values| values.get(view_index))
222 .ok_or_else(|| Error::Extension("bufferView out of range".into()))?;
223 let buffer = view
224 .get("buffer")
225 .and_then(|value| value.as_u64())
226 .and_then(|value| usize::try_from(value).ok())
227 .and_then(|index| self.resources.buffers.get(index))
228 .ok_or_else(|| Error::Extension("buffer is not resolved".into()))?;
229 let offset = view
230 .get("byteOffset")
231 .and_then(|value| value.as_u64())
232 .unwrap_or(0)
233 .checked_add(additional_offset)
234 .and_then(|value| usize::try_from(value).ok())
235 .ok_or_else(|| Error::ResourceLimit("bufferView offset is invalid".into()))?;
236 let stride = view
237 .get("byteStride")
238 .and_then(|value| value.as_u64())
239 .and_then(|value| usize::try_from(value).ok())
240 .unwrap_or(default_stride);
241 if stride < default_stride {
242 return Err(Error::Extension(
243 "bufferView byteStride is too small".into(),
244 ));
245 }
246 Ok((buffer, offset, stride))
247 }
248
249 fn apply_sparse(
250 &self,
251 sparse: &crate::JsonValue,
252 count: usize,
253 layout: AccessorLayout,
254 bytes: &mut [u8],
255 ) -> Result<()> {
256 let sparse_count = sparse
257 .get("count")
258 .and_then(|value| value.as_u64())
259 .and_then(|value| usize::try_from(value).ok())
260 .filter(|value| *value <= count)
261 .ok_or_else(|| Error::Extension("sparse accessor count is invalid".into()))?;
262 let indices = sparse
263 .get("indices")
264 .ok_or_else(|| Error::Extension("sparse accessor indices are missing".into()))?;
265 let index_view = indices
266 .get("bufferView")
267 .and_then(|value| value.as_u64())
268 .and_then(|value| usize::try_from(value).ok())
269 .ok_or_else(|| Error::Extension("sparse indices bufferView is invalid".into()))?;
270 let index_type = indices
271 .get("componentType")
272 .and_then(|value| value.as_u64())
273 .ok_or_else(|| Error::Extension("sparse indices componentType is invalid".into()))?;
274 let index_width = match index_type {
275 5121 => 1,
276 5123 => 2,
277 5125 => 4,
278 _ => {
279 return Err(Error::Extension(
280 "sparse indices componentType is invalid".into(),
281 ))
282 }
283 };
284 let index_offset = indices
285 .get("byteOffset")
286 .and_then(|value| value.as_u64())
287 .unwrap_or(0);
288 let (index_buffer, index_start, _) =
289 self.buffer_view_layout(index_view, index_offset, index_width)?;
290 let values = sparse
291 .get("values")
292 .ok_or_else(|| Error::Extension("sparse accessor values are missing".into()))?;
293 let value_view = values
294 .get("bufferView")
295 .and_then(|value| value.as_u64())
296 .and_then(|value| usize::try_from(value).ok())
297 .ok_or_else(|| Error::Extension("sparse values bufferView is invalid".into()))?;
298 let value_offset = values
299 .get("byteOffset")
300 .and_then(|value| value.as_u64())
301 .unwrap_or(0);
302 let (value_buffer, value_start, value_stride) =
303 self.buffer_view_layout(value_view, value_offset, layout.source_width)?;
304 let mut previous = None;
305 for entry in 0..sparse_count {
306 let index_start =
307 index_start
308 .checked_add(entry.checked_mul(index_width).ok_or_else(|| {
309 Error::ResourceLimit("sparse index offset overflow".into())
310 })?)
311 .ok_or_else(|| Error::ResourceLimit("sparse index offset overflow".into()))?;
312 let index_end = index_start
313 .checked_add(index_width)
314 .filter(|end| *end <= index_buffer.len())
315 .ok_or_else(|| Error::Extension("sparse indices are out of bounds".into()))?;
316 let index = match index_type {
317 5121 => index_buffer[index_start] as usize,
318 5123 => {
319 u16::from_le_bytes(index_buffer[index_start..index_end].try_into().unwrap())
320 as usize
321 }
322 5125 => {
323 u32::from_le_bytes(index_buffer[index_start..index_end].try_into().unwrap())
324 as usize
325 }
326 _ => unreachable!(),
327 };
328 if index >= count || previous.is_some_and(|previous| index <= previous) {
329 return Err(Error::Extension(
330 "sparse indices must be strictly increasing".into(),
331 ));
332 }
333 previous = Some(index);
334 let value_start =
335 value_start
336 .checked_add(entry.checked_mul(value_stride).ok_or_else(|| {
337 Error::ResourceLimit("sparse value offset overflow".into())
338 })?)
339 .ok_or_else(|| Error::ResourceLimit("sparse value offset overflow".into()))?;
340 let destination_start = index
341 .checked_mul(layout.tight_width)
342 .ok_or_else(|| Error::ResourceLimit("sparse value offset overflow".into()))?;
343 let destination_end = destination_start
344 .checked_add(layout.tight_width)
345 .ok_or_else(|| Error::ResourceLimit("sparse value offset overflow".into()))?;
346 copy_accessor_element_into(
347 value_buffer,
348 value_start,
349 layout,
350 &mut bytes[destination_start..destination_end],
351 )?;
352 }
353 Ok(())
354 }
355
356 #[cfg(feature = "accessors")]
358 pub fn read_accessor(&self, index: usize) -> Result<AccessorData> {
359 self.read_accessor_inner::<true>(index)
360 }
361
362 pub(crate) fn read_geometry_accessor(&self, index: usize) -> Result<AccessorData> {
363 self.read_accessor_inner::<false>(index)
364 }
365
366 fn read_accessor_inner<const MATRICES: bool>(&self, index: usize) -> Result<AccessorData> {
367 let (count, components, component_type, data_type, normalized, bytes) =
368 self.read::<MATRICES>(index)?;
369 let accessor_type = self
370 .document
371 .as_value()
372 .get("accessors")
373 .and_then(|value| value.as_array())
374 .and_then(|values| values.get(index))
375 .and_then(|value| value.get("type"))
376 .and_then(|value| value.as_str())
377 .ok_or_else(|| Error::Extension("accessor type is invalid".into()))?
378 .to_owned();
379 Ok(AccessorData {
380 count,
381 accessor_type,
382 components,
383 component_type,
384 data_type,
385 normalized,
386 bytes,
387 })
388 }
389}
390
391fn accessor_layout<const MATRICES: bool>(
392 accessor_type: &str,
393 component_width: usize,
394) -> Result<AccessorLayout> {
395 let (columns, rows) = match accessor_type {
396 "SCALAR" => (1, 1),
397 "VEC2" => (1, 2),
398 "VEC3" => (1, 3),
399 "VEC4" => (1, 4),
400 "MAT2" if MATRICES => (2, 2),
401 "MAT3" if MATRICES => (3, 3),
402 "MAT4" if MATRICES => (4, 4),
403 _ => return Err(Error::Extension("accessor type is invalid".into())),
404 };
405 let column_width = rows * component_width;
406 let column_stride = if columns > 1 && component_width < 4 {
407 column_width
408 .checked_add(3)
409 .map(|width| width & !3)
410 .ok_or_else(|| Error::ResourceLimit("accessor column size overflow".into()))?
411 } else {
412 column_width
413 };
414 Ok(AccessorLayout {
415 tight_width: columns * column_width,
416 source_width: columns * column_stride,
417 columns,
418 column_width,
419 column_stride,
420 })
421}
422
423fn copy_accessor_element(
424 source: &[u8],
425 start: usize,
426 layout: AccessorLayout,
427 destination: &mut Vec<u8>,
428) -> Result<()> {
429 let destination_start = destination.len();
430 destination
431 .try_reserve_exact(layout.tight_width)
432 .map_err(|_| Error::ResourceLimit("accessor materialization allocation failed".into()))?;
433 let destination_end = destination_start
434 .checked_add(layout.tight_width)
435 .ok_or_else(|| Error::ResourceLimit("accessor materialization size overflow".into()))?;
436 destination.resize(destination_end, 0);
437 copy_accessor_element_into(source, start, layout, &mut destination[destination_start..])
438}
439
440fn copy_accessor_element_into(
441 source: &[u8],
442 start: usize,
443 layout: AccessorLayout,
444 destination: &mut [u8],
445) -> Result<()> {
446 if destination.len() != layout.tight_width {
447 return Err(Error::ResourceLimit(
448 "accessor materialization size mismatch".into(),
449 ));
450 }
451 for column in 0..layout.columns {
452 let column_start =
453 start
454 .checked_add(column.checked_mul(layout.column_stride).ok_or_else(|| {
455 Error::ResourceLimit("accessor column offset overflow".into())
456 })?)
457 .ok_or_else(|| Error::ResourceLimit("accessor column offset overflow".into()))?;
458 let column_end = column_start
459 .checked_add(layout.column_width)
460 .filter(|end| *end <= source.len())
461 .ok_or_else(|| Error::Extension("accessor range is out of bounds".into()))?;
462 let destination_start = column * layout.column_width;
463 let destination_end = destination_start + layout.column_width;
464 destination[destination_start..destination_end]
465 .copy_from_slice(&source[column_start..column_end]);
466 }
467 Ok(())
468}
469impl AccessorSource for DocumentAccessorSource<'_> {
470 fn read_attribute(
471 &self,
472 index: usize,
473 expected: &[&str],
474 allowed: &[u32],
475 ) -> std::result::Result<DecodedAccessor, GltfError> {
476 let (count, c, _, t, n, b) = self
477 .read::<false>(index)
478 .map_err(|e| GltfError::InvalidGltf(e.to_string()))?;
479 let a = &self.document.as_value()["accessors"][index];
480 if !expected.contains(&a.get("type").and_then(|v| v.as_str()).unwrap_or(""))
481 || !allowed
482 .contains(&(a.get("componentType").and_then(|v| v.as_u64()).unwrap_or(0) as u32))
483 {
484 return Err(GltfError::Unsupported(
485 "accessor layout is not permitted".into(),
486 ));
487 };
488 DecodedAccessor::new(count, c, t, n, b)
489 }
490 fn read_indices(&self, index: usize) -> std::result::Result<Vec<u32>, GltfError> {
491 let (count, c, component_type, t, _, b) = self
492 .read::<false>(index)
493 .map_err(|e| GltfError::InvalidGltf(e.to_string()))?;
494 if c != 1 {
495 return Err(GltfError::InvalidGltf("indices must be SCALAR".into()));
496 }
497 if !matches!(component_type, 5121 | 5123 | 5125) {
498 return Err(GltfError::Unsupported("index component type".into()));
499 }
500 let w = t.byte_length();
501 (0..count)
502 .map(|i| {
503 let s = &b[i * w..(i + 1) * w];
504 Ok(match t {
505 DataType::Uint8 => s[0] as u32,
506 DataType::Uint16 => u16::from_le_bytes([s[0], s[1]]) as u32,
507 DataType::Uint32 => u32::from_le_bytes([s[0], s[1], s[2], s[3]]),
508 _ => return Err(GltfError::Unsupported("index component type".into())),
509 })
510 })
511 .collect()
512 }
513}