slightly better rle variant, implement the cell based one on the pico, 16fps fits and works
This commit is contained in:
parent
c5f7c245d2
commit
f05d146af7
6 changed files with 123434 additions and 79213 deletions
|
@ -55,49 +55,36 @@ pub fn cell_diff_8_vertical_big(prev_frame: &Frame, encoded: &[u8], reader: &mut
|
||||||
const CELLS_X: usize = WIDTH / 8;
|
const CELLS_X: usize = WIDTH / 8;
|
||||||
const CELLS_Y: usize = HEIGHT / 8;
|
const CELLS_Y: usize = HEIGHT / 8;
|
||||||
|
|
||||||
let mut modified_cells = [[false; CELLS_Y]; CELLS_X];
|
let (cell_runs, modified_cells_flat) = rle_255_decode(&encoded, CELLS_X * CELLS_Y);
|
||||||
|
|
||||||
let (mut cell_runs, modified_cells_flat) =
|
|
||||||
rle_255_decode(&unpack_nybbles(encoded), CELLS_X * CELLS_Y);
|
|
||||||
|
|
||||||
if cell_runs % 2 == 1 {
|
|
||||||
cell_runs += 1;
|
|
||||||
}
|
|
||||||
*reader += cell_runs / 2;
|
|
||||||
let encoded = &encoded[(cell_runs / 2)..];
|
|
||||||
|
|
||||||
let mut changed_cell_count = 0;
|
|
||||||
let mut i = 0;
|
|
||||||
for cellx in 0..CELLS_X {
|
|
||||||
for celly in 0..CELLS_Y {
|
|
||||||
let cell = modified_cells_flat[i] == 1;
|
|
||||||
modified_cells[cellx][celly] = cell;
|
|
||||||
if cell {
|
|
||||||
changed_cell_count += 1;
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
*reader += cell_runs;
|
||||||
|
let encoded = &encoded[cell_runs..];
|
||||||
let mut frame = *prev_frame;
|
let mut frame = *prev_frame;
|
||||||
|
|
||||||
let changed_pixel_count = changed_cell_count * 8 * 8;
|
let mut x = 0;
|
||||||
let (runs, new_pixels) = rle_255_decode(encoded, changed_pixel_count);
|
let mut y = 0;
|
||||||
*reader += runs;
|
let mut color = 1;
|
||||||
|
let mut run = 0;
|
||||||
let mut index = 0;
|
let mut i = 0;
|
||||||
|
while x < WIDTH {
|
||||||
for x in 0..WIDTH {
|
let cx = x / 8;
|
||||||
for y in 0..HEIGHT {
|
let cy = y / 8;
|
||||||
let cellx = x / 8;
|
if modified_cells_flat[cx * CELLS_Y + cy] != 0 {
|
||||||
let celly = y / 8;
|
while run == 0 {
|
||||||
let is_changed = modified_cells[cellx][celly];
|
run = encoded[i];
|
||||||
if is_changed {
|
i += 1;
|
||||||
frame[x][y] = new_pixels[index];
|
color = 1 - color;
|
||||||
index += 1;
|
|
||||||
}
|
}
|
||||||
|
run -= 1;
|
||||||
|
frame[x][y] = color;
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
if y == HEIGHT {
|
||||||
|
x += 1;
|
||||||
|
y = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*reader += i;
|
||||||
|
|
||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
|
@ -307,6 +294,72 @@ pub fn rle_vertical_ext(_prev_frame: &Frame, encoded: &[u8], reader: &mut usize)
|
||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rle_vertical_ext_2(_prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame {
|
||||||
|
let mut x = 0;
|
||||||
|
let mut y = 0;
|
||||||
|
let mut color = 0;
|
||||||
|
let mut i = 0;
|
||||||
|
let mut frame = FRAME_0;
|
||||||
|
|
||||||
|
while x < WIDTH {
|
||||||
|
let byte = encoded[i];
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
let mut run = byte as u16;
|
||||||
|
if byte == 255 {
|
||||||
|
// 16 bit run length
|
||||||
|
let upper = (encoded[i] as u16) << 8;
|
||||||
|
let lower = encoded[i + 1] as u16;
|
||||||
|
i += 2;
|
||||||
|
run = upper | lower;
|
||||||
|
}
|
||||||
|
for _ in 0..run {
|
||||||
|
frame[x][y] = color;
|
||||||
|
y += 1;
|
||||||
|
if y == HEIGHT {
|
||||||
|
y = 0;
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color = 1 - color;
|
||||||
|
}
|
||||||
|
*reader += i;
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rle_horizontal_ext_2(_prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame {
|
||||||
|
let mut x = 0;
|
||||||
|
let mut y = 0;
|
||||||
|
let mut color = 0;
|
||||||
|
let mut i = 0;
|
||||||
|
let mut frame = FRAME_0;
|
||||||
|
|
||||||
|
while y < HEIGHT {
|
||||||
|
let byte = encoded[i];
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
let mut run = byte as u16;
|
||||||
|
if byte == 255 {
|
||||||
|
// 16 bit run length
|
||||||
|
let upper = (encoded[i] as u16) << 8;
|
||||||
|
let lower = encoded[i + 1] as u16;
|
||||||
|
i += 2;
|
||||||
|
run = upper | lower;
|
||||||
|
}
|
||||||
|
for _ in 0..run {
|
||||||
|
frame[x][y] = color;
|
||||||
|
x += 1;
|
||||||
|
if x == WIDTH {
|
||||||
|
x = 0;
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color = 1 - color;
|
||||||
|
}
|
||||||
|
*reader += i;
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rle_vertical_var(_prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame {
|
pub fn rle_vertical_var(_prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame {
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
|
|
|
@ -53,8 +53,8 @@ pub fn cell_diff_4_vertical(prev_frame: &Frame, frame: &Frame, loss: usize) -> E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cell_diff_8_vertical_big(prev_frame: &Frame, frame: &Frame, loss: usize) -> EncodedFrame {
|
pub fn cell_diff_8_vertical_big(prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
let loss = loss / 8;
|
// let loss = loss / 8;
|
||||||
const CELLS_X: usize = WIDTH / 8;
|
const CELLS_X: usize = WIDTH / 8;
|
||||||
const CELLS_Y: usize = HEIGHT / 8;
|
const CELLS_Y: usize = HEIGHT / 8;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ pub fn cell_diff_8_vertical_big(prev_frame: &Frame, frame: &Frame, loss: usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changed > loss {
|
if changed > 0{
|
||||||
modified_cells[cellx][celly] = 1;
|
modified_cells[cellx][celly] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ pub fn cell_diff_8_vertical_big(prev_frame: &Frame, frame: &Frame, loss: usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
data.extend_from_slice(&pack_nybbles(rle_encode(&modified_cells_flat, 15)));
|
data.extend_from_slice(&rle_255_encode(&modified_cells_flat));
|
||||||
data.extend_from_slice(&rle_255_encode(&changed_pixels));
|
data.extend_from_slice(&rle_255_encode(&changed_pixels));
|
||||||
|
|
||||||
EncodedFrame {
|
EncodedFrame {
|
||||||
|
@ -298,7 +298,7 @@ pub fn rle_horizontal_ext(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
};
|
};
|
||||||
|
|
||||||
for y in 0..HEIGHT {
|
for y in 0..HEIGHT {
|
||||||
for x in 0..WIDTH {
|
for x in 0..WIDTH {
|
||||||
let pixel = frame[x][y];
|
let pixel = frame[x][y];
|
||||||
if pixel != last_pixel || run == 0xffff {
|
if pixel != last_pixel || run == 0xffff {
|
||||||
push_run(&mut data, run);
|
push_run(&mut data, run);
|
||||||
|
@ -320,7 +320,6 @@ pub fn rle_horizontal_ext(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn rle_horizontal(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
pub fn rle_horizontal(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
let mut pixels = Vec::new();
|
let mut pixels = Vec::new();
|
||||||
for y in 0..HEIGHT {
|
for y in 0..HEIGHT {
|
||||||
|
@ -349,7 +348,7 @@ pub fn tree_16(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
let x = cx * (WIDTH / 4) + px;
|
let x = cx * (WIDTH / 4) + px;
|
||||||
for py in 0..(HEIGHT / 4) {
|
for py in 0..(HEIGHT / 4) {
|
||||||
let y = cy * (HEIGHT / 4) + py;
|
let y = cy * (HEIGHT / 4) + py;
|
||||||
if frame[x][y] == fg{
|
if frame[x][y] == fg {
|
||||||
any_filled_here = true;
|
any_filled_here = true;
|
||||||
break 'a;
|
break 'a;
|
||||||
}
|
}
|
||||||
|
@ -369,8 +368,8 @@ pub fn tree_16(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
if frame[x][y] == fg {
|
if frame[x][y] == fg {
|
||||||
node_pixels.push(fg);
|
node_pixels.push(fg);
|
||||||
any_filled_here = true;
|
any_filled_here = true;
|
||||||
}else{
|
} else {
|
||||||
node_pixels.push(1-fg);
|
node_pixels.push(1 - fg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,10 +384,10 @@ pub fn tree_16(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
data.push((top_node >>8) as u8);
|
data.push((top_node >> 8) as u8);
|
||||||
data.push(top_node as u8);
|
data.push(top_node as u8);
|
||||||
for n in second_nodes{
|
for n in second_nodes {
|
||||||
data.push((n>>8)as u8);
|
data.push((n >> 8) as u8);
|
||||||
data.push(n as u8);
|
data.push(n as u8);
|
||||||
}
|
}
|
||||||
data.extend_from_slice(&rle_255_encode(&included_pixels));
|
data.extend_from_slice(&rle_255_encode(&included_pixels));
|
||||||
|
@ -422,8 +421,6 @@ pub fn rle_vertical_ext(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
data.push(run as u8);
|
data.push(run as u8);
|
||||||
} else {
|
} else {
|
||||||
// double zero to mark 16 bit run length
|
// double zero to mark 16 bit run length
|
||||||
// if data.last() != Some(&0) {
|
|
||||||
// }
|
|
||||||
data.push(0);
|
data.push(0);
|
||||||
data.push(0);
|
data.push(0);
|
||||||
data.push((run >> 8) as u8);
|
data.push((run >> 8) as u8);
|
||||||
|
@ -454,7 +451,81 @@ pub fn rle_vertical_ext(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rle_vertical_ext_2(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let mut last_pixel = 0;
|
||||||
|
let mut run: u16 = 0;
|
||||||
|
|
||||||
|
let push_run = |data: &mut Vec<u8>, run| {
|
||||||
|
if run < 255 {
|
||||||
|
data.push(run as u8);
|
||||||
|
} else {
|
||||||
|
data.push(255);
|
||||||
|
data.push((run >> 8) as u8);
|
||||||
|
data.push((run & 0xff) as u8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for x in 0..WIDTH {
|
||||||
|
for y in 0..HEIGHT {
|
||||||
|
let pixel = frame[x][y];
|
||||||
|
if pixel != last_pixel || run == 0xffff {
|
||||||
|
push_run(&mut data, run);
|
||||||
|
if run == 0xffff && pixel == last_pixel {
|
||||||
|
// inserting dummy run because we ran out of max len
|
||||||
|
data.push(0);
|
||||||
|
}
|
||||||
|
run = 1;
|
||||||
|
} else {
|
||||||
|
run += 1;
|
||||||
|
}
|
||||||
|
last_pixel = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push_run(&mut data, run);
|
||||||
|
EncodedFrame {
|
||||||
|
encoding: Encoding::RLEVerticalExt2,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rle_horizontal_ext_2(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let mut last_pixel = 0;
|
||||||
|
let mut run: u16 = 0;
|
||||||
|
|
||||||
|
let push_run = |data: &mut Vec<u8>, run| {
|
||||||
|
if run < 255 {
|
||||||
|
data.push(run as u8);
|
||||||
|
} else {
|
||||||
|
data.push(255);
|
||||||
|
data.push((run >> 8) as u8);
|
||||||
|
data.push((run & 0xff) as u8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for y in 0..HEIGHT {
|
||||||
|
for x in 0..WIDTH {
|
||||||
|
let pixel = frame[x][y];
|
||||||
|
if pixel != last_pixel || run == 0xffff {
|
||||||
|
push_run(&mut data, run);
|
||||||
|
if run == 0xffff && pixel == last_pixel {
|
||||||
|
// inserting dummy run because we ran out of max len
|
||||||
|
data.push(0);
|
||||||
|
}
|
||||||
|
run = 1;
|
||||||
|
} else {
|
||||||
|
run += 1;
|
||||||
|
}
|
||||||
|
last_pixel = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push_run(&mut data, run);
|
||||||
|
EncodedFrame {
|
||||||
|
encoding: Encoding::RLEHorizontalExt2,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rle_vertical_var(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
pub fn rle_vertical_var(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
// variable bit count
|
// variable bit count
|
||||||
|
@ -469,12 +540,12 @@ pub fn rle_vertical_var(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
let push_run = |data: &mut Vec<u8>, run| {
|
let push_run = |data: &mut Vec<u8>, run| {
|
||||||
if run < 0x7f {
|
if run < 0x7f {
|
||||||
data.push(run as u8);
|
data.push(run as u8);
|
||||||
}else if run < 0x3fff {
|
} else if run < 0x3fff {
|
||||||
data.push((run >> 8) as u8 | 0x80);
|
data.push((run >> 8) as u8 | 0x80);
|
||||||
data.push(run as u8);
|
data.push(run as u8);
|
||||||
} else {
|
} else {
|
||||||
data.push((run >> 16) as u8 | 0xC0);
|
data.push((run >> 16) as u8 | 0xC0);
|
||||||
data.push((run >> 8 ) as u8);
|
data.push((run >> 8) as u8);
|
||||||
data.push(run as u8);
|
data.push(run as u8);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -482,7 +553,7 @@ pub fn rle_vertical_var(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
|
||||||
for x in 0..WIDTH {
|
for x in 0..WIDTH {
|
||||||
for y in 0..HEIGHT {
|
for y in 0..HEIGHT {
|
||||||
let pixel = frame[x][y];
|
let pixel = frame[x][y];
|
||||||
if pixel != last_pixel{
|
if pixel != last_pixel {
|
||||||
push_run(&mut data, run);
|
push_run(&mut data, run);
|
||||||
run = 1;
|
run = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,37 +15,42 @@ const MAX_LOSS: usize = 0; // highest "loss" value tried for all lossy encodings
|
||||||
|
|
||||||
const LOSSLESS_ENCODINGS: &[FrameEncoder] = &[
|
const LOSSLESS_ENCODINGS: &[FrameEncoder] = &[
|
||||||
enc::rle_horizontal,
|
enc::rle_horizontal,
|
||||||
enc::rle_horizontal_ext,
|
// enc::rle_horizontal_ext,
|
||||||
|
enc::rle_horizontal_ext_2,
|
||||||
enc::rle_vertical,
|
enc::rle_vertical,
|
||||||
enc::rle_vertical_ext,
|
// enc::rle_vertical_ext,
|
||||||
enc::rle_vertical_var,
|
enc::rle_vertical_ext_2,
|
||||||
enc::rle_vertical_16,
|
// enc::rle_vertical_var, // not worth
|
||||||
enc::rle_diff_horizontal,
|
// enc::rle_vertical_16, // not worth
|
||||||
enc::rle_diff_vertical,
|
// enc::rle_diff_horizontal,
|
||||||
|
// enc::rle_diff_vertical,
|
||||||
// enc::bg_strips_horizontal_16, // only works for the tiny display
|
// enc::bg_strips_horizontal_16, // only works for the tiny display
|
||||||
enc::bg_strips_horizontal_24, // intended for the 240x320 display
|
enc::bg_strips_horizontal_24, // intended for the 240x320 display
|
||||||
// enc::tree_16,// turns out to be useless
|
// enc::tree_16,// turns out to be useless
|
||||||
|
enc::cell_diff_8_vertical_big,
|
||||||
];
|
];
|
||||||
const LOSSY_ENCODINGS: &[FrameEncoderLossy] = &[
|
const LOSSY_ENCODINGS: &[FrameEncoderLossy] = &[
|
||||||
enc::fill_white,
|
enc::fill_white,
|
||||||
enc::fill_black,
|
enc::fill_black,
|
||||||
// todo: adapt for big display
|
// todo: adapt for big display
|
||||||
// enc::cell_diff_8_vertical,
|
// enc::cell_diff_8_vertical,
|
||||||
enc::cell_diff_4_vertical,
|
// enc::cell_diff_4_vertical,
|
||||||
enc::cell_diff_8_vertical_big,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let frames = get_all_frames("../video/frames/");
|
let frames = get_all_frames("../video/frames/");
|
||||||
let encoded = encode(&frames);
|
let encoded = encode(&frames);
|
||||||
|
|
||||||
let mut stats: EnumMap<Encoding, u32> = EnumMap::default();
|
let mut stats: EnumMap<Encoding, (u32, Vec<usize>)> = EnumMap::default();
|
||||||
let mut reader = 0;
|
let mut reader = 0;
|
||||||
let mut last_frame = FRAME_0;
|
let mut last_frame = FRAME_0;
|
||||||
let mut frame_index = 0;
|
let mut frame_index = 0;
|
||||||
while reader < encoded.len() {
|
while reader < encoded.len() {
|
||||||
let frame_type: Encoding = encoded[reader].try_into().unwrap();
|
let frame_type: Encoding = encoded[reader].try_into().unwrap();
|
||||||
stats[frame_type] += 1;
|
stats[frame_type].0 += 1;
|
||||||
|
if stats[frame_type].1.len() < 5{
|
||||||
|
stats[frame_type].1.push(frame_index);
|
||||||
|
}
|
||||||
reader += 1;
|
reader += 1;
|
||||||
let decoder = get_matching_decoder(frame_type);
|
let decoder = get_matching_decoder(frame_type);
|
||||||
last_frame = decoder(&last_frame, &encoded[reader..], &mut reader);
|
last_frame = decoder(&last_frame, &encoded[reader..], &mut reader);
|
||||||
|
@ -56,12 +61,12 @@ fn main() {
|
||||||
);
|
);
|
||||||
render_images(&frames[frame_index], &last_frame);
|
render_images(&frames[frame_index], &last_frame);
|
||||||
wait_for_input();
|
wait_for_input();
|
||||||
frame_index += 1;
|
|
||||||
}
|
}
|
||||||
|
frame_index += 1;
|
||||||
}
|
}
|
||||||
for (encoding, &frames) in stats.iter() {
|
for (encoding, (frames, indexes)) in &stats {
|
||||||
if frames > 0 {
|
if *frames > 0 {
|
||||||
println!("{encoding:?} - {frames} frames");
|
println!("{encoding:?} - {frames} frames: {indexes:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
@ -73,13 +78,13 @@ fn main() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut export_string = String::from("// Generated by the `encoder` rust app\n");
|
let mut export_string = String::from("// Generated by the `encoder` rust app\n");
|
||||||
for (encoding, count) in stats {
|
for (encoding, &(count, _)) in &stats {
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
export_string += &format!("#define USE_{encoding:?}\n");
|
export_string += &format!("#define USE_{encoding:?}\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export_string += "\n\ntypedef enum Encoding {\n";
|
export_string += "\n\ntypedef enum Encoding {\n";
|
||||||
for (encoding, count) in stats {
|
for (encoding, (count, _)) in stats {
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
export_string += &format!("\tEncoding_{encoding:?} = {},\n", encoding as u8);
|
export_string += &format!("\tEncoding_{encoding:?} = {},\n", encoding as u8);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +132,7 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for encode in LOSSY_ENCODINGS.iter() {
|
for encode in LOSSY_ENCODINGS.iter() {
|
||||||
for loss in 0..MAX_LOSS {
|
for loss in 0..=MAX_LOSS {
|
||||||
let encoded = encode(&last_frame, frame, loss);
|
let encoded = encode(&last_frame, frame, loss);
|
||||||
let decode = get_matching_decoder(encoded.encoding);
|
let decode = get_matching_decoder(encoded.encoding);
|
||||||
let decoded = decode(&last_frame, &encoded.data, &mut 0);
|
let decoded = decode(&last_frame, &encoded.data, &mut 0);
|
||||||
|
@ -169,8 +174,10 @@ enum Encoding {
|
||||||
FillWhite,
|
FillWhite,
|
||||||
RLEHorizontal,
|
RLEHorizontal,
|
||||||
RLEHorizontalExt,
|
RLEHorizontalExt,
|
||||||
|
RLEHorizontalExt2,
|
||||||
RLEVertical,
|
RLEVertical,
|
||||||
RLEVerticalExt,
|
RLEVerticalExt,
|
||||||
|
RLEVerticalExt2,
|
||||||
RLEVerticalVar,
|
RLEVerticalVar,
|
||||||
RLEVertical16,
|
RLEVertical16,
|
||||||
RLEDiffHorizontal,
|
RLEDiffHorizontal,
|
||||||
|
@ -197,8 +204,10 @@ fn get_matching_decoder(encoding: Encoding) -> FrameDecoder {
|
||||||
Encoding::FillBlack => dec::fill_black,
|
Encoding::FillBlack => dec::fill_black,
|
||||||
Encoding::RLEHorizontal => dec::rle_horizontal,
|
Encoding::RLEHorizontal => dec::rle_horizontal,
|
||||||
Encoding::RLEHorizontalExt => dec::rle_horizontal_ext,
|
Encoding::RLEHorizontalExt => dec::rle_horizontal_ext,
|
||||||
|
Encoding::RLEHorizontalExt2 => dec::rle_horizontal_ext_2,
|
||||||
Encoding::RLEVertical => dec::rle_vertical,
|
Encoding::RLEVertical => dec::rle_vertical,
|
||||||
Encoding::RLEVerticalExt => dec::rle_vertical_ext,
|
Encoding::RLEVerticalExt => dec::rle_vertical_ext,
|
||||||
|
Encoding::RLEVerticalExt2 => dec::rle_vertical_ext_2,
|
||||||
Encoding::RLEVerticalVar => dec::rle_vertical_var,
|
Encoding::RLEVerticalVar => dec::rle_vertical_var,
|
||||||
Encoding::RLEVertical16 => dec::rle_vertical_16,
|
Encoding::RLEVertical16 => dec::rle_vertical_16,
|
||||||
Encoding::RLEDiffHorizontal => dec::rle_diff_horizontal,
|
Encoding::RLEDiffHorizontal => dec::rle_diff_horizontal,
|
||||||
|
|
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13...3.27)
|
||||||
# note: this must happen before project()
|
# note: this must happen before project()
|
||||||
include(pico_sdk_import.cmake)
|
include(pico_sdk_import.cmake)
|
||||||
|
|
||||||
project(Bad_Apple!!_Pico)
|
project(Bad_Apple_Pico)
|
||||||
|
|
||||||
# initialize the Raspberry Pi Pico SDK
|
# initialize the Raspberry Pi Pico SDK
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
202153
pico_decoder/src/data.h
202153
pico_decoder/src/data.h
File diff suppressed because it is too large
Load diff
|
@ -14,12 +14,18 @@
|
||||||
#define HEIGHT ILI9341_TFTHEIGHT
|
#define HEIGHT ILI9341_TFTHEIGHT
|
||||||
#define WIDTH ILI9341_TFTWIDTH
|
#define WIDTH ILI9341_TFTWIDTH
|
||||||
|
|
||||||
|
// #define DEBUG_STUFF
|
||||||
|
|
||||||
|
#define FPS 16
|
||||||
|
|
||||||
|
#define MICROS_PER_FRAME (1000000/FPS)
|
||||||
|
|
||||||
// todo pack as bits instead
|
// todo pack as bits instead
|
||||||
#define AREA (HEIGHT * WIDTH)
|
#define AREA (HEIGHT * WIDTH)
|
||||||
u8 frame[AREA];
|
u8 frame[AREA];
|
||||||
|
|
||||||
u32 reader;
|
u32 reader;
|
||||||
bool error = false;
|
u8 error = 0;
|
||||||
u8 last_frame_type;
|
u8 last_frame_type;
|
||||||
u32 last_frame_start;
|
u32 last_frame_start;
|
||||||
|
|
||||||
|
@ -29,21 +35,21 @@ void set_pixel(u16 x, u16 y, u8 color);
|
||||||
|
|
||||||
void draw_digit(u16 x, u16 y, u8 digit) {
|
void draw_digit(u16 x, u16 y, u8 digit) {
|
||||||
const u16 digit_font[10] = {
|
const u16 digit_font[10] = {
|
||||||
0b111101101101111, // 0
|
0b111101101101111, // 0
|
||||||
0b010110010010111, // 1
|
0b010110010010111, // 1
|
||||||
0b111001111100111, // 2
|
0b111001111100111, // 2
|
||||||
0b111001111001111, // 3
|
0b111001111001111, // 3
|
||||||
0b101101111001001, // 4
|
0b101101111001001, // 4
|
||||||
0b111100111001111, // 5
|
0b111100111001111, // 5
|
||||||
0b111100111101111, // 6
|
0b111100111101111, // 6
|
||||||
0b111001001001001, // 7
|
0b111001001001001, // 7
|
||||||
0b111101111101111, // 8
|
0b111101111101111, // 8
|
||||||
0b111101111001111, // 9
|
0b111101111001111, // 9
|
||||||
};
|
};
|
||||||
|
// background square
|
||||||
for (int xx = 0; xx < 5; xx++)
|
for (int xx = 0; xx < 5; xx++)
|
||||||
for (int yy = 0; yy < 7; yy++){
|
for (int yy = 0; yy < 7; yy++)
|
||||||
set_pixel(x+xx-1, y+yy-1, 0);
|
set_pixel(x+xx-1, y+yy-1, 0);
|
||||||
}
|
|
||||||
|
|
||||||
u16 pixels = digit_font[digit];
|
u16 pixels = digit_font[digit];
|
||||||
set_pixel(x + 0, y + 0, (pixels >> 14) & 1);
|
set_pixel(x + 0, y + 0, (pixels >> 14) & 1);
|
||||||
|
@ -64,8 +70,9 @@ void draw_digit(u16 x, u16 y, u8 digit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_num(u16 x, u16 y, u32 num) {
|
void draw_num(u16 x, u16 y, u32 num) {
|
||||||
|
if (num == 0) draw_digit(x, y, num);
|
||||||
while (num) {
|
while (num) {
|
||||||
u8 digit = num%10;
|
u8 digit = num % 10;
|
||||||
num /= 10;
|
num /= 10;
|
||||||
draw_digit(x, y, digit);
|
draw_digit(x, y, digit);
|
||||||
x -= 4;
|
x -= 4;
|
||||||
|
@ -77,21 +84,35 @@ int main() {
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
tft_init_display(100 * 1000 * 1000); // max is 62.5MHz
|
tft_init_display(100 * 1000 * 1000); // max is 62.5MHz
|
||||||
|
|
||||||
|
u32 next_frame = time_us_32();
|
||||||
|
|
||||||
while (!error) {
|
while (!error) {
|
||||||
|
sleep_until(next_frame);
|
||||||
|
next_frame += MICROS_PER_FRAME;
|
||||||
decode_next_frame();
|
decode_next_frame();
|
||||||
|
#ifdef DEBUG_STUFF
|
||||||
|
draw_num(50, 2, error);
|
||||||
|
draw_num(25, 2, reader - 1);
|
||||||
|
draw_num(25, 8, video[reader - 1]);
|
||||||
|
draw_num(50, 8, video[reader]);
|
||||||
|
draw_num(25, 16, last_frame_start);
|
||||||
|
draw_num(25, 22, last_frame_type);
|
||||||
|
#endif
|
||||||
refresh_screen();
|
refresh_screen();
|
||||||
// sleep_ms(100);
|
// sleep_ms(100);
|
||||||
if (reader >= sizeof(video))
|
if (reader >= sizeof(video))
|
||||||
error = true;
|
error = 1;
|
||||||
// reader = 0;
|
// reader = 0;
|
||||||
}
|
}
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, 1);
|
#ifdef DEBUG_STUFF
|
||||||
draw_num(30, 2, reader-1);
|
gpio_put(PICO_DEFAULT_LED_PIN, 1);
|
||||||
draw_num(15, 8, video[reader-1]);
|
draw_num(30, 2, reader-1);
|
||||||
draw_num(30, 16, last_frame_start);
|
draw_num(15, 8, video[reader-1]);
|
||||||
draw_num(15, 22, last_frame_type);
|
draw_num(30, 16, last_frame_start);
|
||||||
refresh_screen();
|
draw_num(15, 22, last_frame_type);
|
||||||
while(1){};
|
refresh_screen();
|
||||||
|
#endif
|
||||||
|
// while(1){};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,14 +154,20 @@ void fill_frame(u8 color) {
|
||||||
|
|
||||||
void set_pixel(u16 x, u16 y, u8 color)
|
void set_pixel(u16 x, u16 y, u8 color)
|
||||||
{
|
{
|
||||||
// if (x >= WIDTH || y >= HEIGHT){
|
#ifdef DEBUG_STUFF
|
||||||
// while (1){
|
if (x >= WIDTH || y >= HEIGHT){
|
||||||
// gpio_put(PICO_DEFAULT_LED_PIN, 1);
|
draw_num(30, 30, x);
|
||||||
// sleep_ms(50);
|
draw_num(30, 36, y);
|
||||||
// gpio_put(PICO_DEFAULT_LED_PIN, 0);
|
draw_num(30, 42, color);
|
||||||
// sleep_ms(50);
|
refresh_screen();
|
||||||
// }
|
while (1) {
|
||||||
// }
|
gpio_put(PICO_DEFAULT_LED_PIN, 1);
|
||||||
|
sleep_ms(50);
|
||||||
|
gpio_put(PICO_DEFAULT_LED_PIN, 0);
|
||||||
|
sleep_ms(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
x = (WIDTH-1) - x;
|
x = (WIDTH-1) - x;
|
||||||
const u32 index = x * HEIGHT + y;
|
const u32 index = x * HEIGHT + y;
|
||||||
frame[index] = color;
|
frame[index] = color;
|
||||||
|
@ -148,9 +175,10 @@ void set_pixel(u16 x, u16 y, u8 color)
|
||||||
|
|
||||||
void rle_horizontal();
|
void rle_horizontal();
|
||||||
void rle_vertical();
|
void rle_vertical();
|
||||||
void rle_vertical_ext();
|
void rle_vertical_ext_2();
|
||||||
|
void rle_horizontal_ext_2();
|
||||||
void bg_strips_h();
|
void bg_strips_h();
|
||||||
void cell_diff_4vv();
|
void cell_diff_8();
|
||||||
|
|
||||||
void decode_next_frame()
|
void decode_next_frame()
|
||||||
{
|
{
|
||||||
|
@ -178,9 +206,14 @@ void decode_next_frame()
|
||||||
rle_vertical();
|
rle_vertical();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_RLEVerticalExt
|
#ifdef USE_RLEVerticalExt2
|
||||||
case Encoding_RLEVerticalExt:
|
case Encoding_RLEVerticalExt2:
|
||||||
rle_vertical_ext();
|
rle_vertical_ext_2();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_RLEHorizontalExt2
|
||||||
|
case Encoding_RLEHorizontalExt2:
|
||||||
|
rle_horizontal_ext_2();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_BGStripsH24
|
#ifdef USE_BGStripsH24
|
||||||
|
@ -188,13 +221,14 @@ void decode_next_frame()
|
||||||
bg_strips_h();
|
bg_strips_h();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_CellDiff4VV
|
#ifdef USE_CellDiff8VBig
|
||||||
case Encoding_CellDiff4VV:
|
case Encoding_CellDiff8VBig:
|
||||||
cell_diff_4vv();
|
cell_diff_8();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
error = true;
|
error = 99;
|
||||||
|
gpio_put(PICO_DEFAULT_LED_PIN, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
last_frame_type = encoding;
|
last_frame_type = encoding;
|
||||||
|
@ -227,11 +261,9 @@ void rle_vertical() {
|
||||||
u16 x = 0;
|
u16 x = 0;
|
||||||
u16 y = 0;
|
u16 y = 0;
|
||||||
u8 color = 0;
|
u8 color = 0;
|
||||||
while (x < WIDTH)
|
while (x < WIDTH) {
|
||||||
{
|
|
||||||
u16 run = next_byte();
|
u16 run = next_byte();
|
||||||
for (u16 i = 0; i < run; i++)
|
while (run--) {
|
||||||
{
|
|
||||||
set_pixel(x, y, color);
|
set_pixel(x, y, color);
|
||||||
y += 1;
|
y += 1;
|
||||||
if (y == HEIGHT) {
|
if (y == HEIGHT) {
|
||||||
|
@ -244,25 +276,22 @@ void rle_vertical() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RLEVerticalExt2
|
||||||
#ifdef USE_RLEVerticalExt
|
void rle_vertical_ext_2() {
|
||||||
void rle_vertical_ext() {
|
|
||||||
u16 x = 0;
|
u16 x = 0;
|
||||||
u16 y = 0;
|
u16 y = 0;
|
||||||
u8 color = 0;
|
u8 color = 0;
|
||||||
while (x < WIDTH) {
|
while (x < WIDTH) {
|
||||||
u8 byte = next_byte();
|
u8 byte = next_byte();
|
||||||
u16 run = byte;
|
u16 run = byte;
|
||||||
if (byte == 0 && video[reader] == 0) {
|
if (byte == 255) {
|
||||||
// 16 bit run length
|
// 16 bit run length
|
||||||
u16 upper = video[reader + 1] << 8;
|
u16 upper = (u16)video[reader] << 8;
|
||||||
if (upper) {
|
u16 lower = video[reader + 1];
|
||||||
u16 lower = video[reader + 2];
|
reader += 2;
|
||||||
run = upper | lower;
|
run = upper | lower;
|
||||||
reader += 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (u16 i = 0; i < run; i++) {
|
while (run--) {
|
||||||
set_pixel(x, y, color);
|
set_pixel(x, y, color);
|
||||||
y += 1;
|
y += 1;
|
||||||
if (y == HEIGHT) {
|
if (y == HEIGHT) {
|
||||||
|
@ -275,6 +304,34 @@ void rle_vertical_ext() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RLEHorizontalExt2
|
||||||
|
void rle_horizontal_ext_2() {
|
||||||
|
u16 x = 0;
|
||||||
|
u16 y = 0;
|
||||||
|
u8 color = 0;
|
||||||
|
while (y < HEIGHT) {
|
||||||
|
u8 byte = next_byte();
|
||||||
|
u16 run = byte;
|
||||||
|
if (byte == 255) {
|
||||||
|
// 16 bit run length
|
||||||
|
u16 upper = (u16)video[reader] << 8;
|
||||||
|
u16 lower = video[reader + 1];
|
||||||
|
reader += 2;
|
||||||
|
run = upper | lower;
|
||||||
|
}
|
||||||
|
while (run--) {
|
||||||
|
set_pixel(x, y, color);
|
||||||
|
x += 1;
|
||||||
|
if (x == WIDTH) {
|
||||||
|
x = 0;
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color = !color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BGStripsH24
|
#ifdef USE_BGStripsH24
|
||||||
void bg_strips_h() {
|
void bg_strips_h() {
|
||||||
u8 head = next_byte();
|
u8 head = next_byte();
|
||||||
|
@ -295,15 +352,49 @@ void bg_strips_h() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_CellDiff4VV
|
|
||||||
void cell_diff_4vv() {
|
|
||||||
const u32 cells_x = WIDTH/4;
|
|
||||||
const u32 cells_y = HEIGHT/4;
|
|
||||||
bool modified_cells[cells_x*cells_y];
|
|
||||||
|
|
||||||
|
#ifdef USE_CellDiff8VBig
|
||||||
|
void cell_diff_8() {
|
||||||
|
const u32 cells_x = WIDTH / 8;
|
||||||
|
const u32 cells_y = HEIGHT / 8;
|
||||||
|
u8 modified_cells[cells_x * cells_y];
|
||||||
|
|
||||||
for (u16 x = 0; x < WIDTH; x++) {
|
u16 cx = 0;
|
||||||
for (u16 y = 0; y < HEIGHT; y++) {
|
u16 cy = 0;
|
||||||
|
u8 filled = 0;
|
||||||
|
while (cx < cells_x) {
|
||||||
|
u8 run = next_byte();
|
||||||
|
while (run--) {
|
||||||
|
u32 index = cx * cells_y + cy;
|
||||||
|
modified_cells[index] = filled;
|
||||||
|
cy += 1;
|
||||||
|
if (cy == cells_y) {
|
||||||
|
cy = 0;
|
||||||
|
cx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filled = !filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 run = 0;
|
||||||
|
u16 x = 0;
|
||||||
|
u16 y = 0;
|
||||||
|
u8 color = 1;
|
||||||
|
while (x < WIDTH) {
|
||||||
|
u16 ccx = x / 8;
|
||||||
|
u16 ccy = y / 8;
|
||||||
|
if (modified_cells[ccx * cells_y + ccy]) {
|
||||||
|
while (run == 0) {
|
||||||
|
run = next_byte();
|
||||||
|
color = !color;
|
||||||
|
}
|
||||||
|
run -= 1;
|
||||||
|
set_pixel(x, y, color);
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
if (y == HEIGHT) {
|
||||||
|
y = 0;
|
||||||
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue