aboutsummaryrefslogtreecommitdiff
path: root/old/evc/src/block.rs
diff options
context:
space:
mode:
Diffstat (limited to 'old/evc/src/block.rs')
-rw-r--r--old/evc/src/block.rs123
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,
+ }
+ }
+}