use bytemuck::{Pod, Zeroable};
use crate::ShapeRecord;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct ShapeRecordBody {
pub rect: [f32; 4],
pub color: [f32; 4],
pub stroke_width: f32,
pub flags: u32,
pub brush: u32,
pub placement: u32,
pub arc_geometry: [f32; 4],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct ShapeRecordCurve {
pub radii: [f32; 4],
pub arc_normalized: [f32; 4],
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ShapeRecords {
bodies: Vec<ShapeRecordBody>,
curves: Vec<ShapeRecordCurve>,
sources: Vec<[f32; 4]>,
}
impl ShapeRecords {
pub(crate) fn with_capacity(capacity: usize) -> Self {
Self {
bodies: Vec::with_capacity(capacity),
curves: Vec::with_capacity(capacity),
sources: Vec::with_capacity(capacity),
}
}
pub fn len(&self) -> usize {
self.bodies.len()
}
pub fn is_empty(&self) -> bool {
self.bodies.is_empty()
}
pub fn bodies(&self) -> &[ShapeRecordBody] {
&self.bodies
}
pub fn curves(&self) -> &[ShapeRecordCurve] {
&self.curves
}
pub fn get(&self, index: usize) -> Option<ShapeRecord> {
self.bodies
.get(index)
.map(|body| reconstruct(body, &self.curves[index], self.sources[index]))
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = ShapeRecord> + DoubleEndedIterator + '_ {
self.bodies
.iter()
.zip(&self.curves)
.zip(&self.sources)
.map(|((body, curve), &source)| reconstruct(body, curve, source))
}
pub(crate) fn capacity(&self) -> usize {
self.bodies
.capacity()
.min(self.curves.capacity())
.min(self.sources.capacity())
}
pub(crate) fn heap_bytes(&self) -> usize {
self.bodies.capacity() * std::mem::size_of::<ShapeRecordBody>()
+ self.curves.capacity() * std::mem::size_of::<ShapeRecordCurve>()
+ self.sources.capacity() * std::mem::size_of::<[f32; 4]>()
}
pub(crate) fn source_bytes(&self) -> &[u8] {
bytemuck::cast_slice(&self.sources)
}
pub(crate) fn clear(&mut self) {
self.bodies.clear();
self.curves.clear();
self.sources.clear();
}
pub(crate) fn reserve(&mut self, additional: usize) {
self.bodies.reserve(additional);
self.curves.reserve(additional);
self.sources.reserve(additional);
}
pub(crate) fn push(
&mut self,
body: ShapeRecordBody,
curve: ShapeRecordCurve,
source: [f32; 4],
) {
self.bodies.push(body);
self.curves.push(curve);
self.sources.push(source);
}
}
fn reconstruct(body: &ShapeRecordBody, curve: &ShapeRecordCurve, source: [f32; 4]) -> ShapeRecord {
ShapeRecord {
rect: body.rect,
radii: curve.radii,
color: body.color,
stroke_width: body.stroke_width,
flags: body.flags,
brush: body.brush,
reserved: body.placement,
arc: [
body.arc_geometry[0],
body.arc_geometry[1],
source[0],
source[1],
],
arc_band: [
source[2],
source[3],
body.arc_geometry[2],
body.arc_geometry[3],
],
arc_normalized: curve.arc_normalized,
}
}
#[cfg(test)]
#[path = "tests/shape_records_tests.rs"]
mod tests;