diff --git a/src/algorithm.rs b/src/algorithm.rs index ed784fa..2b6a0ad 100644 --- a/src/algorithm.rs +++ b/src/algorithm.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] use std; +use std::cmp; use lerp::{Lerp, lerp_slice}; @@ -140,3 +141,36 @@ pub fn merge_slices_append(slice1: &[T], } } } + +/// Merges two slices of things, storing the result in slice_out. +/// Panics if slice_out is not the right size. +pub fn merge_slices_to(slice1: &[T], + slice2: &[T], + slice_out: &mut [T], + merge: F) + where F: Fn(&T, &T) -> T +{ + assert!(slice_out.len() == cmp::max(slice1.len(), slice2.len())); + + // Transform the bounding boxes + if slice1.len() == 0 || slice2.len() == 0 { + return; + } else if slice1.len() == slice2.len() { + for (xfo, (xf1, xf2)) in Iterator::zip(slice_out.iter_mut(), + Iterator::zip(slice1.iter(), slice2.iter())) { + *xfo = merge(xf1, xf2); + } + } else if slice1.len() > slice2.len() { + let s = (slice1.len() - 1) as f32; + for (i, (xfo, xf1)) in Iterator::zip(slice_out.iter_mut(), slice1.iter()).enumerate() { + let xf2 = lerp_slice(slice2, i as f32 / s); + *xfo = merge(xf1, &xf2); + } + } else if slice1.len() < slice2.len() { + let s = (slice2.len() - 1) as f32; + for (i, (xfo, xf2)) in Iterator::zip(slice_out.iter_mut(), slice2.iter()).enumerate() { + let xf1 = lerp_slice(slice1, i as f32 / s); + *xfo = merge(&xf1, xf2); + } + } +} diff --git a/src/tracer.rs b/src/tracer.rs index 057c2df..1d8790b 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -1,6 +1,7 @@ use std::iter; +use std::cmp; -use algorithm::{partition, merge_slices_append}; +use algorithm::{partition, merge_slices_to}; use math::Matrix4x4; use lerp::lerp_slice; use assembly::{Assembly, Object, InstanceType}; @@ -179,7 +180,6 @@ fn split_rays_by_direction(rays: &mut [AccelRay]) -> [&mut [AccelRay]; 8] { struct TransformStack { stack: Vec, stack_indices: Vec, - scratch_space: Vec, } impl TransformStack { @@ -187,7 +187,6 @@ impl TransformStack { let mut ts = TransformStack { stack: Vec::new(), stack_indices: Vec::new(), - scratch_space: Vec::new(), }; ts.stack_indices.push(0); @@ -205,14 +204,17 @@ impl TransformStack { let sil = self.stack_indices.len(); let i1 = self.stack_indices[sil - 2]; let i2 = self.stack_indices[sil - 1]; - - self.scratch_space.clear(); - merge_slices_append(&self.stack[i1..i2], - xforms, - &mut self.scratch_space, - |xf1, xf2| *xf1 * *xf2); - - self.stack.extend(&self.scratch_space); + // Reserve stack space for the new transforms. + // Note this leaves exposed uninitialized memory. The subsequent call to + // merge_slices_to() fills that memory in. + { + let maxlen = cmp::max(xforms.len(), i2 - i1); + self.stack.reserve(maxlen); + let l = self.stack.len(); + unsafe { self.stack.set_len(l + maxlen) }; + } + let (xfs1, xfs2) = self.stack.split_at_mut(i2); + merge_slices_to(&xfs1[i1..i2], xforms, xfs2, |xf1, xf2| *xf1 * *xf2); } self.stack_indices.push(self.stack.len());