summaryrefslogtreecommitdiff
path: root/src/devices/screen.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/screen.rs')
-rw-r--r--src/devices/screen.rs258
1 files changed, 0 insertions, 258 deletions
diff --git a/src/devices/screen.rs b/src/devices/screen.rs
deleted file mode 100644
index a61d8b3..0000000
--- a/src/devices/screen.rs
+++ /dev/null
@@ -1,258 +0,0 @@
-mod sprite_data;
-mod draw_line;
-mod draw_rect;
-mod draw_sprite;
-
-pub use sprite_data::*;
-use geometry::HasDimensions;
-use phosphor::*;
-use std::cmp::{min, max, Ordering};
-use std::iter::zip;
-
-pub type ScreenDimensions = geometry::Dimensions<u16>;
-pub type ScreenPosition = geometry::Point<u16>;
-pub type Plane = [u8; 8];
-pub type Sprite = [[u8; 8]; 8];
-
-const TRANSPARENT: u8 = 0x08;
-const FLIP_DIAGONAL: u8 = 0x04;
-const FLIP_VERTICAL: u8 = 0x02;
-const FLIP_HORIZONTAL: u8 = 0x01;
-const NEGATIVE: u8 = 0x80;
-const VERTICAL: u8 = 0x40;
-
-
-#[derive(Copy, Clone)]
-pub enum ScreenLayer { Background, Foreground }
-
-macro_rules! test { ($value:expr, $mask:expr) => { $value & $mask != 0 }; }
-
-
-pub struct ScreenDevice {
- pub wake_flag: bool,
-
- /// Each byte represents a screen pixel, left-to-right and top-to-bottom.
- // Only the bottom four bits of each byte are used.
- pub foreground: Vec<u8>,
- pub background: Vec<u8>,
- pub dirty: bool,
- pub resizable: bool,
-
- pub cursor: ScreenPosition,
- pub vector: ScreenPosition,
- pub dimensions: ScreenDimensions,
-
- pub palette_high: u8,
- pub palette: [Colour; 16],
- pub sprite_buffer: SpriteBuffer,
-}
-
-impl ScreenDevice {
- pub fn new() -> Self {
- Self {
- wake_flag: false,
-
- foreground: Vec::new(),
- background: Vec::new(),
- dirty: false,
- resizable: true,
-
- cursor: ScreenPosition::ZERO,
- vector: ScreenPosition::ZERO,
- dimensions: ScreenDimensions::ZERO,
-
- palette_high: 0,
- palette: [Colour::BLACK; 16],
- sprite_buffer: SpriteBuffer::new(),
- }
- }
-
- pub fn set_size(&mut self) {
- self.resizable = false;
- self.resize(self.dimensions);
- }
-
- // Resize the screen buffers while preserving the current content.
- pub fn resize(&mut self, dimensions: ScreenDimensions) {
- let old_width = self.dimensions.width as usize;
- let old_height = self.dimensions.height as usize;
- let new_width = dimensions.width as usize;
- let new_height = dimensions.height as usize;
- let new_area = dimensions.area_usize();
- let y_range = 0..min(old_height, new_height);
-
- match new_width.cmp(&old_width) {
- Ordering::Less => {
- for y in y_range {
- let from = y * old_width;
- let to = y * new_width;
- let len = new_width;
- self.foreground.copy_within(from..from+len, to);
- self.background.copy_within(from..from+len, to);
- }
- self.foreground.resize(new_area, 0);
- self.background.resize(new_area, 0);
- },
- Ordering::Greater => {
- self.foreground.resize(new_area, 0);
- self.background.resize(new_area, 0);
- for y in y_range.rev() {
- let from = y * old_width;
- let to = y * new_width;
- let len = old_width;
- self.foreground.copy_within(from..from+len, to);
- self.background.copy_within(from..from+len, to);
- self.foreground[to+len..to+new_width].fill(0);
- self.background[to+len..to+new_width].fill(0);
- }
- },
- Ordering::Equal => {
- self.foreground.resize(new_area, 0);
- self.background.resize(new_area, 0);
- },
- };
-
- self.dimensions = dimensions;
- self.dirty = true;
- self.wake_flag = true;
- }
-
- pub fn render(&mut self, buffer: &mut Buffer) {
- // Pre-calculate a lookup table for the colour palette
- let mut lookup = [Colour::BLACK; 256];
- for (i, c) in lookup.iter_mut().enumerate() {
- match i > 0x0f {
- true => *c = self.palette[i >> 4],
- false => *c = self.palette[i & 0x0f],
- }
- };
- // Prepare values
- let b_width = buffer.width() as usize;
- let b_height = buffer.height() as usize;
- let s_width = self.dimensions.width() as usize;
- let s_height = self.dimensions.height() as usize;
-
- // Write colours to the buffer
- if b_width == s_width && b_height == s_height {
- let screen_iter = zip(&self.background, &self.foreground);
- let buffer_iter = buffer.as_mut_slice();
- for (b, (bg, fg)) in zip(buffer_iter, screen_iter) {
- *b = lookup[(fg << 4 | bg) as usize];
- }
- // Write colours to the buffer when the size of the buffer is wrong
- } else {
- let width = min(b_width, s_width);
- let height = min(b_height, s_height);
- let width_excess = b_width.saturating_sub(width);
- let b_slice = &mut buffer.as_mut_slice();
- let mut bi = 0;
- let mut si = 0;
- for _ in 0..height {
- let b_iter = &mut b_slice[bi..bi+width];
- let s_iter = zip(
- &self.background[si..si+width],
- &self.foreground[si..si+width],
- );
- for (b, (bg, fg)) in zip(b_iter, s_iter) {
- *b = lookup[(fg << 4 | bg) as usize];
- }
- b_slice[bi+width..bi+width+width_excess].fill(lookup[0]);
- bi += b_width;
- si += s_width;
- }
- b_slice[bi..].fill(lookup[0]);
- }
- self.dirty = false;
- }
-
- pub fn set_palette_high(&mut self, val: u8) {
- self.palette_high = val;
- }
-
- pub fn set_palette_low(&mut self, val: u8) {
- let index = (self.palette_high >> 4) as usize;
- let red = (self.palette_high & 0x0f) * 17;
- let green = (val >> 4) * 17;
- let blue = (val & 0x0f) * 17;
- self.palette[index] = Colour::from_rgb(red, green, blue);
- self.dirty = true;
- }
-
- pub fn shunt(&mut self, val: u8) {
- let negative = test!(val, NEGATIVE);
- let vertical = test!(val, VERTICAL);
- let dist = (val & 0x3f) as u16;
- match (negative, vertical) {
- (false, false) => self.cursor.x = self.cursor.x.wrapping_add(dist),
- (false, true) => self.cursor.y = self.cursor.y.wrapping_add(dist),
- ( true, false) => self.cursor.x = self.cursor.x.wrapping_sub(dist),
- ( true, true) => self.cursor.y = self.cursor.y.wrapping_sub(dist),
- };
- }
-
- pub fn draw(&mut self, val: u8) {
- let operation = val & 0x70;
- let parameters = val & 0x0f;
- let layer = match val & 0x80 != 0 {
- true => ScreenLayer::Foreground,
- false => ScreenLayer::Background
- };
- match operation {
- 0x00 => self.draw_pixel(parameters, layer, self.cursor),
- 0x10 => self.draw_sprite_1bit(parameters, layer),
- 0x20 => self.fill_layer(parameters, layer),
- 0x30 => self.draw_sprite_2bit(parameters, layer),
- 0x40 => self.draw_line(parameters, layer),
- 0x50 => self.draw_line_1bit(parameters, layer),
- 0x60 => self.draw_rect(parameters, layer),
- 0x70 => self.draw_rect_1bit(parameters, layer),
- _ => unreachable!(),
- };
-
- self.dirty = true;
- self.vector = self.cursor;
- }
-
- // Draw a single pixel of a single colour
- fn draw_pixel(&mut self, colour: u8, layer: ScreenLayer, point: ScreenPosition) {
- let dim = self.dimensions;
- if !dim.contains_point(point) || colour > 0xf { return }
- let index = point.x as usize + ((dim.width as usize) * (point.y as usize));
- match layer {
- ScreenLayer::Background => self.background[index] = colour,
- ScreenLayer::Foreground => self.foreground[index] = colour,
- };
- }
-
- // Fill an entire screen layer with a single colour
- fn fill_layer(&mut self, colour: u8, layer: ScreenLayer) {
- match layer {
- ScreenLayer::Background => self.background.fill(colour),
- ScreenLayer::Foreground => self.foreground.fill(colour),
- }
- }
-
- /// Returns [x0, y0, x1, y1], ensuring that x0 <= x1 and y0 <= y1
- fn find_vector_bounding_box(&self) -> Option<[usize; 4]> {
- macro_rules! raise {($v:expr) => {$v.wrapping_add(0x8000)};}
- macro_rules! lower {($v:expr) => {$v.wrapping_sub(0x8000)};}
-
- let [p0, p1] = [self.cursor, self.vector];
- let [p0x, p0y] = [ raise!(p0.x), raise!(p0.y) ];
- let [p1x, p1y] = [ raise!(p1.x), raise!(p1.y) ];
- let [x0, y0] = [ min(p0x, p1x), min(p0y, p1y) ];
- let [x1, y1] = [ max(p0x, p1x), max(p0y, p1y) ];
- let right = self.dimensions.width.saturating_sub(1);
- let bottom = self.dimensions.height.saturating_sub(1);
- if x0 > raise!(right) || y0 > raise!(bottom) || x1 < 0x8000 || y1 < 0x8000 {
- None
- } else {
- Some([
- if x0 < 0x8000 { 0 } else { min(lower!(x0), right) } as usize,
- if y0 < 0x8000 { 0 } else { min(lower!(y0), bottom) } as usize,
- if x1 < 0x8000 { 0 } else { min(lower!(x1), right) } as usize,
- if y1 < 0x8000 { 0 } else { min(lower!(y1), bottom) } as usize,
- ])
- }
- }
-}