diff options
Diffstat (limited to 'shared/src/graphics.rs')
-rw-r--r-- | shared/src/graphics.rs | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/shared/src/graphics.rs b/shared/src/graphics.rs new file mode 100644 index 0000000..ae4ee58 --- /dev/null +++ b/shared/src/graphics.rs @@ -0,0 +1,129 @@ +use crate::helper::ReadWrite; +use glam::{Vec3, vec3}; +use std::io::{Read, Write}; + +#[derive(Debug, Default, Clone)] +pub struct GraphicsPart(Vec<u8>); +impl ReadWrite for GraphicsPart { + fn write(&self, w: &mut dyn Write) -> anyhow::Result<()> { + w.write_all(&self.0)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> anyhow::Result<Self> { + let mut buf = Vec::new(); + r.read_to_end(&mut buf)?; + Ok(Self(buf)) + } +} +impl<'a> IntoIterator for &'a GraphicsPart { + type Item = GraphicsCommand; + type IntoIter = CommandIter<'a>; + fn into_iter(self) -> Self::IntoIter { + CommandIter(&self.0) + } +} + +pub struct CommandIter<'a>(&'a [u8]); + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum GraphicsCommand { + NoFill, + Fill(u8), + + NoStroke, + Stroke(u8), + + StrokeWidth(f32), + + StrokeDash(f32, f32), + + Line(Vec3), + Close, + + Unknown, +} + +impl<'a> Iterator for CommandIter<'a> { + type Item = GraphicsCommand; + fn next(&mut self) -> Option<Self::Item> { + if self.0.len() < 2 { + return None; + } + let step = self.0[0]; + let kind = self.0[1]; + self.0 = &self.0[2..]; + if self.0.len() < step as usize { + return None; + } + let data = &self.0[..step as usize]; + self.0 = &self.0[step as usize..]; + use GraphicsCommand::*; + Some(match (kind, step) { + (0, 0) => NoFill, + (0, 1) => Fill(data[0]), + (1, 0) => NoStroke, + (1, 1) => Stroke(data[0]), + (2, 4) => StrokeWidth(f32::from_le_bytes([data[0], data[1], data[2], data[3]])), + (3, 8) => StrokeDash( + f32::from_le_bytes([data[0], data[1], data[2], data[3]]), + f32::from_le_bytes([data[4], data[5], data[6], data[7]]), + ), + (4, 12) => Line(vec3( + f32::from_le_bytes([data[0], data[1], data[2], data[3]]), + f32::from_le_bytes([data[4], data[5], data[6], data[7]]), + f32::from_le_bytes([data[8], data[9], data[10], data[11]]), + )), + (5, 0) => Close, + _ => Unknown, + }) + } +} +impl GraphicsPart { + pub fn push(&mut self, cmd: GraphicsCommand) { + match cmd { + GraphicsCommand::NoFill => self.0.extend([0, 0]), + GraphicsCommand::Fill(n) => self.0.extend([1, 0, n]), + GraphicsCommand::NoStroke => self.0.extend([0, 1]), + GraphicsCommand::Stroke(n) => self.0.extend([1, 1, n]), + GraphicsCommand::StrokeWidth(w) => { + self.0.extend([4, 2]); + self.0.extend(w.to_le_bytes()); + } + GraphicsCommand::StrokeDash(a, b) => { + self.0.extend([8, 3]); + self.0.extend(a.to_le_bytes()); + self.0.extend(b.to_le_bytes()); + } + GraphicsCommand::Line(p) => { + self.0.extend([12, 4]); + self.0.extend(p.x.to_le_bytes()); + self.0.extend(p.y.to_le_bytes()); + self.0.extend(p.z.to_le_bytes()); + } + GraphicsCommand::Close => self.0.extend([0, 5]), + GraphicsCommand::Unknown => self.0.extend([0, 255]), + } + } +} + +#[test] +#[cfg(test)] +fn test_ser() { + use GraphicsCommand::*; + let cmds = [ + NoFill, + Line(Vec3::NEG_ONE), + Close, + Stroke(4), + StrokeWidth(5.), + StrokeDash(0.5, 1.), + ]; + + let mut p = GraphicsPart::default(); + for c in cmds { + p.push(c); + } + for (i, c) in p.into_iter().enumerate() { + assert_eq!(c, cmds[i], "index={i}"); + } +} |