psychopath/src/transform_stack.rs
Nathan Vegdahl e0ee0d6dff Change to using a dedicated affine transform type.
This lets certain operations, especially matrix inversion, be
quite a bit faster.  And we don't need anything beyond affine
transformations anyway.
2021-05-14 13:30:28 -07:00

84 lines
2.3 KiB
Rust

use std::{
cmp,
mem::{transmute, MaybeUninit},
};
use crate::{algorithm::merge_slices_to, math::Transform};
pub struct TransformStack {
stack: Vec<MaybeUninit<Transform>>,
stack_indices: Vec<usize>,
}
impl TransformStack {
pub fn new() -> TransformStack {
let mut ts = TransformStack {
stack: Vec::new(),
stack_indices: Vec::new(),
};
ts.stack_indices.push(0);
ts.stack_indices.push(0);
ts
}
pub fn clear(&mut self) {
self.stack.clear();
self.stack_indices.clear();
self.stack_indices.push(0);
self.stack_indices.push(0);
}
pub fn push(&mut self, xforms: &[Transform]) {
assert!(!xforms.is_empty());
if self.stack.is_empty() {
let xforms: &[MaybeUninit<Transform>] = unsafe { transmute(xforms) };
self.stack.extend(xforms);
} else {
let sil = self.stack_indices.len();
let i1 = self.stack_indices[sil - 2];
let i2 = self.stack_indices[sil - 1];
// 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(
unsafe { transmute(&xfs1[i1..i2]) },
xforms,
xfs2,
|xf1, xf2| *xf1 * *xf2,
);
}
self.stack_indices.push(self.stack.len());
}
pub fn pop(&mut self) {
assert!(self.stack_indices.len() > 2);
let sl = self.stack.len();
let sil = self.stack_indices.len();
let i1 = self.stack_indices[sil - 2];
let i2 = self.stack_indices[sil - 1];
self.stack.truncate(sl - (i2 - i1));
self.stack_indices.pop();
}
pub fn top(&self) -> &[Transform] {
let sil = self.stack_indices.len();
let i1 = self.stack_indices[sil - 2];
let i2 = self.stack_indices[sil - 1];
unsafe { transmute(&self.stack[i1..i2]) }
}
}