use array_macro::array;
use parking_lot::Mutex;
use crate::image::{Image, SharedImage};
use crate::settings::{
CURSOR_DATA, CURSOR_HEIGHT, CURSOR_WIDTH, DEFAULT_COLORS, FONT_DATA, FONT_HEIGHT, FONT_WIDTH,
IMAGE_SIZE, NUM_COLORS, NUM_FONT_ROWS, NUM_IMAGES, NUM_TILEMAPS, TILEMAP_SIZE,
};
use crate::tilemap::{SharedTilemap, Tilemap};
use crate::types::{Color, Rgb8};
static COLORS: Mutex<[Rgb8; NUM_COLORS as usize]> = Mutex::new(DEFAULT_COLORS);
pub struct Graphics {
screen: SharedImage,
cursor: SharedImage,
font: SharedImage,
images: [SharedImage; NUM_IMAGES as usize],
tilemaps: [SharedTilemap; NUM_TILEMAPS as usize],
}
unsafe_singleton!(Graphics);
impl Graphics {
pub fn init() {
let screen = Image::new(crate::width(), crate::height());
let cursor = Self::new_cursor_image();
let font = Self::new_font_image();
let images = array![_ => Image::new(IMAGE_SIZE, IMAGE_SIZE); NUM_IMAGES as usize];
let tilemaps = array![_ => Tilemap::new(TILEMAP_SIZE, TILEMAP_SIZE, images[0].clone()); NUM_TILEMAPS as usize];
Self::set_instance(Self {
screen,
cursor,
font,
images,
tilemaps,
});
}
fn new_cursor_image() -> SharedImage {
let image = Image::new(CURSOR_WIDTH, CURSOR_HEIGHT);
image.lock().set(0, 0, &CURSOR_DATA);
image
}
fn new_font_image() -> SharedImage {
let width = FONT_WIDTH * NUM_FONT_ROWS;
let height = FONT_HEIGHT * ((FONT_DATA.len() as u32 + NUM_FONT_ROWS - 1) / NUM_FONT_ROWS);
let image = Image::new(width, height);
{
let mut image = image.lock();
for (fi, data) in FONT_DATA.iter().enumerate() {
let row = fi as u32 / NUM_FONT_ROWS;
let col = fi as u32 % NUM_FONT_ROWS;
let mut data = *data;
for yi in 0..FONT_HEIGHT {
for xi in 0..FONT_WIDTH {
let x = FONT_WIDTH * col + xi;
let y = FONT_HEIGHT * row + yi;
let color = if (data & 0x800000) == 0 { 0 } else { 1 };
image.canvas.data[y as usize][x as usize] = color;
data <<= 1;
}
}
}
}
image
}
}
pub fn colors() -> &'static Mutex<[Rgb8; NUM_COLORS as usize]> {
&COLORS
}
pub fn screen() -> SharedImage {
Graphics::instance().screen.clone()
}
pub fn cursor() -> SharedImage {
Graphics::instance().cursor.clone()
}
pub fn font() -> SharedImage {
Graphics::instance().font.clone()
}
pub fn image(image_no: u32) -> SharedImage {
Graphics::instance().images[image_no as usize].clone()
}
pub fn image_no(image: SharedImage) -> Option<u32> {
for (i, builtin_image) in Graphics::instance().images.iter().enumerate() {
if builtin_image.data_ptr() == image.data_ptr() {
return Some(i as u32);
}
}
None
}
pub fn tilemap(image_no: u32) -> SharedTilemap {
Graphics::instance().tilemaps[image_no as usize].clone()
}
pub fn clip(x: f64, y: f64, width: f64, height: f64) {
crate::screen().lock().clip(x, y, width, height);
}
pub fn clip0() {
crate::screen().lock().clip0();
}
pub fn camera(x: f64, y: f64) {
crate::screen().lock().camera(x, y);
}
pub fn camera0() {
crate::screen().lock().camera0();
}
pub fn pal(src_color: Color, dst_color: Color) {
crate::screen().lock().pal(src_color, dst_color);
}
pub fn pal0() {
crate::screen().lock().pal0();
}
pub fn cls(color: Color) {
crate::screen().lock().cls(color);
}
pub fn pget(x: f64, y: f64) -> Color {
crate::screen().lock().pget(x, y)
}
pub fn pset(x: f64, y: f64, color: Color) {
crate::screen().lock().pset(x, y, color);
}
pub fn line(x1: f64, y1: f64, x2: f64, y2: f64, color: Color) {
crate::screen().lock().line(x1, y1, x2, y2, color);
}
pub fn rect(x: f64, y: f64, width: f64, height: f64, color: Color) {
crate::screen().lock().rect(x, y, width, height, color);
}
pub fn rectb(x: f64, y: f64, width: f64, height: f64, color: Color) {
crate::screen().lock().rectb(x, y, width, height, color);
}
pub fn circ(x: f64, y: f64, radius: f64, color: Color) {
crate::screen().lock().circ(x, y, radius, color);
}
pub fn circb(x: f64, y: f64, radius: f64, color: Color) {
crate::screen().lock().circb(x, y, radius, color);
}
pub fn elli(x: f64, y: f64, width: f64, height: f64, color: Color) {
crate::screen().lock().elli(x, y, width, height, color);
}
pub fn ellib(x: f64, y: f64, width: f64, height: f64, color: Color) {
crate::screen().lock().ellib(x, y, width, height, color);
}
pub fn tri(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, color: Color) {
crate::screen().lock().tri(x1, y1, x2, y2, x3, y3, color);
}
pub fn trib(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, color: Color) {
crate::screen().lock().trib(x1, y1, x2, y2, x3, y3, color);
}
pub fn fill(x: f64, y: f64, color: Color) {
crate::screen().lock().fill(x, y, color);
}
pub fn blt(
x: f64,
y: f64,
image_no: u32,
image_x: f64,
image_y: f64,
width: f64,
height: f64,
color_key: Option<Color>,
) {
crate::screen().lock().blt(
x,
y,
crate::image(image_no),
image_x,
image_y,
width,
height,
color_key,
);
}
pub fn bltm(
x: f64,
y: f64,
tilemap_no: u32,
tilemap_x: f64,
tilemap_y: f64,
width: f64,
height: f64,
color_key: Option<Color>,
) {
crate::screen().lock().bltm(
x,
y,
crate::tilemap(tilemap_no),
tilemap_x,
tilemap_y,
width,
height,
color_key,
);
}
pub fn text(x: f64, y: f64, string: &str, color: Color) {
crate::screen().lock().text(x, y, string, color);
}