summaryrefslogtreecommitdiff
path: root/shared/src/graphics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'shared/src/graphics.rs')
-rw-r--r--shared/src/graphics.rs129
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}");
+ }
+}