Skip to content

Commit

Permalink
Add sparse accessor iterators
Browse files Browse the repository at this point in the history
  • Loading branch information
David Harvey-Macaulay committed Sep 20, 2019
1 parent 4b30f52 commit 16d807e
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 190 deletions.
9 changes: 4 additions & 5 deletions src/accessor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,14 @@
//! [`mesh::Reader`]: ../mesh/struct.Reader.html
//!
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
//! # use gltf::accessor::{DataType, Dimensions, Iter};
//! let (gltf, buffers, _) = gltf::import("examples/Box.gltf")?;
//! let get_buffer_data = |buffer: gltf::Buffer| buffers.get(buffer.index()).map(|x| &*x.0);
//! for accessor in gltf.accessors() {
//! match (accessor.data_type(), accessor.dimensions()) {
//! (DataType::F32, Dimensions::Vec3) => {
//! let buffer_index = accessor.view().buffer().index();
//! let buffer_data = buffers[buffer_index].0.as_slice();
//! let iter = Iter::<[f32; 3]>::new(accessor, buffer_data);
//! let iter = Iter::<[f32; 3]>::new(accessor, get_buffer_data);
//! for item in iter {
//! println!("{:?}", item);
//! }
Expand Down Expand Up @@ -163,7 +162,7 @@ impl<'a> Accessor<'a> {

/// Returns sparse storage of attributes that deviate from their initialization
/// value.
pub fn sparse(&self) -> Option<sparse::Sparse> {
pub fn sparse(&self) -> Option<sparse::Sparse<'a>> {
self.json.sparse.as_ref().map(|json| {
sparse::Sparse::new(self.document, json)
})
Expand Down
2 changes: 1 addition & 1 deletion src/accessor/sparse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl<'a> Values<'a> {
}

/// Returns the buffer view containing the sparse values.
pub fn view(&self) -> buffer::View {
pub fn view(&self) -> buffer::View<'a> {
self.document.views().nth(self.json.buffer_view.value()).unwrap()
}

Expand Down
219 changes: 198 additions & 21 deletions src/accessor/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,117 @@
use std::mem;
use std::{iter, mem};
use byteorder::{LE, ByteOrder};
use std::marker::PhantomData;

use crate::{accessor, buffer};

fn buffer_view_slice<'a, 's>(
view: buffer::View<'a>,
get_buffer_data: &dyn Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
) -> Option<&'s [u8]> {
let start = view.offset();
let end = start + view.length();
get_buffer_data(view.buffer())
.map(|slice| &slice[start..end])
}

/// General iterator for an accessor.
#[derive(Clone, Debug)]
pub enum Iter<'a, T: Item> {
/// Standard accessor iterator.
Standard(ItemIter<'a, T>),

/// Iterator for accessor with sparse values.
Sparse(SparseIter<'a, T>),
}

impl<'a, T: Item> Iterator for Iter<'a, T> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
match self {
&mut Iter::Standard(ref mut iter) => iter.next(),
&mut Iter::Sparse(ref mut iter) => iter.next(),
}
}
}

/// Iterator over indices of sparse accessor.
#[derive(Clone, Debug)]
pub enum SparseIndicesIter<'a> {
/// 8-bit indices.
U8(ItemIter<'a, u8>),
/// 16-bit indices.
U16(ItemIter<'a, u16>),
/// 32-bit indices.
U32(ItemIter<'a, u32>),
}

impl<'a> Iterator for SparseIndicesIter<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
match *self {
SparseIndicesIter::U8(ref mut iter) => iter.next().map(|x| x as u32),
SparseIndicesIter::U16(ref mut iter) => iter.next().map(|x| x as u32),
SparseIndicesIter::U32(ref mut iter) => iter.next(),
}
}
}

/// Iterates over a sparse accessor.
#[derive(Clone, Debug)]
pub struct SparseIter<'a, T: Item> {
/// Base value iterator.
base: ItemIter<'a, T>,

/// Sparse indices iterator.
indices: iter::Peekable<SparseIndicesIter<'a>>,

/// Sparse values iterator.
values: ItemIter<'a, T>,

/// Iterator counter.
counter: u32,
}

