Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sparse accessor iterators #246

Merged
merged 1 commit into from
Sep 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making Accessor an enum too

/// 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