use crate::prelude::{Console, font::Font, Shader, XpLayer, string_to_cp437, BTermPlatform, SparseConsoleBackend};
use std::any::Any;
use bracket_color::prelude::{RGB, XpColor};
use bracket_geometry::prelude::Rect;
pub struct SparseTile {
pub idx: usize,
pub glyph: u8,
pub fg: RGB,
pub bg: RGB,
}
pub struct SparseConsole {
pub width: u32,
pub height: u32,
pub tiles: Vec<SparseTile>,
pub is_dirty: bool,
offset_x: f32,
offset_y: f32,
scale: f32,
scale_center: (i32, i32),
backend: SparseConsoleBackend,
}
impl SparseConsole {
pub fn init(width: u32, height: u32, platform: &BTermPlatform) -> Box<SparseConsole> {
let new_console = SparseConsole {
width,
height,
tiles: Vec::with_capacity((width * height) as usize),
is_dirty: true,
offset_x: 0.0,
offset_y: 0.0,
scale: 1.0,
scale_center: (width as i32 / 2, height as i32 / 2),
backend: SparseConsoleBackend::new(platform, width as usize, height as usize),
};
Box::new(new_console)
}
fn rebuild_vertices(&mut self, platform: &BTermPlatform) {
self.backend.rebuild_vertices(
platform,
self.height,
self.width,
self.offset_x,
self.offset_y,
self.scale,
self.scale_center,
&self.tiles,
);
}
}
impl Console for SparseConsole {
fn rebuild_if_dirty(&mut self, platform: &BTermPlatform) {
if self.is_dirty {
self.rebuild_vertices(platform);
self.is_dirty = false;
}
}
fn get_char_size(&self) -> (u32, u32) {
(self.width, self.height)
}
fn resize_pixels(&mut self, _width: u32, _height: u32) {
self.is_dirty = true;
}
fn gl_draw(&mut self, font: &Font, shader: &Shader, platform: &BTermPlatform) {
self.backend.gl_draw(font, shader, platform, &self.tiles);
self.is_dirty = false;
}
fn at(&self, x: i32, y: i32) -> usize {
(((self.height - 1 - y as u32) * self.width) + x as u32) as usize
}
fn cls(&mut self) {
self.is_dirty = true;
self.tiles.clear();
}
fn cls_bg(&mut self, _background: RGB) {
self.is_dirty = true;
self.tiles.clear();
}
fn print(&mut self, x: i32, y: i32, output: &str) {
self.is_dirty = true;
let bounds = self.get_char_size();
let bytes = string_to_cp437(output);
self.tiles.extend(
bytes
.into_iter()
.enumerate()
.filter(|(i, _)| (*i as i32 + x) < bounds.0 as i32)
.map(|(i, glyph)| {
let idx =
(((bounds.1 - 1 - y as u32) * bounds.0) + (x + i as i32) as u32) as usize;
SparseTile {
idx,
glyph,
fg: RGB::from_f32(1.0, 1.0, 1.0),
bg: RGB::from_f32(0.0, 0.0, 0.0),
}
}),
);
}
fn print_color(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, output: &str) {
self.is_dirty = true;
let bounds = self.get_char_size();
let bytes = string_to_cp437(output);
self.tiles.extend(
bytes
.into_iter()
.enumerate()
.filter(|(i, _)| (*i as i32 + x) < bounds.0 as i32)
.map(|(i, glyph)| {
let idx =
(((bounds.1 - 1 - y as u32) * bounds.0) + (x + i as i32) as u32) as usize;
SparseTile { idx, glyph, fg, bg }
}),
);
}
fn set(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: u8) {
if let Some(idx) = self.try_at(x, y) {
self.tiles.push(SparseTile { idx, glyph, fg, bg });
}
}
fn set_bg(&mut self, x: i32, y: i32, bg: RGB) {
if let Some(idx) = self.try_at(x, y) {
self.tiles[idx].bg = bg;
}
}
fn draw_box(&mut self, sx: i32, sy: i32, width: i32, height: i32, fg: RGB, bg: RGB) {
crate::prelude::draw_box(self, sx, sy, width, height, fg, bg);
}
fn draw_box_double(&mut self, sx: i32, sy: i32, width: i32, height: i32, fg: RGB, bg: RGB) {
crate::prelude::draw_box_double(self, sx, sy, width, height, fg, bg);
}
fn draw_hollow_box(&mut self, sx: i32, sy: i32, width: i32, height: i32, fg: RGB, bg: RGB) {
crate::prelude::draw_hollow_box(self, sx, sy, width, height, fg, bg);
}
fn draw_hollow_box_double(
&mut self,
sx: i32,
sy: i32,
width: i32,
height: i32,
fg: RGB,
bg: RGB,
) {
crate::prelude::draw_hollow_box_double(self, sx, sy, width, height, fg, bg);
}
fn fill_region(&mut self, target: Rect, glyph: u8, fg: RGB, bg: RGB) {
target.for_each(|point| {
self.set(point.x, point.y, fg, bg, glyph);
});
}
fn get(&self, x: i32, y: i32) -> Option<(&u8, &RGB, &RGB)> {
let idx = self.at(x, y);
for t in self.tiles.iter().filter(|t| t.idx == idx) {
return Some((&t.glyph, &t.fg, &t.bg));
}
None
}
fn draw_bar_horizontal(
&mut self,
sx: i32,
sy: i32,
width: i32,
n: i32,
max: i32,
fg: RGB,
bg: RGB,
) {
crate::prelude::draw_bar_horizontal(self, sx, sy, width, n, max, fg, bg);
}
fn draw_bar_vertical(
&mut self,
sx: i32,
sy: i32,
height: i32,
n: i32,
max: i32,
fg: RGB,
bg: RGB,
) {
crate::prelude::draw_bar_vertical(self, sx, sy, height, n, max, fg, bg);
}
fn print_centered(&mut self, y: i32, text: &str) {
self.is_dirty = true;
self.print(
(self.width as i32 / 2) - (text.to_string().len() as i32 / 2),
y,
text,
);
}
fn print_color_centered(&mut self, y: i32, fg: RGB, bg: RGB, text: &str) {
self.is_dirty = true;
self.print_color(
(self.width as i32 / 2) - (text.to_string().len() as i32 / 2),
y,
fg,
bg,
text,
);
}
fn to_xp_layer(&self) -> XpLayer {
let mut layer = XpLayer::new(self.width as usize, self.height as usize);
for y in 0..self.height {
for x in 0..self.width {
let cell = layer.get_mut(x as usize, y as usize).unwrap();
cell.bg = XpColor::TRANSPARENT;
}
}
for c in &self.tiles {
let x = c.idx % self.width as usize;
let y = c.idx / self.width as usize;
let cell = layer.get_mut(x as usize, y as usize).unwrap();
cell.ch = u32::from(c.glyph);
cell.fg = c.fg.to_xp();
cell.bg = c.bg.to_xp();
}
layer
}
fn set_offset(&mut self, x: f32, y: f32) {
self.offset_x = x * (2.0 / self.width as f32);
self.offset_y = y * (2.0 / self.height as f32);
}
fn set_scale(&mut self, scale: f32, center_x: i32, center_y: i32) {
self.scale = scale;
self.scale_center = (center_x, center_y);
}
fn as_any(&self) -> &dyn Any {
self
}
}