impl<'a, T: Item> SparseIter<'a, T> {
/// Constructor.
pub fn new(
base: ItemIter<'a, T>,
indices: SparseIndicesIter<'a>,
values: ItemIter<'a, T>,
) -> Self {
SparseIter {
base: base,
indices: indices.peekable(),
values: values,
counter: 0,
}
}
}

impl<'a, T: Item> Iterator for SparseIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let next_base_value = self.base.next();
if next_base_value.is_none() {
return None;
}

let mut next_value = next_base_value.unwrap();
let next_sparse_index = self.indices.peek().clone();
if let Some(index) = next_sparse_index {
if *index == self.counter {
self.indices.next(); // advance
next_value = self.values.next().unwrap();
}
}

self.counter += 1;

Some(next_value)
}
}

/// Represents items that can be read by an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
Expand All @@ -14,7 +124,7 @@ pub trait Item {
///
/// [`Accessor`]: struct.Accessor.html
#[derive(Copy, Clone, Debug)]
pub struct Iter<'a, T> {
pub struct ItemIter<'a, T: Item> {
stride: usize,
data: &'a [u8],
_phantom: PhantomData<T>,
Expand Down Expand Up @@ -83,26 +193,93 @@ impl<T: Item> Item for [T; 4] {
}
}

impl<'a, T> Iter<'a, T> {
impl<'a, T: Item> ItemIter<'a, T> {
/// Constructor.
pub fn new(
accessor: super::Accessor,
buffer_data: &'a [u8],
) -> Iter<'a, T> {
debug_assert_eq!(mem::size_of::<T>(), accessor.size());
debug_assert!(mem::size_of::<T>() > 0);
let view = accessor.view();
let stride = view.stride().unwrap_or(mem::size_of::<T>());
debug_assert!(stride >= mem::size_of::<T>(), "Mismatch in stride, expected at least {} stride but found {}", mem::size_of::<T>(), stride);
let start = view.offset() + accessor.offset();
let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
let data = &buffer_data[start .. end];
Iter { stride, data, _phantom: PhantomData }
}
}

impl<'a, T: Item> ExactSizeIterator for Iter<'a, T> {}
impl<'a, T: Item> Iterator for Iter<'a, T> {
pub fn new(slice: &'a [u8], stride: usize) -> Self {
ItemIter {
data: slice,
stride: stride,
_phantom: PhantomData,
}
}
}

impl<'a, 's, T: Item> Iter<'s, T> {
/// Constructor.
pub fn new<F>(
accessor: super::Accessor<'a>,
get_buffer_data: F,
) -> Option<Iter<'s, T>>
where F: Clone + Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
{
let is_sparse = accessor.sparse().is_some();
if is_sparse {
let sparse = accessor.sparse();
let indices = sparse.as_ref().unwrap().indices();
let values = sparse.as_ref().unwrap().values();
let base_iter = {
let view = accessor.view();
let stride = view.stride().unwrap_or(mem::size_of::<T>());
let start = accessor.offset();
let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
&slice[start..end]
} else {
return None
};
ItemIter::new(subslice, stride)
};
let sparse_count = sparse.as_ref().unwrap().count() as usize;
let index_iter = {
let view = indices.view();
let index_size = indices.index_type().size();
let stride = view.stride().unwrap_or(index_size);
let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
let start = indices.offset() as usize;
let end = start + stride * (sparse_count - 1) + index_size;
&slice[start..end]
} else {
return None
};
match indices.index_type() {
accessor::sparse::IndexType::U8 => SparseIndicesIter::U8(ItemIter::new(subslice, stride)),
accessor::sparse::IndexType::U16 => SparseIndicesIter::U16(ItemIter::new(subslice, stride)),
accessor::sparse::IndexType::U32 => SparseIndicesIter::U32(ItemIter::new(subslice, stride)),
}
};
let value_iter = {
let view = values.view();
let stride = view.stride().unwrap_or(mem::size_of::<T>());
let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
let start = values.offset() as usize;
let end = start + stride * (sparse_count - 1) + mem::size_of::<T>();
&slice[start..end]
} else {
return None
};
ItemIter::new(subslice, stride)
};
Some(Iter::Sparse(SparseIter::new(base_iter, index_iter, value_iter)))
} else {
debug_assert_eq!(mem::size_of::<T>(), accessor.size());
debug_assert!(mem::size_of::<T>() > 0);
let view = accessor.view();
let stride = view.stride().unwrap_or(mem::size_of::<T>());
debug_assert!(stride >= mem::size_of::<T>(), "Mismatch in stride, expected at least {} stride but found {}", mem::size_of::<T>(), stride);
let start = accessor.offset();
let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
&slice[start..end]
} else {
return None
};
Some(Iter::Standard(ItemIter { stride, data: subslice, _phantom: PhantomData }))
}
}
}

