2024-05-16 17:22:47 +02:00
|
|
|
use std::sync::{RwLock, RwLockWriteGuard};
|
|
|
|
|
|
|
|
use log::{debug, error, info, warn};
|
2024-05-26 15:24:44 +02:00
|
|
|
use servicepoint::{
|
2024-06-26 17:23:41 +02:00
|
|
|
BrightnessGrid, Command, Cp437Grid, Grid, Origin, PixelGrid, Tiles,
|
|
|
|
PIXEL_COUNT, PIXEL_WIDTH, TILE_SIZE,
|
2024-05-16 17:22:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
use crate::font::BitmapFont;
|
|
|
|
|
|
|
|
pub(crate) fn execute_command(
|
|
|
|
command: Command,
|
|
|
|
font: &BitmapFont,
|
|
|
|
display_ref: &RwLock<PixelGrid>,
|
2024-06-26 17:23:41 +02:00
|
|
|
luma_ref: &RwLock<BrightnessGrid>,
|
2024-05-16 17:22:47 +02:00
|
|
|
) -> bool {
|
|
|
|
debug!("received {command:?}");
|
|
|
|
match command {
|
|
|
|
Command::Clear => {
|
|
|
|
info!("clearing display");
|
|
|
|
display_ref.write().unwrap().fill(false);
|
|
|
|
}
|
|
|
|
Command::HardReset => {
|
|
|
|
warn!("display shutting down");
|
|
|
|
return false;
|
|
|
|
}
|
2024-06-26 17:23:41 +02:00
|
|
|
Command::BitmapLinearWin(Origin { x, y, .. }, pixels, _) => {
|
2024-05-16 17:22:47 +02:00
|
|
|
let mut display = display_ref.write().unwrap();
|
2024-05-26 10:50:29 +02:00
|
|
|
print_pixel_grid(x, y, &pixels, &mut display);
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
Command::Cp437Data(origin, grid) => {
|
|
|
|
let mut display = display_ref.write().unwrap();
|
|
|
|
print_cp437_data(origin, &grid, font, &mut display);
|
|
|
|
}
|
|
|
|
#[allow(deprecated)]
|
|
|
|
Command::BitmapLegacy => {
|
|
|
|
warn!("ignoring deprecated command {:?}", command);
|
|
|
|
}
|
|
|
|
// TODO: how to deduplicate this code in a rusty way?
|
|
|
|
Command::BitmapLinear(offset, vec, _) => {
|
2024-05-26 10:50:29 +02:00
|
|
|
if !check_bitmap_valid(offset as u16, vec.len()) {
|
2024-05-16 17:22:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let mut display = display_ref.write().unwrap();
|
|
|
|
for bitmap_index in 0..vec.len() {
|
2024-06-26 17:23:41 +02:00
|
|
|
let (x, y) = get_coordinates_for_index(offset, bitmap_index);
|
2024-06-05 20:42:15 +02:00
|
|
|
display.set(x, y, vec[bitmap_index]);
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::BitmapLinearAnd(offset, vec, _) => {
|
2024-05-26 10:50:29 +02:00
|
|
|
if !check_bitmap_valid(offset as u16, vec.len()) {
|
2024-05-16 17:22:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let mut display = display_ref.write().unwrap();
|
|
|
|
for bitmap_index in 0..vec.len() {
|
2024-06-26 17:23:41 +02:00
|
|
|
let (x, y) = get_coordinates_for_index(offset, bitmap_index);
|
2024-05-16 17:22:47 +02:00
|
|
|
let old_value = display.get(x, y);
|
2024-06-05 20:42:15 +02:00
|
|
|
display.set(x, y, old_value && vec[bitmap_index]);
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::BitmapLinearOr(offset, vec, _) => {
|
2024-05-26 10:50:29 +02:00
|
|
|
if !check_bitmap_valid(offset as u16, vec.len()) {
|
2024-05-16 17:22:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let mut display = display_ref.write().unwrap();
|
|
|
|
for bitmap_index in 0..vec.len() {
|
2024-06-26 17:23:41 +02:00
|
|
|
let (x, y) = get_coordinates_for_index(offset, bitmap_index);
|
2024-05-16 17:22:47 +02:00
|
|
|
let old_value = display.get(x, y);
|
2024-06-05 20:42:15 +02:00
|
|
|
display.set(x, y, old_value || vec[bitmap_index]);
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::BitmapLinearXor(offset, vec, _) => {
|
2024-05-26 10:50:29 +02:00
|
|
|
if !check_bitmap_valid(offset as u16, vec.len()) {
|
2024-05-16 17:22:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let mut display = display_ref.write().unwrap();
|
|
|
|
for bitmap_index in 0..vec.len() {
|
2024-06-26 17:23:41 +02:00
|
|
|
let (x, y) = get_coordinates_for_index(offset, bitmap_index);
|
2024-05-16 17:22:47 +02:00
|
|
|
let old_value = display.get(x, y);
|
2024-06-05 20:42:15 +02:00
|
|
|
display.set(x, y, old_value ^ vec[bitmap_index]);
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::CharBrightness(origin, grid) => {
|
|
|
|
let mut luma = luma_ref.write().unwrap();
|
2024-05-17 21:28:51 +02:00
|
|
|
for inner_y in 0..grid.height() {
|
|
|
|
for inner_x in 0..grid.width() {
|
2024-05-16 17:22:47 +02:00
|
|
|
let brightness = grid.get(inner_x, inner_y);
|
|
|
|
luma.set(
|
2024-06-26 17:23:41 +02:00
|
|
|
origin.x + inner_x,
|
|
|
|
origin.y + inner_y,
|
2024-05-16 17:22:47 +02:00
|
|
|
brightness,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::Brightness(brightness) => {
|
|
|
|
luma_ref.write().unwrap().fill(brightness);
|
|
|
|
}
|
|
|
|
Command::FadeOut => {
|
|
|
|
error!("command not implemented: {command:?}")
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_bitmap_valid(offset: u16, payload_len: usize) -> bool {
|
|
|
|
if offset as usize + payload_len > PIXEL_COUNT {
|
|
|
|
error!(
|
|
|
|
"bitmap with offset {offset} is too big ({} bytes)",
|
|
|
|
payload_len
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_cp437_data(
|
2024-06-26 17:23:41 +02:00
|
|
|
origin: Origin<Tiles>,
|
|
|
|
grid: &Cp437Grid,
|
2024-05-16 17:22:47 +02:00
|
|
|
font: &BitmapFont,
|
|
|
|
display: &mut RwLockWriteGuard<PixelGrid>,
|
|
|
|
) {
|
2024-06-26 17:23:41 +02:00
|
|
|
let Origin { x, y, .. } = origin;
|
2024-05-17 21:28:51 +02:00
|
|
|
for char_y in 0usize..grid.height() {
|
|
|
|
for char_x in 0usize..grid.width() {
|
2024-05-16 17:22:47 +02:00
|
|
|
let char_code = grid.get(char_x, char_y);
|
|
|
|
|
|
|
|
let tile_x = char_x + x;
|
|
|
|
let tile_y = char_y + y;
|
|
|
|
|
|
|
|
let bitmap = font.get_bitmap(char_code);
|
2024-05-18 17:19:13 +02:00
|
|
|
if !print_pixel_grid(
|
2024-05-26 10:50:29 +02:00
|
|
|
tile_x * TILE_SIZE,
|
|
|
|
tile_y * TILE_SIZE,
|
2024-05-16 17:22:47 +02:00
|
|
|
bitmap,
|
|
|
|
display,
|
2024-05-18 17:19:13 +02:00
|
|
|
) {
|
|
|
|
error!("stopping drawing text because char draw failed");
|
|
|
|
return;
|
|
|
|
}
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_pixel_grid(
|
|
|
|
offset_x: usize,
|
|
|
|
offset_y: usize,
|
|
|
|
pixels: &PixelGrid,
|
|
|
|
display: &mut RwLockWriteGuard<PixelGrid>,
|
2024-05-18 17:19:13 +02:00
|
|
|
) -> bool {
|
2024-05-16 17:22:47 +02:00
|
|
|
debug!(
|
|
|
|
"printing {}x{} grid at {offset_x} {offset_y}",
|
2024-05-17 21:28:51 +02:00
|
|
|
pixels.width(),
|
|
|
|
pixels.height()
|
2024-05-16 17:22:47 +02:00
|
|
|
);
|
2024-05-17 21:28:51 +02:00
|
|
|
for inner_y in 0..pixels.height() {
|
|
|
|
for inner_x in 0..pixels.width() {
|
2024-05-16 17:22:47 +02:00
|
|
|
let is_set = pixels.get(inner_x, inner_y);
|
2024-05-18 17:19:13 +02:00
|
|
|
let x = offset_x + inner_x;
|
|
|
|
let y = offset_y + inner_y;
|
|
|
|
|
|
|
|
if x >= display.width() || y >= display.height() {
|
|
|
|
error!("stopping pixel grid draw because coordinate {x} {y} is out of bounds");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
display.set(x, y, is_set);
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
2024-05-18 17:19:13 +02:00
|
|
|
|
|
|
|
true
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_coordinates_for_index(offset: usize, index: usize) -> (usize, usize) {
|
|
|
|
let pixel_index = offset + index;
|
2024-05-26 10:50:29 +02:00
|
|
|
(pixel_index % PIXEL_WIDTH, pixel_index / PIXEL_WIDTH)
|
2024-05-16 17:22:47 +02:00
|
|
|
}
|