diff options
Diffstat (limited to 'old/evc/src/block.rs')
-rw-r--r-- | old/evc/src/block.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/old/evc/src/block.rs b/old/evc/src/block.rs new file mode 100644 index 0000000..d0f940b --- /dev/null +++ b/old/evc/src/block.rs @@ -0,0 +1,123 @@ +use crate::{ + format::ser::{ConstSizeSerExt, Ser, Sink, Small, Source}, + helpers::vector::Vec2, + helpers::{matrix::Mat2, pixel::Pixel}, +}; +use anyhow::bail; + +#[derive(Clone, Debug, PartialEq)] +pub enum Block { + Literal(Vec<Pixel>), + CompressedLiteral(Vec<u8>), + Split(Box<[Block; 2]>), + Reference { translation: Vec2<isize> }, + AdvancedReference(AdvancedReference), +} + +#[derive(Clone, Debug, PartialEq)] +pub struct AdvancedReference { + pub translation: Vec2<i8>, + pub transform: Mat2<i8>, + pub value_scale: i8, +} + +impl Block { + pub const REFZERO: Block = Block::Reference { + translation: Vec2::<isize>::ZERO, + }; + + pub fn write(&self, sink: &mut impl std::io::Write, size: Vec2<isize>) -> anyhow::Result<()> { + match &self { + Block::Literal(pixels) => { + sink.put(0u8)?; + pixels.write_const_size(sink, size.area() as usize)?; + } + Block::CompressedLiteral(data) => { + sink.put(1u8)?; + data.write(sink)?; + } + Block::Split(box [a, b]) => { + sink.put(2u8)?; + let [asize, bsize] = split_size(size); + a.write(sink, asize)?; + b.write(sink, bsize)?; + } + Block::Reference { translation } => { + sink.put(3u8)?; + sink.put(Small(*translation))?; + } + Block::AdvancedReference(AdvancedReference { + translation, + transform, + value_scale, + }) => { + sink.put(4u8)?; + sink.put((*translation, *transform, *value_scale))?; + } + } + Ok(()) + } + + pub fn read(source: &mut impl std::io::Read, size: Vec2<isize>) -> anyhow::Result<Self> { + let variant = source.get::<u8>()?; + Ok(match variant { + 0 => Block::Literal(Vec::read_const_size(source, size.area() as usize)?), + 1 => Block::CompressedLiteral(Vec::read(source)?), + 2 => Block::Split(Box::new({ + let [asize, bsize] = split_size(size); + let a = Block::read(source, asize)?; + let b = Block::read(source, bsize)?; + [a, b] + })), + 3 => Block::Reference { + translation: source.get::<Small<Vec2<isize>>>()?.0, + }, + 4 => Block::AdvancedReference(AdvancedReference { + translation: source.get()?, + transform: source.get()?, + value_scale: source.get()?, + }), + x => bail!("corrupt block type ({})", x), + }) + } +} + +pub fn split_size(size: Vec2<isize>) -> [Vec2<isize>; 2] { + let vert = size.x > size.y; + [ + if vert { + (size.x / 2, size.y).into() + } else { + (size.x, size.y / 2).into() + }, + if vert { + (size.x - size.x / 2, size.y).into() + } else { + (size.x, size.y - size.y / 2).into() + }, + ] +} + +impl Block { + pub fn is_literal(&self) -> bool { + matches!(self, Block::Literal(..)) + } + pub fn identical_ref(a: &Self, b: &Self) -> bool { + matches!(a, Block::Reference { .. }) && a == b + } +} + +impl Default for AdvancedReference { + fn default() -> Self { + Self { + translation: Vec2 { x: 0, y: 0 }, + transform: Mat2 { + a: 4, + b: 0, + c: 0, + d: 4, + }, + value_scale: 0, + } + } +} |