aboutsummaryrefslogtreecommitdiff
path: root/evc
diff options
context:
space:
mode:
Diffstat (limited to 'evc')
-rw-r--r--evc/src/bin/encode.rs17
-rw-r--r--evc/src/block.rs6
-rw-r--r--evc/src/codec/encode.rs46
-rw-r--r--evc/src/debug.rs24
-rw-r--r--evc/src/lib.rs3
-rw-r--r--evc/src/pixel.rs30
-rw-r--r--evc/src/view.rs4
7 files changed, 100 insertions, 30 deletions
diff --git a/evc/src/bin/encode.rs b/evc/src/bin/encode.rs
index 05ebd24..d6029aa 100644
--- a/evc/src/bin/encode.rs
+++ b/evc/src/bin/encode.rs
@@ -1,7 +1,10 @@
use anyhow::Context;
use clap::Parser;
use evc::{
- codec::{decode::decode_block, encode::encode_block},
+ codec::{
+ decode::decode_block,
+ encode::{encode_block, EncodeConfig},
+ },
frame::Frame,
header::Header,
ser::Sink,
@@ -17,6 +20,11 @@ pub struct EncodeArgs {
width: usize,
#[arg(short = 'H', long)]
height: usize,
+
+ #[arg(short = 't', long, default_value = "0.9")]
+ ref_thres: f64,
+ #[arg(short = 'T', long)]
+ no_translation: bool,
}
fn main() -> anyhow::Result<()> {
@@ -26,6 +34,11 @@ fn main() -> anyhow::Result<()> {
let mut input = BufReader::new(std::io::stdin());
let mut output = BufWriter::new(std::io::stdout());
+ let config = EncodeConfig {
+ translate: !args.no_translation,
+ ref_thres: args.ref_thres,
+ };
+
let size = Vec2 {
x: args.width as isize,
y: args.height as isize,
@@ -47,7 +60,7 @@ fn main() -> anyhow::Result<()> {
let v1 = frame.view();
let v2 = prev_frame.view();
- let root = encode_block(v1, v2);
+ let root = encode_block(v1, v2, &config);
root.write(&mut output).context("writing encoded frame")?;
decode_block(&root, frame.view_mut(), prev_frame.view());
diff --git a/evc/src/block.rs b/evc/src/block.rs
index d0dd4d5..024adb6 100644
--- a/evc/src/block.rs
+++ b/evc/src/block.rs
@@ -25,9 +25,9 @@ impl Block {
a.write(sink)?;
b.write(sink)?;
}
- Block::Reference { translation: _ } => {
+ Block::Reference { translation } => {
sink.put(2u8)?;
- // sink.put(*translation)?;
+ sink.put(*translation)?;
}
}
Ok(())
@@ -54,7 +54,7 @@ impl Block {
[a, b]
})),
2 => Block::Reference {
- translation: Vec2::ZERO, //source.get()?,
+ translation: source.get()?,
},
x => bail!("corrupt block type ({})", x),
})
diff --git a/evc/src/codec/encode.rs b/evc/src/codec/encode.rs
index 7256265..a5cb94b 100644
--- a/evc/src/codec/encode.rs
+++ b/evc/src/codec/encode.rs
@@ -1,28 +1,40 @@
-use crate::{block::Block, frame::Frame, view::View, vec2::Vec2};
+use crate::{block::Block, frame::Frame, vec2::Vec2, view::View};
-pub fn encode_block(view: View<&Frame>, prev: View<&Frame>) -> Block {
- // let mut best_diff = f64::INFINITY;
- // for x in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] {
- // for y in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] {
- // let diff = View::diff(&view, &prev) / view.area() as f64;
- // if diff < best_diff {
- // }
- // }
- // }
- let diff = View::diff(&view, &prev) / view.area() as f64;
- // if best_diff < 0.9 {
- if diff < 0.9 {
- Block::Reference {
- translation: Vec2::ZERO,
+#[derive(Debug, Clone)]
+pub struct EncodeConfig {
+ pub translate: bool,
+ pub ref_thres: f64,
+}
+
+pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block {
+ let (diff, translation) = if view.area() > 10_000 {
+ (f64::INFINITY, Vec2::ZERO)
+ } else if config.translate {
+ let mut best_diff = f64::INFINITY;
+ let mut best_translation = Vec2::ZERO;
+ for x in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] {
+ for y in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] {
+ let diff = View::diff(&view, &prev) / view.area() as f64;
+ if diff < best_diff {
+ best_translation = Vec2 { x, y };
+ best_diff = diff;
+ }
+ }
}
+ (best_diff, best_translation)
+ } else {
+ (View::diff(&view, &prev) / view.area() as f64, Vec2::ZERO)
+ };
+ if diff < config.ref_thres {
+ Block::Reference { translation }
} else {
if view.size.x < 16 {
Block::Literal(view.pixels())
} else {
let [av, bv] = view.split();
let [ap, bp] = prev.split();
- let a = encode_block(av, ap);
- let b = encode_block(bv, bp);
+ let a = encode_block(av, ap, config);
+ let b = encode_block(bv, bp, config);
if a.is_literal() && b.is_literal() {
Block::Literal(view.pixels())
} else {
diff --git a/evc/src/debug.rs b/evc/src/debug.rs
index 7b27b83..cbc598e 100644
--- a/evc/src/debug.rs
+++ b/evc/src/debug.rs
@@ -1,4 +1,4 @@
-use crate::{frame::Frame, pixel::Pixel, view::View};
+use crate::{frame::Frame, pixel::Pixel, vec2::Vec2, view::View};
impl View<&mut Frame> {
pub fn draw_box(&mut self, color: Pixel) {
@@ -14,6 +14,28 @@ impl View<&mut Frame> {
}
}
}
+
+impl Frame {
+ pub fn draw_line(&mut self, start: Vec2, end: Vec2, color: Pixel) {
+ let (sx, sy) = (start.x as f32, start.y as f32);
+ let (ex, ey) = (end.x as f32, end.y as f32);
+ let (dx, dy) = (ex - sx, ey - sy);
+ let len = (dx * dx + dy * dy).sqrt();
+ let (nx, ny) = (dx / len, dy / len);
+ let (mut cx, mut cy) = (sx, sy);
+ let mut lc = 0.0;
+ while lc < len {
+ self[Vec2 {
+ x: cx as isize,
+ y: cy as isize,
+ }] = color;
+ lc += 0.5;
+ cx += nx * 0.5;
+ cy += ny * 0.5;
+ }
+ }
+}
+
impl Pixel {
pub const RED: Pixel = Pixel { r: 255, g: 0, b: 0 };
pub const GREEN: Pixel = Pixel { r: 0, g: 255, b: 0 };
diff --git a/evc/src/lib.rs b/evc/src/lib.rs
index ee242e6..22866e1 100644
--- a/evc/src/lib.rs
+++ b/evc/src/lib.rs
@@ -1,4 +1,7 @@
#![feature(box_patterns)]
+#![feature(const_fn_floating_point_arithmetic)]
+// #![feature(const_for)]
+// #![feature(const_mut_refs)]
pub mod block;
pub mod codec;
diff --git a/evc/src/pixel.rs b/evc/src/pixel.rs
index b3ef841..4fb6772 100644
--- a/evc/src/pixel.rs
+++ b/evc/src/pixel.rs
@@ -21,12 +21,32 @@ impl Ser for Pixel {
impl Pixel {
pub const BLACK: Pixel = Pixel { r: 0, g: 0, b: 0 };
#[inline]
- pub fn distance(a: Pixel, b: Pixel) -> f64 {
+ pub fn distance(a: Pixel, b: Pixel) -> usize {
let (rd, gd, bd) = (
- a.r.abs_diff(b.r) as f64,
- a.r.abs_diff(b.r) as f64,
- a.r.abs_diff(b.r) as f64,
+ a.r.abs_diff(b.r) as usize,
+ a.r.abs_diff(b.r) as usize,
+ a.r.abs_diff(b.r) as usize,
);
- (rd * rd + gd * gd + bd * bd).sqrt()
+ SQRT[rd + gd + bd]
}
}
+
+const SQRT: [usize; 256 * 3] = gen_sqrt_lookup();
+
+const fn gen_sqrt_lookup<const N: usize>() -> [usize; N] {
+ let mut arr = [0; N];
+ let mut i = 0;
+ while i < N {
+ arr[i] = sqrt(i as f32) as usize;
+ i += 1;
+ }
+ arr
+}
+
+const fn sqrt(x: f32) -> f32 {
+ let a = 1.0;
+ let a = (a + x / a) * 0.5;
+ let a = (a + x / a) * 0.5;
+ let a = (a + x / a) * 0.5;
+ a
+}
diff --git a/evc/src/view.rs b/evc/src/view.rs
index 4cd4a45..45c1728 100644
--- a/evc/src/view.rs
+++ b/evc/src/view.rs
@@ -124,7 +124,7 @@ impl<T: Copy> View<T> {
impl<T: Index<Vec2, Output = Pixel>> View<&T> {
pub fn diff(va: &Self, vb: &Self) -> f64 {
assert_eq!(va.size, vb.size);
- let mut acc = 0.0;
+ let mut acc = 0;
for x in 0..va.size.x {
for y in 0..va.size.y {
let a = va[(x, y)];
@@ -132,7 +132,7 @@ impl<T: Index<Vec2, Output = Pixel>> View<&T> {
acc += Pixel::distance(a, b);
}
}
- acc
+ acc as f64
}
pub fn pixels(&self) -> Vec<Pixel> {
let mut v = vec![];