mirror of
https://github.com/cccb/servicepoint.git
synced 2025-01-18 10:00:14 +01:00
move grid functions to trait
This commit is contained in:
parent
314bec36f3
commit
bcf040911d
14
README.md
14
README.md
|
@ -63,15 +63,13 @@ int main(void) {
|
||||||
|
|
||||||
sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
|
sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
|
||||||
sp2_pixel_grid_fill(pixels, true);
|
sp2_pixel_grid_fill(pixels, true);
|
||||||
|
|
||||||
command = sp2_command_bitmap_linear_win(0, 0, pixels); // pixels get consumed here
|
|
||||||
if (command == NULL)
|
|
||||||
return 4;
|
|
||||||
if (!sp2_connection_send(connection, command)) // command gets consumed here
|
|
||||||
return 5;
|
|
||||||
|
|
||||||
// connection does not get consumed and has to be freed manually
|
sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
||||||
sp2_connection_dealloc(connection);
|
sp2_Packet *packet = sp2_packet_from_command(command);
|
||||||
|
if (!sp2_connection_send(connection, packet))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
sp2_connection_dealloc(connection);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use servicepoint2::{ByteGrid, Command, Connection, Origin};
|
use servicepoint2::{ByteGrid, Command, Connection, Grid, Origin};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
|
|
@ -3,9 +3,7 @@ use std::thread;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use rand::{distributions, Rng};
|
use rand::{distributions, Rng};
|
||||||
|
|
||||||
use servicepoint2::{
|
use servicepoint2::{Command, CompressionCode, Connection, Origin, PixelGrid, FRAME_PACING, Grid};
|
||||||
Command, CompressionCode, Connection, Origin, PixelGrid, FRAME_PACING,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
|
|
@ -2,10 +2,7 @@ use std::thread;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use servicepoint2::{
|
use servicepoint2::{Command, CompressionCode, Connection, Origin, PixelGrid, FRAME_PACING, PIXEL_HEIGHT, PIXEL_WIDTH, Grid};
|
||||||
Command, CompressionCode, Connection, Origin, PixelGrid, FRAME_PACING,
|
|
||||||
PIXEL_HEIGHT, PIXEL_WIDTH,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
|
|
@ -4,10 +4,7 @@ use clap::Parser;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness};
|
use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness};
|
||||||
use servicepoint2::{
|
use servicepoint2::{ByteGrid, CompressionCode, Connection, Grid, Origin, PixelGrid, TILE_HEIGHT, TILE_WIDTH};
|
||||||
ByteGrid, CompressionCode, Connection, Origin, PixelGrid, TILE_HEIGHT,
|
|
||||||
TILE_WIDTH,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
|
|
@ -3,10 +3,7 @@ use std::time::Duration;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use servicepoint2::{
|
use servicepoint2::{BitVec, Command, CompressionCode, Connection, PixelGrid, FRAME_PACING, PIXEL_HEIGHT, PIXEL_WIDTH, Grid};
|
||||||
BitVec, Command, CompressionCode, Connection, PixelGrid, FRAME_PACING,
|
|
||||||
PIXEL_HEIGHT, PIXEL_WIDTH,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::Grid;
|
||||||
|
|
||||||
/// A 2D grid of bytes
|
/// A 2D grid of bytes
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ByteGrid {
|
pub struct ByteGrid {
|
||||||
|
@ -34,40 +36,11 @@ impl ByteGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current value at the specified position
|
|
||||||
///
|
|
||||||
/// returns: current byte value
|
|
||||||
pub fn get(&self, x: usize, y: usize) -> u8 {
|
|
||||||
self.check_indexes(x, y);
|
|
||||||
self.data[x + y * self.width]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the byte value at the specified position
|
|
||||||
pub fn set(&mut self, x: usize, y: usize, value: u8) {
|
|
||||||
self.check_indexes(x, y);
|
|
||||||
self.data[x + y * self.width] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets all bytes in the grid to the specified value
|
|
||||||
pub fn fill(&mut self, value: u8) {
|
|
||||||
self.data.fill(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the underlying byte rows
|
/// Get the underlying byte rows
|
||||||
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
||||||
self.data.as_mut_slice()
|
self.data.as_mut_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// the size in x-direction
|
|
||||||
pub fn width(&self) -> usize {
|
|
||||||
self.width
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the height in y-direction
|
|
||||||
pub fn height(&self) -> usize {
|
|
||||||
self.height
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_indexes(&self, x: usize, y: usize) {
|
fn check_indexes(&self, x: usize, y: usize) {
|
||||||
if x >= self.width {
|
if x >= self.width {
|
||||||
panic!("cannot access byte {x}-{y} because x is outside of bounds 0..{}", self.width)
|
panic!("cannot access byte {x}-{y} because x is outside of bounds 0..{}", self.width)
|
||||||
|
@ -78,6 +51,34 @@ impl ByteGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Grid<u8> for ByteGrid {
|
||||||
|
fn set(&mut self, x: usize, y: usize, value: u8) -> u8 {
|
||||||
|
self.check_indexes(x, y);
|
||||||
|
let pos = &mut self.data[x + y * self.width];
|
||||||
|
let old_val = *pos;
|
||||||
|
*pos = value;
|
||||||
|
old_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, x: usize, y: usize) -> u8 {
|
||||||
|
self.check_indexes(x, y);
|
||||||
|
self.data[x + y * self.width]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill(&mut self, value: u8) {
|
||||||
|
self.data.fill(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl From<ByteGrid> for Vec<u8> {
|
impl From<ByteGrid> for Vec<u8> {
|
||||||
/// Turn into the underlying `Vec<u8>` containing the rows of bytes.
|
/// Turn into the underlying `Vec<u8>` containing the rows of bytes.
|
||||||
fn from(value: ByteGrid) -> Self {
|
fn from(value: ByteGrid) -> Self {
|
||||||
|
@ -88,6 +89,7 @@ impl From<ByteGrid> for Vec<u8> {
|
||||||
#[cfg(feature = "c_api")]
|
#[cfg(feature = "c_api")]
|
||||||
pub mod c_api {
|
pub mod c_api {
|
||||||
use crate::{ByteGrid, CByteSlice};
|
use crate::{ByteGrid, CByteSlice};
|
||||||
|
use crate::grid::Grid;
|
||||||
|
|
||||||
/// Creates a new `ByteGrid` instance.
|
/// Creates a new `ByteGrid` instance.
|
||||||
/// The returned instance has to be freed with `byte_grid_dealloc`.
|
/// The returned instance has to be freed with `byte_grid_dealloc`.
|
||||||
|
@ -198,7 +200,7 @@ pub mod c_api {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::ByteGrid;
|
use crate::{ByteGrid, Grid};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fill() {
|
fn fill() {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::command_code::CommandCode;
|
use crate::command_code::CommandCode;
|
||||||
use crate::compression::{into_compressed, into_decompressed};
|
use crate::compression::{into_compressed, into_decompressed};
|
||||||
use crate::{
|
use crate::{BitVec, ByteGrid, CompressionCode, Grid, Header, Packet, PixelGrid, TILE_SIZE};
|
||||||
BitVec, ByteGrid, CompressionCode, Header, Packet, PixelGrid, TILE_SIZE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An origin marks the top left position of a window sent to the display.
|
/// An origin marks the top left position of a window sent to the display.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
@ -728,6 +726,7 @@ mod tests {
|
||||||
if compression != CompressionCode::Uncompressed {
|
if compression != CompressionCode::Uncompressed {
|
||||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||||
} else {
|
} else {
|
||||||
|
// when not compressing, there is no way to detect corrupted data
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
servicepoint2/src/grid.rs
Normal file
18
servicepoint2/src/grid.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
pub trait Grid<T> {
|
||||||
|
/// Sets the value at the specified position
|
||||||
|
///
|
||||||
|
/// returns: the old value
|
||||||
|
fn set(&mut self, x: usize, y: usize, value: T) -> T;
|
||||||
|
|
||||||
|
/// Get the current value at the specified position
|
||||||
|
fn get(&self, x: usize, y: usize) -> T;
|
||||||
|
|
||||||
|
/// Sets all cells in the grid to the specified value
|
||||||
|
fn fill(&mut self, value: T);
|
||||||
|
|
||||||
|
/// the size in x-direction
|
||||||
|
fn width(&self) -> usize;
|
||||||
|
|
||||||
|
/// the height in y-direction
|
||||||
|
fn height(&self) -> usize;
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ pub use crate::compression_code::CompressionCode;
|
||||||
pub use crate::connection::Connection;
|
pub use crate::connection::Connection;
|
||||||
pub use crate::packet::{Header, Packet, Payload};
|
pub use crate::packet::{Header, Packet, Payload};
|
||||||
pub use crate::pixel_grid::PixelGrid;
|
pub use crate::pixel_grid::PixelGrid;
|
||||||
|
pub use crate::grid::Grid;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[cfg(feature = "c_api")]
|
#[cfg(feature = "c_api")]
|
||||||
|
@ -20,17 +21,23 @@ mod compression_code;
|
||||||
mod connection;
|
mod connection;
|
||||||
mod packet;
|
mod packet;
|
||||||
mod pixel_grid;
|
mod pixel_grid;
|
||||||
|
mod grid;
|
||||||
|
|
||||||
/// size of a single tile in one dimension
|
/// size of a single tile in one dimension
|
||||||
pub const TILE_SIZE: u16 = 8;
|
pub const TILE_SIZE: u16 = 8;
|
||||||
|
|
||||||
/// tile count in the x-direction
|
/// tile count in the x-direction
|
||||||
pub const TILE_WIDTH: u16 = 56;
|
pub const TILE_WIDTH: u16 = 56;
|
||||||
|
|
||||||
/// tile count in the y-direction
|
/// tile count in the y-direction
|
||||||
pub const TILE_HEIGHT: u16 = 20;
|
pub const TILE_HEIGHT: u16 = 20;
|
||||||
|
|
||||||
/// screen width in pixels
|
/// screen width in pixels
|
||||||
pub const PIXEL_WIDTH: u16 = TILE_WIDTH * TILE_SIZE;
|
pub const PIXEL_WIDTH: u16 = TILE_WIDTH * TILE_SIZE;
|
||||||
|
|
||||||
/// screen height in pixels
|
/// screen height in pixels
|
||||||
pub const PIXEL_HEIGHT: u16 = TILE_HEIGHT * TILE_SIZE;
|
pub const PIXEL_HEIGHT: u16 = TILE_HEIGHT * TILE_SIZE;
|
||||||
|
|
||||||
/// pixel count on whole screen
|
/// pixel count on whole screen
|
||||||
pub const PIXEL_COUNT: usize = PIXEL_WIDTH as usize * PIXEL_HEIGHT as usize;
|
pub const PIXEL_COUNT: usize = PIXEL_WIDTH as usize * PIXEL_HEIGHT as usize;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{BitVec, PIXEL_HEIGHT, PIXEL_WIDTH};
|
use crate::{BitVec, Grid, PIXEL_HEIGHT, PIXEL_WIDTH};
|
||||||
|
|
||||||
/// A grid of pixels stored in packed bytes.
|
/// A grid of pixels stored in packed bytes.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -58,38 +58,10 @@ impl PixelGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the byte value at the specified position
|
|
||||||
pub fn set(&mut self, x: usize, y: usize, value: bool) -> bool {
|
|
||||||
self.check_indexes(x, y);
|
|
||||||
self.bit_vec.set(x + y * self.width, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the current value at the specified position
|
|
||||||
///
|
|
||||||
/// returns: current pixel value
|
|
||||||
pub fn get(&self, x: usize, y: usize) -> bool {
|
|
||||||
self.bit_vec.get(x + y * self.width)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets all pixels in the grid to the specified value
|
|
||||||
pub fn fill(&mut self, value: bool) {
|
|
||||||
self.bit_vec.fill(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
||||||
self.bit_vec.mut_data_ref()
|
self.bit_vec.mut_data_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// the size in x-direction in pixels
|
|
||||||
pub fn width(&self) -> usize {
|
|
||||||
self.width
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the height in y-direction in pixels
|
|
||||||
pub fn height(&self) -> usize {
|
|
||||||
self.height
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_indexes(&self, x: usize, y: usize) {
|
fn check_indexes(&self, x: usize, y: usize) {
|
||||||
if x >= self.width {
|
if x >= self.width {
|
||||||
panic!("cannot access pixel {x}-{y} because x is outside of bounds 0..{}", self.width)
|
panic!("cannot access pixel {x}-{y} because x is outside of bounds 0..{}", self.width)
|
||||||
|
@ -100,6 +72,29 @@ impl PixelGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Grid<bool> for PixelGrid {
|
||||||
|
fn set(&mut self, x: usize, y: usize, value: bool) -> bool {
|
||||||
|
self.check_indexes(x, y);
|
||||||
|
self.bit_vec.set(x + y * self.width, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, x: usize, y: usize) -> bool {
|
||||||
|
self.bit_vec.get(x + y * self.width)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill(&mut self, value: bool) {
|
||||||
|
self.bit_vec.fill(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<PixelGrid> for Vec<u8> {
|
impl From<PixelGrid> for Vec<u8> {
|
||||||
/// Turns a `PixelGrid` into the underlying `Vec<u8>`.
|
/// Turns a `PixelGrid` into the underlying `Vec<u8>`.
|
||||||
fn from(value: PixelGrid) -> Self {
|
fn from(value: PixelGrid) -> Self {
|
||||||
|
@ -110,7 +105,7 @@ impl From<PixelGrid> for Vec<u8> {
|
||||||
#[cfg(feature = "c_api")]
|
#[cfg(feature = "c_api")]
|
||||||
pub mod c_api {
|
pub mod c_api {
|
||||||
use crate::c_slice::CByteSlice;
|
use crate::c_slice::CByteSlice;
|
||||||
use crate::PixelGrid;
|
use crate::{Grid, PixelGrid};
|
||||||
|
|
||||||
/// Creates a new `PixelGrid` instance.
|
/// Creates a new `PixelGrid` instance.
|
||||||
/// The returned instance has to be freed with `pixel_grid_dealloc`.
|
/// The returned instance has to be freed with `pixel_grid_dealloc`.
|
||||||
|
@ -221,7 +216,7 @@ pub mod c_api {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::PixelGrid;
|
use crate::{Grid, PixelGrid};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fill() {
|
fn fill() {
|
||||||
|
|
Loading…
Reference in a new issue