use crate::voxel_clip::{occ_words_per_col, LoopMode, VoxelClip, VoxelFrame};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Pivot {
BottomCenter,
Center,
Custom([f32; 3]),
}
impl Pivot {
#[allow(clippy::cast_precision_loss)]
pub(crate) fn resolve(self, dims: [u32; 3]) -> [f32; 3] {
let (w, t, h) = (dims[0] as f32, dims[1] as f32, dims[2] as f32);
match self {
Self::BottomCenter => [w * 0.5, t * 0.5, 0.0],
Self::Center => [w * 0.5, t * 0.5, h * 0.5],
Self::Custom(p) => p,
}
}
}
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn voxelize_rgba(
canvas: &[u8],
lw: usize,
lh: usize,
thickness: u32,
alpha_cutoff: u8,
) -> VoxelFrame {
let dims = [lw as u32, thickness, lh as u32];
let owpc = occ_words_per_col(dims) as usize;
let mut img_col: Vec<Vec<(u32, u32)>> = vec![Vec::new(); lw];
for row in 0..lh {
let z = (lh - 1 - row) as u32; for (x, run) in img_col.iter_mut().enumerate() {
let i = (row * lw + x) * 4;
if canvas[i + 3] < alpha_cutoff {
continue; }
let mut rgb = (u32::from(canvas[i]) << 16)
| (u32::from(canvas[i + 1]) << 8)
| u32::from(canvas[i + 2]);
if rgb == 0 {
rgb = 0x0001_0101; }
run.push((z, 0x8000_0000 | rgb));
}
}
for run in &mut img_col {
run.sort_unstable_by_key(|&(z, _)| z);
}
let cols = lw * thickness as usize;
let mut occupancy = vec![0u32; cols * owpc];
let mut colors: Vec<u32> = Vec::new();
let mut color_offsets: Vec<u32> = Vec::with_capacity(cols + 1);
color_offsets.push(0);
for depth in 0..thickness as usize {
for (x, run) in img_col.iter().enumerate() {
let col = x + depth * lw;
for &(z, c) in run {
let zi = z as usize;
occupancy[col * owpc + zi / 32] |= 1u32 << (zi % 32);
colors.push(c);
}
color_offsets.push(colors.len() as u32);
}
}
VoxelFrame {
occupancy,
colors,
color_offsets,
}
}
pub(crate) fn assemble_clip(
dims: [u32; 3],
pivot: Pivot,
voxel_world_size: f32,
loop_mode: LoopMode,
frames: &[VoxelFrame],
durations: &[u32],
default_frame_ms: u32,
keyframe_gap: u32,
) -> VoxelClip {
VoxelClip::from_frames_auto(
dims,
pivot.resolve(dims),
voxel_world_size,
loop_mode,
frames,
durations,
default_frame_ms,
keyframe_gap,
)
}