#![allow(dead_code)]
#[allow(unused_imports)]
use crate::{
prelude::{
init_raw, BEvent, CharacterTranslationMode, Console, FlexiConsole, Font, FontCharType,
GameState, InitHints, Radians, RenderSprite, Shader, SimpleConsole, SpriteConsole,
SpriteSheet, TextAlign, VirtualKeyCode, XpFile, XpLayer, BACKEND, INPUT,
},
BResult,
};
use bracket_color::prelude::RGBA;
use bracket_geometry::prelude::{Point, PointF, Rect};
use parking_lot::Mutex;
use std::convert::*;
pub struct DisplayConsole {
pub console: Box<dyn Console>,
pub shader_index: usize,
pub font_index: usize,
}
pub struct BTermInternal {
pub fonts: Vec<Font>,
pub shaders: Vec<Shader>,
pub consoles: Vec<DisplayConsole>,
pub sprite_sheets: Vec<SpriteSheet>,
}
impl BTermInternal {
pub fn new() -> Self {
Self {
fonts: Vec::new(),
shaders: Vec::new(),
consoles: Vec::new(),
sprite_sheets: Vec::new(),
}
}
}
impl Default for BTermInternal {
fn default() -> Self {
Self {
fonts: Vec::new(),
shaders: Vec::new(),
consoles: Vec::new(),
sprite_sheets: Vec::new(),
}
}
}
unsafe impl Send for BTermInternal {}
unsafe impl Sync for BTermInternal {}
lazy_static! {
pub static ref BACKEND_INTERNAL: Mutex<BTermInternal> = Mutex::new(BTermInternal::new());
}
#[derive(Clone, Debug)]
pub struct BTerm {
pub width_pixels: u32,
pub height_pixels: u32,
pub original_height_pixels: u32,
pub original_width_pixels: u32,
pub fps: f32,
pub frame_time_ms: f32,
pub active_console: usize,
pub key: Option<VirtualKeyCode>,
pub mouse_pos: (i32, i32),
pub left_click: bool,
pub shift: bool,
pub control: bool,
pub alt: bool,
pub web_button: Option<String>,
pub quitting: bool,
pub post_scanlines: bool,
pub post_screenburn: bool,
pub screen_burn_color: bracket_color::prelude::RGB,
pub mouse_visible: bool,
}
impl BTerm {
pub fn init_raw<S: ToString, T>(
width_pixels: T,
height_pixels: T,
window_title: S,
platform_hints: InitHints,
) -> BResult<BTerm>
where
T: TryInto<u32>,
{
let w = width_pixels.try_into();
let h = height_pixels.try_into();
let (w, h) = if let (Ok(w), Ok(h)) = (w, h) {
(w, h)
} else {
return Err("Couldn't convert to u32".into());
};
init_raw(w, h, window_title, platform_hints)
}
#[deprecated(
since = "0.6.2",
note = "Please migrate to the BTermBuilder system instead."
)]
pub fn init_simple8x8<S: ToString, T>(
width_chars: T,
height_chars: T,
window_title: S,
path_to_shaders: S,
) -> BTerm
where
T: TryInto<u32>,
{
let w: u32 = width_chars.try_into().ok().unwrap();
let h: u32 = height_chars.try_into().ok().unwrap();
let font_path = format!("{}/terminal8x8.png", &path_to_shaders.to_string());
let mut context = BTerm::init_raw(w * 8, h * 8, window_title, InitHints::new()).unwrap();
let font = context.register_font(Font::load(font_path, (8, 8), None));
context.register_console(SimpleConsole::init(w, h), font.unwrap());
context
}
#[deprecated(
since = "0.6.2",
note = "Please migrate to the BTermBuilder system instead."
)]
pub fn init_simple8x16<S: ToString, T>(
width_chars: T,
height_chars: T,
window_title: S,
path_to_shaders: S,
) -> BTerm
where
T: TryInto<u32>,
{
let w: u32 = width_chars.try_into().ok().unwrap();
let h: u32 = height_chars.try_into().ok().unwrap();
let font_path = format!("{}/vga8x16.png", &path_to_shaders.to_string());
let mut context = BTerm::init_raw(w * 8, h * 16, window_title, InitHints::new()).unwrap();
let font = context.register_font(Font::load(font_path, (8, 16), None));
context.register_console(SimpleConsole::init(w, h), font.unwrap());
context
}
pub(crate) fn register_font(&mut self, font: Font) -> BResult<usize> {
let mut bi = BACKEND_INTERNAL.lock();
bi.fonts.push(font);
Ok(bi.fonts.len() - 1)
}
pub fn register_console(&mut self, new_console: Box<dyn Console>, font_index: usize) -> usize {
let mut bi = BACKEND_INTERNAL.lock();
bi.consoles.push(DisplayConsole {
console: new_console,
font_index,
shader_index: 0,
});
bi.consoles.len() - 1
}
pub fn register_console_no_bg(
&mut self,
new_console: Box<dyn Console>,
font_index: usize,
) -> usize {
let mut bi = BACKEND_INTERNAL.lock();
bi.consoles.push(DisplayConsole {
console: new_console,
font_index,
shader_index: 1,
});
bi.consoles.len() - 1
}
pub fn register_fancy_console(
&mut self,
new_console: Box<dyn Console>,
font_index: usize,
) -> usize {
let mut bi = BACKEND_INTERNAL.lock();
bi.consoles.push(DisplayConsole {
console: new_console,
font_index,
shader_index: 4,
});
bi.consoles.len() - 1
}
pub fn register_sprite_console(&mut self, new_console: Box<dyn Console>) -> usize {
let mut bi = BACKEND_INTERNAL.lock();
bi.consoles.push(DisplayConsole {
console: new_console,
font_index: 0,
shader_index: 5,
});
bi.consoles.len() - 1
}
pub fn set_active_console(&mut self, id: usize) {
let length = BACKEND_INTERNAL.lock().consoles.len();
if id < length {
self.active_console = id;
} else {
panic!(
"Invalid console id: {}. Valid consoles are 0..{}",
id, length
);
}
}
#[cfg(any(feature = "curses", feature = "cross_term"))]
pub fn mouse_pos(&self) -> (i32, i32) {
(self.mouse_pos.0, self.mouse_pos.1)
}
#[cfg(any(feature = "curses", feature = "cross_term"))]
fn pixel_to_char_pos(&self, pos: (i32, i32), _console: &Box<dyn Console>) -> (i32, i32) {
pos
}
#[cfg(not(any(feature = "curses", feature = "cross_term")))]
fn pixel_to_char_pos(&self, pos: (i32, i32), console: &Box<dyn Console>) -> (i32, i32) {
let max_sizes = console.get_char_size();
let (scale, center_x, center_y) = console.get_scale();
let font_size = (
self.width_pixels as f32 / max_sizes.0 as f32,
self.height_pixels as f32 / max_sizes.1 as f32,
);
let mut offsets = (
center_x as f32 * font_size.0 * (scale - 1.0),
center_y as f32 * font_size.1 * (scale - 1.0),
);
let w: f32;
let h: f32;
{
let be = crate::hal::BACKEND.lock();
w = be.screen_scaler.available_width as f32;
h = be.screen_scaler.available_height as f32;
offsets.0 -= be.screen_scaler.gutter_left as f32;
offsets.1 -= be.screen_scaler.gutter_top as f32;
}
let extent_x = (pos.0 as f32 + offsets.0) / w;
let extent_y = (pos.1 as f32 + offsets.1) / h;
let mouse_x = f32::min(extent_x * max_sizes.0 as f32, max_sizes.0 as f32 - 1.0);
let mouse_y = f32::min(extent_y * max_sizes.1 as f32, max_sizes.1 as f32 - 1.0);
(i32::max(0, mouse_x as i32), i32::max(0, mouse_y as i32))
}
#[cfg(not(any(feature = "curses", feature = "cross_term")))]
pub fn mouse_pos(&self) -> (i32, i32) {
let bi = BACKEND_INTERNAL.lock();
let active_console = &bi.consoles[self.active_console].console;
self.pixel_to_char_pos(self.mouse_pos, active_console)
}
pub fn mouse_point(&self) -> Point {
let bi = BACKEND_INTERNAL.lock();
let active_console = &bi.consoles[self.active_console].console;
let char_pos = self.pixel_to_char_pos(self.mouse_pos, active_console);
Point::new(char_pos.0, char_pos.1)
}
pub fn quit(&mut self) {
self.quitting = true;
}
pub fn render_xp_sprite(&mut self, xp: &super::rex::XpFile, x: i32, y: i32) {
let mut bi = BACKEND_INTERNAL.lock();
super::rex::xp_to_console(xp, &mut bi.consoles[self.active_console].console, x, y);
}
pub fn to_xp_file(&self, width: usize, height: usize) -> XpFile {
let bi = BACKEND_INTERNAL.lock();
let mut xp = XpFile::new(width, height);
xp.layers
.push(bi.consoles[self.active_console].console.to_xp_layer());
if bi.consoles.len() > 1 {
for layer in bi.consoles.iter().skip(1) {
xp.layers.push(layer.console.to_xp_layer());
}
}
xp
}
pub fn with_post_scanlines(&mut self, with_burn: bool) {
self.post_scanlines = true;
self.post_screenburn = with_burn;
}
pub fn screen_burn_color(&mut self, color: bracket_color::prelude::RGB) {
self.screen_burn_color = color;
}
pub fn with_mouse_visibility(&mut self, with_visibility: bool) {
self.mouse_visible = with_visibility;
}
pub(crate) fn on_key(&mut self, key: VirtualKeyCode, scan_code: u32, pressed: bool) {
let mut input = INPUT.lock();
if pressed {
self.key = Some(key);
input.on_key_down(key, scan_code);
} else {
self.key = None;
input.on_key_up(key, scan_code);
}
input.push_event(BEvent::KeyboardInput {
key,
scan_code,
pressed,
});
}
pub(crate) fn on_mouse_button(&mut self, button_num: usize, pressed: bool) {
if button_num == 0 {
self.left_click = true;
}
let mut input = INPUT.lock();
if pressed {
input.on_mouse_button_down(button_num);
} else {
input.on_mouse_button_up(button_num);
}
input.push_event(BEvent::MouseClick {
button: button_num,
pressed,
});
}
pub(crate) fn on_mouse_position(&mut self, x: f64, y: f64) {
let bi = BACKEND_INTERNAL.lock();
self.mouse_pos = (x as i32, y as i32);
let mut input = INPUT.lock();
input.on_mouse_pixel_position(x, y);
for (i, cons) in bi.consoles.iter().enumerate() {
let char_pos = self.pixel_to_char_pos(self.mouse_pos, &cons.console);
input.on_mouse_tile_position(i, char_pos.0, char_pos.1);
}
}
#[allow(dead_code)]
pub(crate) fn on_event(&mut self, event: BEvent) {
INPUT.lock().push_event(event);
}
}
impl BTerm {
pub fn get_char_size(&self) -> (u32, u32) {
let bi = BACKEND_INTERNAL.lock();
bi.consoles[self.active_console].console.get_char_size()
}
pub(crate) fn resize_pixels<T>(&mut self, width: T, height: T, scaling_enabled: bool)
where
T: Into<u32>,
{
self.width_pixels = width.into();
self.height_pixels = height.into();
if scaling_enabled {
self.original_width_pixels = self.width_pixels;
self.original_height_pixels = self.height_pixels;
}
let mut bi = BACKEND_INTERNAL.lock();
for c in bi.consoles.iter_mut() {
c.console
.resize_pixels(self.width_pixels, self.height_pixels);
}
}
pub fn cls(&mut self) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.cls();
}
pub fn cls_bg<COLOR>(&mut self, background: COLOR)
where
COLOR: Into<RGBA>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.cls_bg(background.into());
}
pub fn print<S, X, Y>(&mut self, x: X, y: Y, output: S)
where
S: ToString,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
&output.to_string(),
);
}
pub fn print_color<S, COLOR, COLOR2, X, Y>(
&mut self,
x: X,
y: Y,
fg: COLOR,
bg: COLOR2,
output: S,
) where
S: ToString,
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_color(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
&output.to_string(),
);
}
pub fn set<COLOR, COLOR2, GLYPH, X, Y>(
&mut self,
x: X,
y: Y,
fg: COLOR,
bg: COLOR2,
glyph: GLYPH,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
GLYPH: TryInto<FontCharType>,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
glyph.try_into().ok().expect("Must be u16 convertible"),
);
}
#[cfg(any(feature = "opengl", feature = "webgpu"))]
#[allow(clippy::too_many_arguments)]
pub fn set_fancy<COLOR, COLOR2, GLYPH, ANGLE>(
&mut self,
position: PointF,
z_order: i32,
rotation: ANGLE,
scale: PointF,
fg: COLOR,
bg: COLOR2,
glyph: GLYPH,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
GLYPH: TryInto<FontCharType>,
ANGLE: Into<Radians>,
{
let mut be = BACKEND_INTERNAL.lock();
let cons_any = be.consoles[self.active_console].console.as_any_mut();
if let Some(fc) = cons_any.downcast_mut::<FlexiConsole>() {
fc.set_fancy(
position,
z_order,
rotation.into().0,
scale,
fg.into(),
bg.into(),
glyph.try_into().ok().expect("Must be u16 convertible"),
);
}
}
#[cfg(not(any(feature = "opengl", feature = "webgpu")))]
pub fn set_fancy<COLOR, COLOR2, GLYPH, ANGLE>(
&mut self,
_position: PointF,
_z_order: i32,
_rotation: ANGLE,
_scale: PointF,
_fg: COLOR,
_bg: COLOR2,
_glyph: GLYPH,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
GLYPH: TryInto<FontCharType>,
ANGLE: Into<Radians>,
{
}
pub fn set_bg<COLOR, X, Y>(&mut self, x: X, y: Y, bg: COLOR)
where
COLOR: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_bg(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
bg.into(),
);
}
pub fn draw_box<COLOR, COLOR2, X, Y, W, H>(
&mut self,
x: X,
y: Y,
width: W,
height: H,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
W: TryInto<i32>,
H: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.draw_box(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
width.try_into().ok().expect("Must be i32 convertible"),
height.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
);
}
pub fn draw_box_double<COLOR, COLOR2, X, Y, W, H>(
&mut self,
x: X,
y: Y,
width: W,
height: H,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
W: TryInto<i32>,
H: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.draw_box_double(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
width.try_into().ok().expect("Must be i32 convertible"),
height.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
);
}
pub fn draw_hollow_box<COLOR, COLOR2, X, Y, W, H>(
&mut self,
x: X,
y: Y,
width: W,
height: H,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
W: TryInto<i32>,
H: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.draw_hollow_box(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
width.try_into().ok().expect("Must be i32 convertible"),
height.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
);
}
pub fn draw_hollow_box_double<COLOR, COLOR2, X, Y, W, H>(
&mut self,
x: X,
y: Y,
width: W,
height: H,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
W: TryInto<i32>,
H: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.draw_hollow_box_double(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
width.try_into().ok().expect("Must be i32 convertible"),
height.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
);
}
#[allow(clippy::too_many_arguments)]
pub fn draw_bar_horizontal<COLOR, COLOR2, X, Y, W, N, MAX>(
&mut self,
x: X,
y: Y,
width: W,
n: N,
max: MAX,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
W: TryInto<i32>,
N: TryInto<i32>,
MAX: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.draw_bar_horizontal(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
width.try_into().ok().expect("Must be i32 convertible"),
n.try_into().ok().expect("Must be i32 convertible"),
max.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
);
}
#[allow(clippy::too_many_arguments)]
pub fn draw_bar_vertical<COLOR, COLOR2, X, Y, H, N, MAX>(
&mut self,
x: X,
y: Y,
height: H,
n: N,
max: MAX,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
H: TryInto<i32>,
N: TryInto<i32>,
MAX: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.draw_bar_vertical(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
height.try_into().ok().expect("Must be i32 convertible"),
n.try_into().ok().expect("Must be i32 convertible"),
max.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
);
}
pub fn fill_region<COLOR, COLOR2, GLYPH>(
&mut self,
target: Rect,
glyph: GLYPH,
fg: COLOR,
bg: COLOR2,
) where
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
GLYPH: TryInto<FontCharType>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.fill_region(target, glyph.try_into().ok().unwrap(), fg.into(), bg.into());
}
pub fn print_centered<S, Y>(&mut self, y: Y, text: S)
where
S: ToString,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_centered(
y.try_into().ok().expect("Must be i32 convertible"),
&text.to_string(),
);
}
pub fn print_color_centered<S, COLOR, COLOR2, Y>(
&mut self,
y: Y,
fg: COLOR,
bg: COLOR2,
text: S,
) where
S: ToString,
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_color_centered(
y.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
&text.to_string(),
);
}
pub fn print_centered_at<S, X, Y>(&mut self, x: X, y: Y, text: S)
where
S: ToString,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_centered_at(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
&text.to_string(),
);
}
pub fn print_color_centered_at<S, COLOR, COLOR2, X, Y>(
&mut self,
x: X,
y: Y,
fg: COLOR,
bg: COLOR2,
text: S,
) where
S: ToString,
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_color_centered_at(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
&text.to_string(),
);
}
pub fn print_right<S, X, Y>(&mut self, x: X, y: Y, text: S)
where
S: ToString,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_right(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
&text.to_string(),
);
}
pub fn print_color_right<S, COLOR, COLOR2, X, Y>(
&mut self,
x: X,
y: Y,
fg: COLOR,
bg: COLOR2,
text: S,
) where
S: ToString,
COLOR: Into<RGBA>,
COLOR2: Into<RGBA>,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.print_color_right(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
fg.into(),
bg.into(),
&text.to_string(),
);
}
pub fn printer<S, X, Y>(
&mut self,
x: X,
y: Y,
output: S,
align: TextAlign,
background: Option<RGBA>,
) where
S: ToString,
X: TryInto<i32>,
Y: TryInto<i32>,
{
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.printer(
x.try_into().ok().expect("Must be i32 convertible"),
y.try_into().ok().expect("Must be i32 convertible"),
&output.to_string(),
align,
background,
);
}
pub fn to_xp_layer(&self) -> XpLayer {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.to_xp_layer()
}
pub fn set_offset(&mut self, x: f32, y: f32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_offset(x, y);
}
pub fn set_scale(&mut self, scale: f32, center_x: i32, center_y: i32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_scale(scale, center_x, center_y);
}
pub fn get_scale(&self) -> (f32, i32, i32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.get_scale()
}
pub fn set_clipping(&mut self, clipping: Option<Rect>) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_clipping(clipping);
}
pub fn get_clipping(&self) -> Option<Rect> {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.get_clipping()
}
pub fn set_all_fg_alpha(&mut self, alpha: f32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_all_fg_alpha(alpha);
}
pub fn set_all_bg_alpha(&mut self, alpha: f32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_all_bg_alpha(alpha);
}
pub fn set_all_alpha(&mut self, fg: f32, bg: f32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_all_alpha(fg, bg);
}
pub fn set_translation_mode(&mut self, console: usize, translation: CharacterTranslationMode) {
BACKEND_INTERNAL.lock().consoles[console]
.console
.set_translation_mode(translation)
}
#[cfg(any(feature = "opengl", feature = "webgpu"))]
pub fn set_active_font(&mut self, font_index: usize, resize_to_natural_dimensions: bool) {
let mut be = BACKEND_INTERNAL.lock();
if font_index > be.fonts.len() {
panic!("Font index out of bounds.");
}
let old_font_size = be.fonts[be.consoles[self.active_console].font_index].tile_size;
let new_font_size = be.fonts[font_index].tile_size;
be.consoles[self.active_console].font_index = font_index;
if old_font_size != new_font_size && resize_to_natural_dimensions {
let x_size = self.original_width_pixels / new_font_size.0;
let y_size = self.original_height_pixels / new_font_size.1;
be.consoles[self.active_console]
.console
.set_char_size(x_size, y_size);
}
}
#[cfg(all(
any(feature = "opengl", feature = "webgpu"),
not(target_arch = "wasm32")
))]
pub fn set_char_size(&mut self, width: u32, height: u32) {
BACKEND_INTERNAL.lock().consoles[self.active_console]
.console
.set_char_size(width, height);
}
#[cfg(all(
any(feature = "opengl", feature = "webgpu"),
not(target_arch = "wasm32")
))]
pub fn set_char_size_and_resize_window(&mut self, _width: u32, _height: u32) {
}
#[cfg(all(
any(feature = "opengl", feature = "webgpu"),
not(target_arch = "wasm32")
))]
pub fn screenshot<S: ToString>(&mut self, filename: S) {
BACKEND.lock().request_screenshot = Some(filename.to_string());
}
#[cfg(not(all(
any(feature = "opengl", feature = "webgpu"),
not(target_arch = "wasm32")
)))]
pub fn screenshot<S: ToString>(&mut self, _filename: S) {
}
#[cfg(any(feature = "opengl", feature = "webgpu"))]
pub fn register_spritesheet(&mut self, ss: SpriteSheet) -> usize {
let mut bi = BACKEND_INTERNAL.lock();
let id = bi.sprite_sheets.len();
bi.sprite_sheets.push(ss);
id
}
#[cfg(any(feature = "opengl", feature = "webgpu"))]
pub fn add_sprite(&mut self, destination: Rect, z_order: i32, tint: RGBA, index: usize) {
let mut bi = BACKEND_INTERNAL.lock();
let as_any = bi.consoles[self.active_console].console.as_any_mut();
if let Some(cons) = as_any.downcast_mut::<SpriteConsole>() {
cons.render_sprite(RenderSprite {
destination,
z_order,
tint,
index,
});
}
}
}
pub fn main_loop<GS: GameState>(bterm: BTerm, gamestate: GS) -> BResult<()> {
super::hal::main_loop(bterm, gamestate)?;
Ok(())
}
pub fn letter_to_option(key: VirtualKeyCode) -> i32 {
match key {
VirtualKeyCode::A => 0,
VirtualKeyCode::B => 1,
VirtualKeyCode::C => 2,
VirtualKeyCode::D => 3,
VirtualKeyCode::E => 4,
VirtualKeyCode::F => 5,
VirtualKeyCode::G => 6,
VirtualKeyCode::H => 7,
VirtualKeyCode::I => 8,
VirtualKeyCode::J => 9,
VirtualKeyCode::K => 10,
VirtualKeyCode::L => 11,
VirtualKeyCode::M => 12,
VirtualKeyCode::N => 13,
VirtualKeyCode::O => 14,
VirtualKeyCode::P => 15,
VirtualKeyCode::Q => 16,
VirtualKeyCode::R => 17,
VirtualKeyCode::S => 18,
VirtualKeyCode::T => 19,
VirtualKeyCode::U => 20,
VirtualKeyCode::V => 21,
VirtualKeyCode::W => 22,
VirtualKeyCode::X => 23,
VirtualKeyCode::Y => 24,
VirtualKeyCode::Z => 25,
_ => -1,
}
}
fn iclamp(val: i32, min: i32, max: i32) -> i32 {
i32::max(min, i32::min(val, max))
}
#[cfg(test)]
mod tests {
use super::iclamp;
#[test]
fn test_iclamp() {
assert!(iclamp(1, 0, 2) == 1);
assert!(iclamp(5, 0, 2) == 2);
assert!(iclamp(-5, 0, 2) == 0);
}
}