aboutsummaryrefslogtreecommitdiff
path: root/lvc/codec/src/serialize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'lvc/codec/src/serialize.rs')
-rw-r--r--lvc/codec/src/serialize.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/lvc/codec/src/serialize.rs b/lvc/codec/src/serialize.rs
new file mode 100644
index 0000000..ac6230e
--- /dev/null
+++ b/lvc/codec/src/serialize.rs
@@ -0,0 +1,123 @@
+use crate::split::split;
+use crate::Block;
+use crate::Pixel;
+use crate::Ref;
+use crate::View;
+use crate::P2;
+use std::io::Read;
+use std::io::Result;
+use std::io::Write;
+
+impl Pixel {
+ #[inline]
+ pub fn write(&self, w: &mut impl Write) -> Result<()> {
+ w.write_all(&[
+ self.r.clamp(0, 255) as u8,
+ self.g.clamp(0, 255) as u8,
+ self.b.clamp(0, 255) as u8,
+ ])
+ }
+ #[inline]
+ pub fn read(r: &mut impl Read) -> Result<Pixel> {
+ Ok(Self {
+ r: read_byte(r)? as i16,
+ g: read_byte(r)? as i16,
+ b: read_byte(r)? as i16,
+ })
+ }
+}
+impl Pixel {
+ #[inline]
+ pub fn write_full(&self, w: &mut impl Write) -> Result<()> {
+ write_word(w, self.r)?;
+ write_word(w, self.g)?;
+ write_word(w, self.b)?;
+ Ok(())
+ }
+ #[inline]
+ pub fn read_full(r: &mut impl Read) -> Result<Pixel> {
+ Ok(Self {
+ r: read_word(r)?,
+ g: read_word(r)?,
+ b: read_word(r)?,
+ })
+ }
+}
+impl P2 {
+ #[inline]
+ pub fn write(&self, w: &mut impl Write) -> Result<()> {
+ write_word(w, self.x as i16)?;
+ write_word(w, self.y as i16)?;
+ Ok(())
+ }
+
+ #[inline]
+ pub fn read(r: &mut impl Read) -> Result<P2> {
+ Ok(Self {
+ x: read_word(r)? as i32,
+ y: read_word(r)? as i32,
+ })
+ }
+}
+
+impl Block {
+ pub fn write(&self, w: &mut impl Write) -> Result<()> {
+ match self {
+ Block::Split(a, b) => {
+ w.write_all(&[0])?;
+ a.write(w)?;
+ b.write(w)?;
+ }
+ Block::Lit(pixels) => {
+ w.write_all(&[1])?;
+ for p in pixels {
+ p.write(w)?;
+ }
+ }
+ Block::Ref(k) => {
+ w.write_all(&[2])?;
+ k.pos_off.write(w)?;
+ k.color_off.write_full(w)?;
+ }
+ }
+ Ok(())
+ }
+ pub fn read(r: &mut impl Read, view: View) -> Result<Block> {
+ match read_byte(r)? {
+ 0 => {
+ let [av, bv] = split(view);
+ Ok(Block::Split(
+ box Block::read(r, av)?,
+ box Block::read(r, bv)?,
+ ))
+ }
+ 1 => {
+ let mut px = vec![];
+ for _ in 0..view.size().area() {
+ px.push(Pixel::read(r)?)
+ }
+ Ok(Block::Lit(px))
+ }
+ 2 => Ok(Block::Ref(Ref {
+ pos_off: P2::read(r)?,
+ color_off: Pixel::read_full(r)?,
+ })),
+ _ => Err(std::io::Error::other("unknown block variant")),
+ }
+ }
+}
+
+#[inline]
+fn read_byte(r: &mut impl Read) -> Result<u8> {
+ let mut buf = [0u8];
+ r.read_exact(&mut buf)?;
+ Ok(buf[0])
+}
+#[inline]
+fn write_word(w: &mut impl Write, v: i16) -> Result<()> {
+ w.write_all(&[(v & 0xff) as u8, (v >> 8) as u8])
+}
+#[inline]
+fn read_word(r: &mut impl Read) -> Result<i16> {
+ Ok((read_byte(r)? as u16 | ((read_byte(r)? as u16) << 8)) as i16)
+}