impl<'a, T: Item> ExactSizeIterator for ItemIter<'a, T> {}
impl<'a, T: Item> Iterator for ItemIter<'a, T> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
Expand Down
54 changes: 23 additions & 31 deletions src/animation/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,45 +141,37 @@ where F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
{
/// Visits the input samples of a channel.
pub fn read_inputs(&self) -> Option<ReadInputs<'s>> {
let buffer = self.channel.sampler().input().view().buffer();
if let Some(slice) = (self.get_buffer_data)(buffer) {
Some(accessor::Iter::new(self.channel.sampler().input(), slice))
} else {
None
}
accessor::Iter::new(self.channel.sampler().input(), self.get_buffer_data.clone())
}

/// Visits the output samples of a channel.
pub fn read_outputs(&self) -> Option<ReadOutputs<'s>> {
use accessor::{DataType, Iter};
use crate::animation::Property;

let output = self.channel.sampler().output();
if let Some(slice) = (self.get_buffer_data)(output.view().buffer()) {
Some(
match self.channel.target().property() {
Property::Translation => ReadOutputs::Translations(Iter::new(output, slice)),
Property::Rotation => ReadOutputs::Rotations(match output.data_type() {
DataType::I8 => Rotations::I8(Iter::new(output, slice)),
DataType::U8 => Rotations::U8(Iter::new(output, slice)),
DataType::I16 => Rotations::I16(Iter::new(output, slice)),
DataType::U16 => Rotations::U16(Iter::new(output, slice)),
DataType::F32 => Rotations::F32(Iter::new(output, slice)),
_ => unreachable!()
}),
Property::Scale => ReadOutputs::Scales(Iter::new(output, slice)),
Property::MorphTargetWeights => ReadOutputs::MorphTargetWeights(match output.data_type() {
DataType::I8 => MorphTargetWeights::I8(Iter::new(output, slice)),
DataType::U8 => MorphTargetWeights::U8(Iter::new(output, slice)),
DataType::I16 => MorphTargetWeights::I16(Iter::new(output, slice)),
DataType::U16 => MorphTargetWeights::U16(Iter::new(output, slice)),
DataType::F32 => MorphTargetWeights::F32(Iter::new(output, slice)),
_ => unreachable!()
}),
match self.channel.target().property() {
Property::Translation => Iter::new(output, self.get_buffer_data.clone()).map(ReadOutputs::Translations),
Property::Rotation => {
match output.data_type() {
DataType::I8 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::Rotations(Rotations::I8(x))),
DataType::U8 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::Rotations(Rotations::U8(x))),
DataType::I16 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::Rotations(Rotations::I16(x))),
DataType::U16 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::Rotations(Rotations::U16(x))),
DataType::F32 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::Rotations(Rotations::F32(x))),
_ => unreachable!()
}
},
Property::Scale => Iter::new(output, self.get_buffer_data.clone()).map(ReadOutputs::Scales),
Property::MorphTargetWeights => {
match output.data_type() {
DataType::I8 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::MorphTargetWeights(MorphTargetWeights::I8(x))),
DataType::U8 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::MorphTargetWeights(MorphTargetWeights::U8(x))),
DataType::I16 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::MorphTargetWeights(MorphTargetWeights::I16(x))),
DataType::U16 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::MorphTargetWeights(MorphTargetWeights::U16(x))),
DataType::F32 => Iter::new(output, self.get_buffer_data.clone()).map(|x| ReadOutputs::MorphTargetWeights(MorphTargetWeights::F32(x))),
_ => unreachable!()
}
)
} else {
None
},
}
}
}
Loading

0 comments on commit 16d807e

Please sign in to comment.