From da4df3287812278aa2e3f67b1e4ebee5b56e50a5 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Thu, 16 May 2024 23:03:07 +0200 Subject: [PATCH] add new compression commands to BitmapLinearWin --- examples/game_of_life/src/main.rs | 5 +- examples/moving_line/src/main.rs | 4 +- examples/random_brightness/src/main.rs | 6 +- examples/wiping_clear/src/main.rs | 10 +- servicepoint2-binding-c/servicepoint2.h | 3 +- .../src/BindGen/ServicePoint2.g.cs | 2 +- servicepoint2/src/command.rs | 106 +++++++++++------- servicepoint2/src/command_code.rs | 8 +- 8 files changed, 84 insertions(+), 60 deletions(-) diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index c560d21..c93092a 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -4,7 +4,7 @@ use std::time::Duration; use clap::Parser; use rand::{distributions, Rng}; -use servicepoint2::{Command, Connection, Origin, PixelGrid}; +use servicepoint2::{Command, CompressionCode, Connection, Origin, PixelGrid}; #[derive(Parser, Debug)] struct Cli { @@ -23,7 +23,7 @@ fn main() { loop { connection - .send(Command::BitmapLinearWin(Origin::top_left(), field.clone()).into()) + .send(Command::BitmapLinearWin(Origin::top_left(), field.clone(), CompressionCode::Bzip2).into()) .expect("could not send"); thread::sleep(Duration::from_millis(30)); field = iteration(field); @@ -36,6 +36,7 @@ fn iteration(field: PixelGrid) -> PixelGrid { for y in 0..field.height { let old_state = field.get(x, y); let neighbors = count_neighbors(&field, x as i32, y as i32); + let new_state = matches!((old_state, neighbors), (true, 2) | (true, 3) | (false, 3)); next.set(x, y, new_state); } diff --git a/examples/moving_line/src/main.rs b/examples/moving_line/src/main.rs index 5a7ee42..b42962d 100644 --- a/examples/moving_line/src/main.rs +++ b/examples/moving_line/src/main.rs @@ -3,7 +3,7 @@ use std::time::Duration; use clap::Parser; -use servicepoint2::{Command, Connection, Origin, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid}; +use servicepoint2::{Command, CompressionCode, Connection, Origin, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid}; #[derive(Parser, Debug)] struct Cli { @@ -24,7 +24,7 @@ fn main() { pixels.set((y + x_offset) % PIXEL_WIDTH as usize, y, true); } connection - .send(Command::BitmapLinearWin(Origin::top_left(), pixels.clone()).into()) + .send(Command::BitmapLinearWin(Origin::top_left(), pixels.clone(), CompressionCode::Lzma).into()) .unwrap(); thread::sleep(Duration::from_millis(14)); } diff --git a/examples/random_brightness/src/main.rs b/examples/random_brightness/src/main.rs index e764036..eff7a25 100644 --- a/examples/random_brightness/src/main.rs +++ b/examples/random_brightness/src/main.rs @@ -4,9 +4,7 @@ use clap::Parser; use rand::Rng; use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness}; -use servicepoint2::{ - ByteGrid, Connection, Origin, PixelGrid, TILE_HEIGHT, TILE_WIDTH, -}; +use servicepoint2::{ByteGrid, CompressionCode, Connection, Origin, PixelGrid, TILE_HEIGHT, TILE_WIDTH}; #[derive(Parser, Debug)] struct Cli { @@ -30,7 +28,7 @@ fn main() { let mut filled_grid = PixelGrid::max_sized(); filled_grid.fill(true); connection - .send(BitmapLinearWin(Origin::top_left(), filled_grid).into()) + .send(BitmapLinearWin(Origin::top_left(), filled_grid, CompressionCode::Lzma).into()) .unwrap(); } diff --git a/examples/wiping_clear/src/main.rs b/examples/wiping_clear/src/main.rs index bec8385..d27492f 100644 --- a/examples/wiping_clear/src/main.rs +++ b/examples/wiping_clear/src/main.rs @@ -3,7 +3,7 @@ use std::time::Duration; use clap::Parser; -use servicepoint2::{BitVec, Command, CompressionCode, Connection, Origin, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid}; +use servicepoint2::{BitVec, Command, CompressionCode, Connection, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid}; #[derive(Parser, Debug)] struct Cli { @@ -16,16 +16,10 @@ struct Cli { fn main() { env_logger::init(); let cli = Cli::parse(); + let sleep_duration = Duration::from_millis(cli.time / PIXEL_WIDTH as u64); let connection = Connection::open(cli.destination).unwrap(); - let mut buf = PixelGrid::max_sized(); - buf.fill(true); - connection.send(Command::BitmapLinearWin(Origin(0, 0), buf).into()) - .expect("send failed"); - - let sleep_duration = Duration::from_millis(cli.time / PIXEL_WIDTH as u64); - let mut enabled_pixels = PixelGrid::new(PIXEL_WIDTH as usize, PIXEL_HEIGHT as usize); enabled_pixels.fill(true); diff --git a/servicepoint2-binding-c/servicepoint2.h b/servicepoint2-binding-c/servicepoint2.h index 717bf35..3d606f9 100644 --- a/servicepoint2-binding-c/servicepoint2.h +++ b/servicepoint2-binding-c/servicepoint2.h @@ -284,7 +284,8 @@ struct sp2_Command *sp2_command_bitmap_linear_or(sp2_Offset offset, */ struct sp2_Command *sp2_command_bitmap_linear_win(uint16_t x, uint16_t y, - struct sp2_PixelGrid *byte_grid); + struct sp2_PixelGrid *byte_grid, + sp2_CompressionCode compression_code); /** * Allocates a new `Command::BitmapLinearXor` instance. diff --git a/servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs b/servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs index f4e3d53..2fb4fef 100644 --- a/servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs +++ b/servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs @@ -149,7 +149,7 @@ namespace ServicePoint2.BindGen /// Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets deallocated in the process. [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp2_command_bitmap_linear_win(ushort x, ushort y, PixelGrid* byte_grid); + public static extern Command* sp2_command_bitmap_linear_win(ushort x, ushort y, PixelGrid* byte_grid, CompressionCode compression_code); /// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need to do this if you use the library for parsing commands. [DllImport(__DllName, EntryPoint = "sp2_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] diff --git a/servicepoint2/src/command.rs b/servicepoint2/src/command.rs index 4b7b2fe..1a9e2d0 100644 --- a/servicepoint2/src/command.rs +++ b/servicepoint2/src/command.rs @@ -1,7 +1,4 @@ -use crate::{ - BitVec, ByteGrid, CompressionCode, Header, Packet, PixelGrid, - TILE_SIZE, -}; +use crate::{BitVec, ByteGrid, CompressionCode, Header, Packet, PixelGrid, TILE_SIZE}; use crate::command_code::CommandCode; use crate::compression::{into_compressed, into_decompressed}; @@ -56,7 +53,7 @@ pub enum Command { /// Show text on the screen. Note that the byte data has to be CP437 encoded. Cp437Data(Origin, ByteGrid), /// Sets a window of pixels to the specified values - BitmapLinearWin(Origin, PixelGrid), + BitmapLinearWin(Origin, PixelGrid, CompressionCode), } impl From for Packet { @@ -85,18 +82,25 @@ impl From for Packet { ), vec![brightness], ), - Command::BitmapLinearWin(Origin(pixel_x, pixel_y), pixels) => { + Command::BitmapLinearWin(Origin(pixel_x, pixel_y), pixels, compression) => { debug_assert_eq!(pixel_x % 8, 0); debug_assert_eq!(pixels.width % 8, 0); + + let tile_x = pixel_x / TILE_SIZE; + let tile_w = pixels.width as u16 / TILE_SIZE; + let pixel_h = pixels.height as u16; + let payload = into_compressed(compression, pixels.into()); + let command = match compression { + CompressionCode::Uncompressed => CommandCode::BitmapLinearWinUncompressed, + CompressionCode::Zlib => CommandCode::BitmapLinearWinZlib, + CompressionCode::Bzip2 => CommandCode::BitmapLinearWinBzip2, + CompressionCode::Lzma => CommandCode::BitmapLinearWinLzma, + CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd, + }; + Packet( - Header( - CommandCode::BitmapLinearWin.into(), - pixel_x / TILE_SIZE, - pixel_y, - pixels.width as u16 / TILE_SIZE, - pixels.height as u16, - ), - pixels.into(), + Header(command.into(), tile_x, pixel_y, tile_w, pixel_h), + payload, ) } Command::BitmapLinear(offset, bits, compression) => { @@ -160,8 +164,8 @@ impl TryFrom for Command { type Error = TryFromPacketError; /// Try to interpret the `Packet` as one containing a `Command` - fn try_from(value: Packet) -> Result { - let Packet(Header(command_u16, a, b, c, d), _) = value; + fn try_from(packet: Packet) -> Result { + let Packet(Header(command_u16, a, b, c, d), _) = packet; let command_code = match CommandCode::try_from(command_u16) { Err(_) => { return Err(TryFromPacketError::InvalidCommand(command_u16)); @@ -170,12 +174,12 @@ impl TryFrom for Command { }; match command_code { - CommandCode::Clear => match check_command_only(value) { + CommandCode::Clear => match check_command_only(packet) { Some(err) => Err(err), None => Ok(Command::Clear), }, CommandCode::Brightness => { - let Packet(header, payload) = value; + let Packet(header, payload) = packet; if payload.len() != 1 { return Err(TryFromPacketError::UnexpectedPayloadSize( 1, @@ -190,23 +194,23 @@ impl TryFrom for Command { Ok(Command::Brightness(payload[0])) } } - CommandCode::HardReset => match check_command_only(value) { + CommandCode::HardReset => match check_command_only(packet) { Some(err) => Err(err), None => Ok(Command::HardReset), }, - CommandCode::FadeOut => match check_command_only(value) { + CommandCode::FadeOut => match check_command_only(packet) { Some(err) => Err(err), None => Ok(Command::FadeOut), }, CommandCode::Cp437Data => { - let Packet(_, payload) = value; + let Packet(_, payload) = packet; Ok(Command::Cp437Data( Origin(a, b), ByteGrid::load(c as usize, d as usize, &payload), )) } CommandCode::CharBrightness => { - let Packet(_, payload) = value; + let Packet(_, payload) = packet; Ok(Command::CharBrightness( Origin(a, b), ByteGrid::load(c as usize, d as usize, &payload), @@ -214,37 +218,60 @@ impl TryFrom for Command { } #[allow(deprecated)] CommandCode::BitmapLegacy => Ok(Command::BitmapLegacy), - CommandCode::BitmapLinearWin => { - let Packet(_, payload) = value; - Ok(Command::BitmapLinearWin( - Origin(a * TILE_SIZE, b), - PixelGrid::load( - c as usize * TILE_SIZE as usize, - d as usize, - &payload, - ), - )) - } CommandCode::BitmapLinear => { - let (vec, compression) = packet_into_linear_bitmap(value)?; + let (vec, compression) = packet_into_linear_bitmap(packet)?; Ok(Command::BitmapLinear(a, vec, compression)) } CommandCode::BitmapLinearAnd => { - let (vec, compression) = packet_into_linear_bitmap(value)?; + let (vec, compression) = packet_into_linear_bitmap(packet)?; Ok(Command::BitmapLinearAnd(a, vec, compression)) } CommandCode::BitmapLinearOr => { - let (vec, compression) = packet_into_linear_bitmap(value)?; + let (vec, compression) = packet_into_linear_bitmap(packet)?; Ok(Command::BitmapLinearOr(a, vec, compression)) } CommandCode::BitmapLinearXor => { - let (vec, compression) = packet_into_linear_bitmap(value)?; + let (vec, compression) = packet_into_linear_bitmap(packet)?; Ok(Command::BitmapLinearXor(a, vec, compression)) } + CommandCode::BitmapLinearWinUncompressed => { + packet_into_bitmap_win(packet, CompressionCode::Uncompressed) + } + CommandCode::BitmapLinearWinZlib => { + packet_into_bitmap_win(packet, CompressionCode::Zlib) + } + CommandCode::BitmapLinearWinBzip2 => { + packet_into_bitmap_win(packet, CompressionCode::Bzip2) + } + CommandCode::BitmapLinearWinLzma => { + packet_into_bitmap_win(packet, CompressionCode::Lzma) + } + CommandCode::BitmapLinearWinZstd => { + packet_into_bitmap_win(packet, CompressionCode::Zstd) + } } } } +fn packet_into_bitmap_win(packet: Packet, compression: CompressionCode) -> Result { + let Packet(Header(_, tiles_x, pixels_y, tile_w, pixel_h), payload) = packet; + + let payload = match into_decompressed(compression, payload) { + None => return Err(TryFromPacketError::DecompressionFailed), + Some(decompressed) => decompressed, + }; + + Ok(Command::BitmapLinearWin( + Origin(tiles_x * TILE_SIZE, pixels_y), + PixelGrid::load( + tile_w as usize * TILE_SIZE as usize, + pixel_h as usize, + &payload, + ), + CompressionCode::Uncompressed, + )) +} + /// Helper method for BitMapLinear*-Commands into Packet fn bitmap_linear_into_packet( command: CommandCode, @@ -315,7 +342,6 @@ pub mod c_api use crate::{BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin, Packet, PixelGrid}; - /// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process. /// /// Returns: pointer to command or NULL @@ -409,9 +435,9 @@ pub mod c_api /// Allocates a new `Command::BitmapLinearWin` instance. /// The passed `PixelGrid` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn sp2_command_bitmap_linear_win(x: u16, y: u16, byte_grid: *mut PixelGrid) -> *mut Command { + pub unsafe extern "C" fn sp2_command_bitmap_linear_win(x: u16, y: u16, byte_grid: *mut PixelGrid, compression_code: CompressionCode) -> *mut Command { let byte_grid = *Box::from_raw(byte_grid); - Box::into_raw(Box::new(Command::BitmapLinearWin(Origin(x, y), byte_grid))) + Box::into_raw(Box::new(Command::BitmapLinearWin(Origin(x, y), byte_grid, compression_code))) } /// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need diff --git a/servicepoint2/src/command_code.rs b/servicepoint2/src/command_code.rs index 4c77a23..0331573 100644 --- a/servicepoint2/src/command_code.rs +++ b/servicepoint2/src/command_code.rs @@ -11,10 +11,14 @@ pub(crate) enum CommandCode { #[deprecated] BitmapLegacy = 0x0010, BitmapLinear = 0x0012, - BitmapLinearWin = 0x0013, + BitmapLinearWinUncompressed = 0x0013, BitmapLinearAnd = 0x0014, BitmapLinearOr = 0x0015, BitmapLinearXor = 0x0016, + BitmapLinearWinZlib = 0x0017, + BitmapLinearWinBzip2 = 0x0018, + BitmapLinearWinLzma = 0x0019, + BitmapLinearWinZstd = 0x001A, } impl From for u16 { @@ -41,7 +45,7 @@ impl TryFrom for CommandCode { #[allow(deprecated)] value if value == BitmapLegacy as u16 => Ok(BitmapLegacy), value if value == BitmapLinear as u16 => Ok(BitmapLinear), - value if value == BitmapLinearWin as u16 => Ok(BitmapLinearWin), + value if value == BitmapLinearWinUncompressed as u16 => Ok(BitmapLinearWinUncompressed), value if value == BitmapLinearAnd as u16 => Ok(BitmapLinearAnd), value if value == BitmapLinearOr as u16 => Ok(BitmapLinearOr), value if value == BitmapLinearXor as u16 => Ok(BitmapLinearXor),