add RLEVerticalExt (16 bit run length support)

This commit is contained in:
Crispy 2025-06-16 23:46:01 +02:00
parent 90f648e0b0
commit 62ee8a6efa
8 changed files with 77689 additions and 106875 deletions

View file

@ -4,7 +4,8 @@
"name": "Linux", "name": "Linux",
"includePath": [ "includePath": [
"${workspaceFolder}/**", "${workspaceFolder}/**",
"${workspaceFolder}/../ch32v003fun/ch32v003fun" "${workspaceFolder}/../ch32v003fun/ch32v003fun",
"${workspaceFolder}/../pico-sdk/**"
], ],
"defines": [], "defines": [],
"compilerPath": "/usr/bin/clang", "compilerPath": "/usr/bin/clang",

View file

@ -1,6 +1,6 @@
use crate::*; use crate::*;
pub fn cell_diff_4_vertical_small(prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame { pub fn cell_diff_4_vertical(prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame {
const CELLS_X: usize = WIDTH / 4; const CELLS_X: usize = WIDTH / 4;
const CELLS_Y: usize = HEIGHT / 4; const CELLS_Y: usize = HEIGHT / 4;
@ -126,7 +126,6 @@ pub fn bg_strips_horizontal24(_prev_frame: &Frame, encoded: &[u8], reader: &mut
frame frame
} }
pub fn rle_diff_horizontal(prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame { pub fn rle_diff_horizontal(prev_frame: &Frame, encoded: &[u8], reader: &mut usize) -> Frame {
let (runs, decoded) = rle_255_decode(encoded, FRAME_SIZE); let (runs, decoded) = rle_255_decode(encoded, FRAME_SIZE);
*reader += runs; *reader += runs;
@ -187,6 +186,41 @@ pub fn rle_vertical(_prev_frame: &Frame, encoded: &[u8], reader: &mut usize) ->
frame frame
} }
pub fn rle_vertical_ext(_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 == 0 && encoded[i] == 0 {
// 16 bit run length
let upper = (encoded[i+1] as u16) << 8;
if upper > 0{
let lower = encoded[i + 2] as u16;
i += 3;
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 fill_white(_prev_frame: &Frame, _encoded: &[u8], _reader: &mut usize) -> Frame { pub fn fill_white(_prev_frame: &Frame, _encoded: &[u8], _reader: &mut usize) -> Frame {
FRAME_1 FRAME_1
} }

View file

@ -1,6 +1,6 @@
use crate::*; use crate::*;
pub fn cell_diff_4_vertical_small(prev_frame: &Frame, frame: &Frame, loss: usize) -> EncodedFrame { pub fn cell_diff_4_vertical(prev_frame: &Frame, frame: &Frame, loss: usize) -> EncodedFrame {
let loss = loss / 4; let loss = loss / 4;
const CELLS_X: usize = WIDTH / 4; const CELLS_X: usize = WIDTH / 4;
const CELLS_Y: usize = HEIGHT / 4; const CELLS_Y: usize = HEIGHT / 4;
@ -48,7 +48,7 @@ pub fn cell_diff_4_vertical_small(prev_frame: &Frame, frame: &Frame, loss: usize
data.extend_from_slice(&rle_255_encode(&changed_pixels)); data.extend_from_slice(&rle_255_encode(&changed_pixels));
EncodedFrame { EncodedFrame {
encoding: Encoding::CellDiff4VV_small, encoding: Encoding::CellDiff4VV,
data, data,
} }
} }
@ -306,6 +306,48 @@ pub fn rle_vertical(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame {
} }
} }
pub fn rle_vertical_ext(_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 < 256 {
data.push(run as u8);
} else {
// double zero to mark 16 bit run length
// if data.last() != Some(&0) {
// }
data.push(0);
data.push(0);
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::RLEVerticalExt,
data,
}
}
pub fn fill_white(_prev_frame: &Frame, _frame: &Frame, _loss: usize) -> EncodedFrame { pub fn fill_white(_prev_frame: &Frame, _frame: &Frame, _loss: usize) -> EncodedFrame {
EncodedFrame { EncodedFrame {
encoding: Encoding::FillWhite, encoding: Encoding::FillWhite,

View file

@ -16,17 +16,18 @@ const MAX_LOSS: usize = 16; // highest "loss" value tried for all lossy encoding
const LOSSLESS_ENCODINGS: &[FrameEncoder] = &[ const LOSSLESS_ENCODINGS: &[FrameEncoder] = &[
enc::rle_horizontal, enc::rle_horizontal,
enc::rle_vertical, enc::rle_vertical,
enc::rle_diff_horizontal, enc::rle_vertical_ext,
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
]; ];
const LOSSY_ENCODINGS: &[FrameEncoderLossy] = &[ const LOSSY_ENCODINGS: &[FrameEncoderLossy] = &[
enc::fill_white, enc::fill_white,
enc::fill_black, enc::fill_black,
// todo: adapt these for big display // todo: adapt for big display
// enc::cell_diff_8_vertical, // enc::cell_diff_8_vertical,
// enc::cell_diff_4_vertical_small, // enc::cell_diff_4_vertical,
]; ];
fn main() { fn main() {
@ -80,6 +81,7 @@ fn main() {
} }
export_string += "} Encoding_t;\n\n"; export_string += "} Encoding_t;\n\n";
export_string += "const unsigned char video[] = {"; export_string += "const unsigned char video[] = {";
// export_string += &format!("const unsigned char video[{}] = {{", encoded.len());
let mut i = 99; let mut i = 99;
for byte in encoded { for byte in encoded {
if i > 15 { if i > 15 {
@ -108,7 +110,9 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
options.push(encoded); options.push(encoded);
} else { } else {
dbg!(&encoded); dbg!(&encoded);
eprintln!("{:?}, error: {error}, frame: {_i}", encoded.encoding);
println!("{:?}, error: {error}, frame: {_i}", encoded.encoding); println!("{:?}, error: {error}, frame: {_i}", encoded.encoding);
println!("original | decoded");
render_images(&frame, &decoded); render_images(&frame, &decoded);
panic!("error in lossless compression"); panic!("error in lossless compression");
} }
@ -161,6 +165,7 @@ enum Encoding {
FillWhite, FillWhite,
RLEHorizontal, RLEHorizontal,
RLEVertical, RLEVertical,
RLEVerticalExt,
RLEDiffHorizontal, RLEDiffHorizontal,
RLEDiffVertical, RLEDiffVertical,
BGStripsH16, BGStripsH16,
@ -173,7 +178,7 @@ enum Encoding {
// CellDiff4HH, // CellDiff4HH,
// CellDiff4HV, // CellDiff4HV,
// CellDiff4VH, // CellDiff4VH,
CellDiff4VV_small, CellDiff4VV,
// CellDiff4VV_large, // CellDiff4VV_large,
} }
@ -183,6 +188,7 @@ 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::RLEVertical => dec::rle_vertical, Encoding::RLEVertical => dec::rle_vertical,
Encoding::RLEVerticalExt => dec::rle_vertical_ext,
Encoding::RLEDiffHorizontal => dec::rle_diff_horizontal, Encoding::RLEDiffHorizontal => dec::rle_diff_horizontal,
Encoding::RLEDiffVertical => dec::rle_diff_vertical, Encoding::RLEDiffVertical => dec::rle_diff_vertical,
Encoding::BGStripsH16 => dec::bg_strips_horizontal16, Encoding::BGStripsH16 => dec::bg_strips_horizontal16,
@ -195,8 +201,7 @@ fn get_matching_decoder(encoding: Encoding) -> FrameDecoder {
// Encoding::CellDiff4HH => todo!(), // Encoding::CellDiff4HH => todo!(),
// Encoding::CellDiff4HV => todo!(), // Encoding::CellDiff4HV => todo!(),
// Encoding::CellDiff4VH => todo!(), // Encoding::CellDiff4VH => todo!(),
Encoding::CellDiff4VV_small => dec::cell_diff_4_vertical_small, Encoding::CellDiff4VV => dec::cell_diff_4_vertical,
// Encoding::CellDiff4VV_large => dec::cell_diff_4_vertical_large,
} }
} }

View file

@ -1,121 +0,0 @@
BGStripsH24, error: 868, frame: 14
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ▀█████| ▀█████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| █████| █████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ██████| ██████|
| ███████| ███████|
| ███████| ███████|
| ███████| ███████|
| ███████| ███████|
| ███████| ███████|
| ███████| ███████|
| ███████| ███████|
| ▄███████| ▄███████|
| ████████| ████████|
| ████████| ████████|
| ████████| ████████|
| ████████| ████████|
| ████████| ████████|
| ████████| ████████|
| ▄████████| ▄████████|
| █████████| █████████|
| █████████| █████████|
| █████████| █████████|
| █████████| █████████|
| ██████████| ██████████|
| ██████████| ██████████|
| ███████████| ███████████|
| ███████████| ███████████|
| ▄███████████| ▄███████████|
| ████████████| ████████████|
| ▄████████████| ▄████████████|
| █████████████| █████████████|
| ▄█████████████| ▄█████████████|
| ██████████████| ██████████████|
| ▄██████████████| ▄██████████████|
| ███████████████| ███████████████|
| ▄███████████████| ▄███████████████|
| ████████████████| ████████████████|
| ▄████████████████| ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀|
| █████████████████| |
| ▄█████████████████| |
| ██████████████████| |
| ▄██████████████████| |
| ███████████████████| |
| ███████████████████| |
| ███████████████████| |
| ███████████████████| |
| ▀██████████████████| |
| ██████████████████| |
| ██████████████████| |
| ██████████████████| |
| ██████████████████| |
| ██████████████████| |
| ██████████████████| |
| █ ██████████████████| |
| ██ ██████████████████| |
| ███ ██████████████████| |
| ▀▀█▄ ██████████████████| |
| ██████████████████| |
| ▀█████████████████| |
| ▀██████████████| |
| ▀▀██████████| |
| ▀▀██████| |
| ▀▀██| |
| ▀| |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |

View file

@ -1,6 +1,7 @@
build_thing: build_thing:
cmake -B bin -DPICO_SDK_PATH=../../pico-sdk cmake -B bin -DPICO_SDK_PATH=../../pico-sdk
# -DCMAKE_CXX_FLAGS=-Oz
make -j8 -C bin make -j8 -C bin
# then manually copy bin/thing.uf2 to the pico # then manually copy bin/thing.uf2 to the pico

File diff suppressed because it is too large Load diff

View file

@ -75,21 +75,21 @@ void draw_num(u16 x, u16 y, u32 num) {
int main() { int main() {
gpio_init(PICO_DEFAULT_LED_PIN); gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
gpio_put(PICO_DEFAULT_LED_PIN, 1);
tft_init_display(100 * 1000 * 1000); // max is 62.5MHz tft_init_display(100 * 1000 * 1000); // max is 62.5MHz
// tft_fill(0); // tft_fill(0);
while (!error) { while (!error) {
decode_next_frame(); decode_next_frame();
draw_num(30,2, reader);
draw_num(15, 8, video[reader]);
refresh_screen(); refresh_screen();
sleep_ms(100); // sleep_ms(100);
if (reader >= sizeof(video)) if (reader >= sizeof(video))
reader = 0; error = true;
// reader = 0;
} }
gpio_put(PICO_DEFAULT_LED_PIN, 1); gpio_put(PICO_DEFAULT_LED_PIN, 1);
draw_num(30, 2, reader); draw_num(30, 2, reader-1);
draw_num(15, 8, video[reader]); draw_num(15, 8, video[reader-1]);
draw_num(30, 16, last_frame_start); draw_num(30, 16, last_frame_start);
draw_num(15, 22, last_frame_type); draw_num(15, 22, last_frame_type);
refresh_screen(); refresh_screen();
@ -106,7 +106,7 @@ void refresh_screen() {
DC_D; DC_D;
u32 pixel_count = AREA; u32 pixel_count = AREA;
const u8 pixels[2] = {0, 176}; const u8 pixels[2] = {0, 255};
while (pixel_count--) { while (pixel_count--) {
u8 p = pixels[frame[pixel_count]]; u8 p = pixels[frame[pixel_count]];
@ -135,14 +135,14 @@ 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){ // if (x >= WIDTH || y >= HEIGHT){
while (1){ // while (1){
gpio_put(PICO_DEFAULT_LED_PIN, 1); // gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(50); // sleep_ms(50);
gpio_put(PICO_DEFAULT_LED_PIN, 0); // gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(50); // sleep_ms(50);
} // }
} // }
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;
@ -150,6 +150,7 @@ 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 bg_strips_h(); void bg_strips_h();
void cell_diff_4vv(); void cell_diff_4vv();
@ -179,13 +180,18 @@ void decode_next_frame()
rle_vertical(); rle_vertical();
break; break;
#endif #endif
#ifdef USE_RLEVerticalExt
case Encoding_RLEVerticalExt:
rle_vertical_ext();
break;
#endif
#ifdef USE_BGStripsH24 #ifdef USE_BGStripsH24
case Encoding_BGStripsH24: case Encoding_BGStripsH24:
bg_strips_h(); bg_strips_h();
break; break;
#endif #endif
#ifdef USE_CellDiff4VV_small #ifdef USE_CellDiff4VV
case Encoding_CellDiff4VV_small: case Encoding_CellDiff4VV:
cell_diff_4vv(); cell_diff_4vv();
break; break;
#endif #endif
@ -219,8 +225,7 @@ void rle_horizontal()
#endif #endif
#ifdef USE_RLEVertical #ifdef USE_RLEVertical
void rle_vertical() void rle_vertical() {
{
u16 x = 0; u16 x = 0;
u16 y = 0; u16 y = 0;
u8 color = 0; u8 color = 0;
@ -241,9 +246,39 @@ void rle_vertical()
} }
#endif #endif
#ifdef USE_RLEVerticalExt
void rle_vertical_ext() {
u16 x = 0;
u16 y = 0;
u8 color = 0;
while (x < WIDTH) {
u8 byte = next_byte();
u16 run = byte;
if (byte == 0 && video[reader] == 0) {
// 16 bit run length
u16 upper = video[reader + 1] << 8;
if (upper) {
u16 lower = video[reader + 2];
run = upper | lower;
reader += 3;
}
}
for (u16 i = 0; i < run; i++) {
set_pixel(x, y, color);
y += 1;
if (y == HEIGHT) {
y = 0;
x += 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();
u8 bg = head >> 7; u8 bg = head >> 7;
u8 fg = 1 - bg; u8 fg = 1 - bg;
@ -262,7 +297,7 @@ void bg_strips_h()
} }
#endif #endif
#ifdef USE_CellDiff4VV_small #ifdef USE_CellDiff4VV
void cell_diff_4vv() { void cell_diff_4vv() {
const u32 cells_x = WIDTH/4; const u32 cells_x = WIDTH/4;
const u32 cells_y = HEIGHT/4; const u32 cells_y = HEIGHT/4;