2022-01-22 00:01:16 -06:00
|
|
|
use crate::vga_e::VGAE;
|
2022-01-18 06:15:51 -06:00
|
|
|
use alloc::{boxed::Box, vec, vec::Vec};
|
2022-01-22 00:01:16 -06:00
|
|
|
use shadeable::{
|
|
|
|
evaluate_shader,
|
|
|
|
pixel_format::{new_rgba64, Rgba64},
|
|
|
|
};
|
|
|
|
use spin;
|
2022-01-18 06:15:51 -06:00
|
|
|
use vga::{colors::Color16, writers::GraphicsWriter};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ScreenSize {
|
|
|
|
pub x: usize,
|
|
|
|
pub y: usize,
|
|
|
|
}
|
2022-01-22 00:01:16 -06:00
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
pub static ref SCREEN_BUFFER: spin::Mutex<ScreenBuffer> = spin::Mutex::new(ScreenBuffer::new(640, 480));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-01-18 06:15:51 -06:00
|
|
|
impl ScreenSize {
|
|
|
|
pub fn new(x: usize, y: usize) -> Self {
|
|
|
|
Self { x, y }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum GraphicsReturn {
|
|
|
|
Ok,
|
|
|
|
ImproperScreenSize,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ScreenBuffer {
|
|
|
|
pub size: ScreenSize,
|
|
|
|
pub clear_color: Rgba64,
|
|
|
|
pub buff: Box<[Rgba64]>, // Vec<Rgba64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ScreenBuffer {
|
|
|
|
// Add optional size later
|
|
|
|
pub fn new(x: usize, y: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
size: ScreenSize::new(x, y),
|
|
|
|
clear_color: 0,
|
|
|
|
buff: vec![0u64; x * y].into_boxed_slice(),
|
|
|
|
}
|
|
|
|
}
|
2022-01-22 00:01:16 -06:00
|
|
|
pub fn draw_filled_circle(&mut self, cx: i32, cy: i32, radius: usize, color: Rgba64) {
|
|
|
|
let r = radius as i32 * 2;
|
|
|
|
for y in 0..640 {
|
|
|
|
for x in 0..480 {
|
|
|
|
let dx = cx - x as i32 * 2 - 1;
|
|
|
|
let dy = cy - y as i32 * 2 - 1;
|
|
|
|
|
|
|
|
if dx * dx + dy * dy <= r * r {
|
|
|
|
self.set_pixel(x, y, color);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-18 06:15:51 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn set_pixel(&mut self, x: usize, y: usize, color: Rgba64) {
|
2022-01-18 08:30:09 -06:00
|
|
|
self.buff[y * self.size.x + x] = color;
|
2022-01-18 06:15:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
self.buff = vec![0u64; self.buff.len()].into_boxed_slice();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn blit(&mut self, _width: usize, _height: usize) {}
|
2022-01-22 00:01:16 -06:00
|
|
|
pub fn draw_filled_rect(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, color: Rgba64) {
|
|
|
|
for y in y1..y2 {
|
|
|
|
for x in x1..x2 {
|
|
|
|
self.set_pixel(x, y, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn draw_unfilled_rect(
|
|
|
|
&mut self,
|
|
|
|
x1: usize,
|
|
|
|
y1: usize,
|
|
|
|
x2: usize,
|
|
|
|
y2: usize,
|
|
|
|
color: Rgba64,
|
|
|
|
) {
|
|
|
|
// x1 y1 => x2 y1 => x2 y2 => x1 y2 => x1 y1
|
|
|
|
self.draw_line(x1, y1, x2, y1, color);
|
|
|
|
self.draw_line(x2, y1, x2, y2, color);
|
|
|
|
self.draw_line(x2, y2, x1, y2, color);
|
|
|
|
self.draw_line(x1, y2, x1, y1, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn draw_line(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, color: Rgba64) {
|
|
|
|
let x = crate::graphics::get_coordinates(
|
|
|
|
x1.try_into().unwrap(),
|
|
|
|
y1.try_into().unwrap(),
|
|
|
|
x2.try_into().unwrap(),
|
|
|
|
y2.try_into().unwrap(),
|
|
|
|
);
|
|
|
|
|
|
|
|
for coord in x {
|
|
|
|
self.set_pixel(coord.0, coord.1, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn shade(&mut self) {
|
|
|
|
for y in 0..100 {
|
|
|
|
for x in 0..100 {
|
|
|
|
let rgba_ret = evaluate_shader(x, y, self.buff[y * self.size.x + x]);
|
|
|
|
match rgba_ret {
|
|
|
|
Ok(pixel) => {
|
|
|
|
// info!("{:?}", pixel);
|
|
|
|
self.set_pixel(x, y, pixel);
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(err) => error!("{}", err),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("Shaders done");
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO force clear
|
|
|
|
pub fn force_redraw(&mut self) {
|
|
|
|
use shadeable::pixel_format::into_vga_16;
|
|
|
|
VGAE.lock().clear_screen(into_vga_16(self.clear_color));
|
|
|
|
}
|
2022-01-18 06:15:51 -06:00
|
|
|
}
|
2022-01-22 00:01:16 -06:00
|
|
|
|
2022-01-18 06:15:51 -06:00
|
|
|
pub trait VgaBuffer {
|
|
|
|
fn copy_to_buffer(&self) -> GraphicsReturn;
|
|
|
|
}
|
|
|
|
impl VgaBuffer for ScreenBuffer {
|
|
|
|
fn copy_to_buffer(&self) -> GraphicsReturn {
|
|
|
|
let mode = VGAE.lock();
|
|
|
|
for y in 0..self.size.y {
|
|
|
|
for x in 0..self.size.x {
|
2022-01-18 08:30:09 -06:00
|
|
|
use shadeable::pixel_format::{get_color16, into_vga_16};
|
2022-01-22 00:01:16 -06:00
|
|
|
// let vga_color = get_color16(self.buff[y * self.size.x + x]);
|
|
|
|
|
|
|
|
let vga_color = into_vga_16(self.buff[y * self.size.x + x]);
|
|
|
|
|
|
|
|
if into_vga_16(self.clear_color) != vga_color {
|
|
|
|
mode.set_pixel(x, y, vga_color);
|
|
|
|
}
|
2022-01-18 06:15:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GraphicsReturn::Ok
|
|
|
|
}
|
|
|
|
}
|
2022-01-22 00:01:16 -06:00
|
|
|
pub fn get_coordinates(x1: i32, y1: i32, x2: i32, y2: i32) -> Vec<(usize, usize)> {
|
|
|
|
let mut coordinates: Vec<(usize, usize)> = vec![];
|
|
|
|
let dx: i32 = i32::abs(x2 - x1);
|
|
|
|
let dy: i32 = i32::abs(y2 - y1);
|
|
|
|
let sx: i32 = {
|
|
|
|
if x1 < x2 {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
-1
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let sy: i32 = {
|
|
|
|
if y1 < y2 {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
-1
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let mut error: i32 = (if dx > dy { dx } else { -dy }) / 2;
|
|
|
|
let mut current_x: i32 = x1;
|
|
|
|
let mut current_y: i32 = y1;
|
|
|
|
loop {
|
|
|
|
coordinates.push((current_x as usize, current_y as usize));
|
|
|
|
// info!("0 {:?}", (current_x, current_y));
|
|
|
|
|
|
|
|
if current_x == x2 && current_y == y2 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let error2: i32 = error;
|
|
|
|
|
|
|
|
if error2 > -dx {
|
|
|
|
error -= dy;
|
|
|
|
current_x += sx;
|
|
|
|
}
|
|
|
|
if error2 < dy {
|
|
|
|
error += dx;
|
|
|
|
current_y += sy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
coordinates
|
|
|
|
}
|