make fonts generic over GeneralBitmap types
this also includes a semi-important change where the existing BitmaskCharacter draw implementation will now not draw anything if FontRenderOpts::None is passed in, instead of just substituting color 0. this probably makes more sense this way anyway
This commit is contained in:
parent
434bd6dbed
commit
986a2a9677
|
@ -3,6 +3,7 @@ use std::path::Path;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use ggdt::audio::*;
|
use ggdt::audio::*;
|
||||||
|
use ggdt::graphics::*;
|
||||||
use ggdt::graphics::indexed::*;
|
use ggdt::graphics::indexed::*;
|
||||||
use ggdt::system::*;
|
use ggdt::system::*;
|
||||||
use ggdt::utils::rnd_value;
|
use ggdt::utils::rnd_value;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::path::Path;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use ggdt::*;
|
use ggdt::*;
|
||||||
|
use ggdt::graphics::*;
|
||||||
use ggdt::graphics::indexed::*;
|
use ggdt::graphics::indexed::*;
|
||||||
use ggdt::math::*;
|
use ggdt::math::*;
|
||||||
use ggdt::system::*;
|
use ggdt::system::*;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use ggdt::entities::*;
|
use ggdt::entities::*;
|
||||||
use ggdt::events::*;
|
use ggdt::events::*;
|
||||||
|
use ggdt::graphics::*;
|
||||||
use ggdt::graphics::indexed::*;
|
use ggdt::graphics::indexed::*;
|
||||||
use ggdt::math::*;
|
use ggdt::math::*;
|
||||||
use ggdt::states::*;
|
use ggdt::states::*;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::path::Path;
|
||||||
|
|
||||||
use ggdt::base::*;
|
use ggdt::base::*;
|
||||||
use ggdt::entities::*;
|
use ggdt::entities::*;
|
||||||
|
use ggdt::graphics::font::*;
|
||||||
use ggdt::graphics::indexed::*;
|
use ggdt::graphics::indexed::*;
|
||||||
use ggdt::states::*;
|
use ggdt::states::*;
|
||||||
use ggdt::system::*;
|
use ggdt::system::*;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use ggdt::{SCREEN_BOTTOM, SCREEN_RIGHT};
|
use ggdt::{SCREEN_BOTTOM, SCREEN_RIGHT};
|
||||||
|
use ggdt::graphics::*;
|
||||||
use ggdt::graphics::indexed::*;
|
use ggdt::graphics::indexed::*;
|
||||||
use ggdt::system::*;
|
use ggdt::system::*;
|
||||||
use ggdt::utils::rnd_value;
|
use ggdt::utils::rnd_value;
|
||||||
|
|
|
@ -35,6 +35,9 @@ pub trait GeneralBitmap: Sized + Clone {
|
||||||
/// Returns the height of the bitmap in pixels.
|
/// Returns the height of the bitmap in pixels.
|
||||||
fn height(&self) -> u32;
|
fn height(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the current clipping region set on this bitmap.
|
||||||
|
fn clip_region(&self) -> &Rect;
|
||||||
|
|
||||||
/// Returns a rect representing the full bitmap boundaries, ignoring the current clipping
|
/// Returns a rect representing the full bitmap boundaries, ignoring the current clipping
|
||||||
/// region set on this bitmap.
|
/// region set on this bitmap.
|
||||||
fn full_bounds(&self) -> Rect;
|
fn full_bounds(&self) -> Rect;
|
||||||
|
@ -111,6 +114,10 @@ impl GeneralBitmap for indexed::Bitmap {
|
||||||
self.height()
|
self.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clip_region(&self) -> &Rect {
|
||||||
|
self.clip_region()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn full_bounds(&self) -> Rect {
|
fn full_bounds(&self) -> Rect {
|
||||||
self.full_bounds()
|
self.full_bounds()
|
||||||
|
|
|
@ -4,12 +4,14 @@ use std::io::{BufReader, BufWriter, Cursor};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
|
use num_traits::{PrimInt, Unsigned};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::graphics::*;
|
||||||
use crate::graphics::indexed::*;
|
use crate::graphics::indexed::*;
|
||||||
use crate::math::*;
|
use crate::math::*;
|
||||||
|
|
||||||
pub static VGA_FONT_BYTES: &[u8] = include_bytes!("../../../assets/vga.fnt");
|
pub static VGA_FONT_BYTES: &[u8] = include_bytes!("../../assets/vga.fnt");
|
||||||
|
|
||||||
pub const NUM_CHARS: usize = 256;
|
pub const NUM_CHARS: usize = 256;
|
||||||
pub const CHAR_HEIGHT: usize = 8;
|
pub const CHAR_HEIGHT: usize = 8;
|
||||||
|
@ -25,14 +27,16 @@ pub enum FontError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum FontRenderOpts {
|
pub enum FontRenderOpts<PixelType: PrimInt + Unsigned> {
|
||||||
Color(u8),
|
Color(PixelType),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Character {
|
pub trait Character {
|
||||||
fn bounds(&self) -> &Rect;
|
fn bounds(&self) -> &Rect;
|
||||||
fn draw(&self, dest: &mut Bitmap, x: i32, y: i32, opts: FontRenderOpts);
|
fn draw<BitmapType>(&self, dest: &mut BitmapType, x: i32, y: i32, opts: FontRenderOpts<BitmapType::PixelType>)
|
||||||
|
where
|
||||||
|
BitmapType: GeneralBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Font {
|
pub trait Font {
|
||||||
|
@ -41,7 +45,9 @@ pub trait Font {
|
||||||
fn character(&self, ch: char) -> &Self::CharacterType;
|
fn character(&self, ch: char) -> &Self::CharacterType;
|
||||||
fn space_width(&self) -> u8;
|
fn space_width(&self) -> u8;
|
||||||
fn line_height(&self) -> u8;
|
fn line_height(&self) -> u8;
|
||||||
fn measure(&self, text: &str, opts: FontRenderOpts) -> (u32, u32);
|
fn measure<PixelType>(&self, text: &str, opts: FontRenderOpts<PixelType>) -> (u32, u32)
|
||||||
|
where
|
||||||
|
PixelType: PrimInt + Unsigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
@ -56,7 +62,10 @@ impl Character for BitmaskCharacter {
|
||||||
&self.bounds
|
&self.bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, dest: &mut Bitmap, x: i32, y: i32, opts: FontRenderOpts) {
|
fn draw<BitmapType>(&self, dest: &mut BitmapType, x: i32, y: i32, opts: FontRenderOpts<BitmapType::PixelType>)
|
||||||
|
where
|
||||||
|
BitmapType: GeneralBitmap
|
||||||
|
{
|
||||||
// out of bounds check
|
// out of bounds check
|
||||||
if ((x + self.bounds.width as i32) < dest.clip_region().x)
|
if ((x + self.bounds.width as i32) < dest.clip_region().x)
|
||||||
|| ((y + self.bounds.height as i32) < dest.clip_region().y)
|
|| ((y + self.bounds.height as i32) < dest.clip_region().y)
|
||||||
|
@ -68,7 +77,11 @@ impl Character for BitmaskCharacter {
|
||||||
|
|
||||||
let color = match opts {
|
let color = match opts {
|
||||||
FontRenderOpts::Color(color) => color,
|
FontRenderOpts::Color(color) => color,
|
||||||
_ => 0,
|
// this kind of highlights a weakness of this design i guess. what does it mean to render a BitmaskFont,
|
||||||
|
// which has no inherent colour information in it, when there is no specific render colour passed in?
|
||||||
|
// TODO: is it better to return an error here? should a BitmaskFont have a "default colour" to fall back to?
|
||||||
|
// or, should a Bitmap have a "default colour" property we could fall back to? not sure!
|
||||||
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: i'm sure this can be optimized, lol
|
// TODO: i'm sure this can be optimized, lol
|
||||||
|
@ -195,7 +208,10 @@ impl Font for BitmaskFont {
|
||||||
self.line_height
|
self.line_height
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, text: &str, _opts: FontRenderOpts) -> (u32, u32) {
|
fn measure<PixelType>(&self, text: &str, _opts: FontRenderOpts<PixelType>) -> (u32, u32)
|
||||||
|
where
|
||||||
|
PixelType: PrimInt + Unsigned
|
||||||
|
{
|
||||||
if text.is_empty() {
|
if text.is_empty() {
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
}
|
}
|
||||||
|
@ -249,29 +265,29 @@ pub mod tests {
|
||||||
{
|
{
|
||||||
let font = BitmaskFont::load_from_file(Path::new("./assets/vga.fnt"))?;
|
let font = BitmaskFont::load_from_file(Path::new("./assets/vga.fnt"))?;
|
||||||
|
|
||||||
assert_eq!((40, 8), font.measure("Hello", FontRenderOpts::None));
|
assert_eq!((40, 8), font.measure("Hello", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((40, 16), font.measure("Hello\nthere", FontRenderOpts::None));
|
assert_eq!((40, 16), font.measure("Hello\nthere", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((88, 24), font.measure("longer line\nshort\nthe end", FontRenderOpts::None));
|
assert_eq!((88, 24), font.measure("longer line\nshort\nthe end", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((0, 0), font.measure("", FontRenderOpts::None));
|
assert_eq!((0, 0), font.measure("", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((0, 0), font.measure(" ", FontRenderOpts::None));
|
assert_eq!((0, 0), font.measure(" ", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((40, 16), font.measure("\nhello", FontRenderOpts::None));
|
assert_eq!((40, 16), font.measure("\nhello", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((0, 0), font.measure("\n", FontRenderOpts::None));
|
assert_eq!((0, 0), font.measure("\n", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((40, 8), font.measure("hello\n", FontRenderOpts::None));
|
assert_eq!((40, 8), font.measure("hello\n", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((40, 24), font.measure("hello\n\nthere", FontRenderOpts::None));
|
assert_eq!((40, 24), font.measure("hello\n\nthere", FontRenderOpts::<u8>::None));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let font = BitmaskFont::load_from_file(Path::new("./test-assets/small.fnt"))?;
|
let font = BitmaskFont::load_from_file(Path::new("./test-assets/small.fnt"))?;
|
||||||
|
|
||||||
assert_eq!((22, 7), font.measure("Hello", FontRenderOpts::None));
|
assert_eq!((22, 7), font.measure("Hello", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((24, 14), font.measure("Hello\nthere", FontRenderOpts::None));
|
assert_eq!((24, 14), font.measure("Hello\nthere", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((50, 21), font.measure("longer line\nshort\nthe end", FontRenderOpts::None));
|
assert_eq!((50, 21), font.measure("longer line\nshort\nthe end", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((0, 0), font.measure("", FontRenderOpts::None));
|
assert_eq!((0, 0), font.measure("", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((0, 0), font.measure(" ", FontRenderOpts::None));
|
assert_eq!((0, 0), font.measure(" ", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((21, 14), font.measure("\nhello", FontRenderOpts::None));
|
assert_eq!((21, 14), font.measure("\nhello", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((0, 0), font.measure("\n", FontRenderOpts::None));
|
assert_eq!((0, 0), font.measure("\n", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((21, 7), font.measure("hello\n", FontRenderOpts::None));
|
assert_eq!((21, 7), font.measure("hello\n", FontRenderOpts::<u8>::None));
|
||||||
assert_eq!((24, 21), font.measure("hello\n\nthere", FontRenderOpts::None));
|
assert_eq!((24, 21), font.measure("hello\n\nthere", FontRenderOpts::<u8>::None));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
|
@ -1,5 +1,6 @@
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
|
|
||||||
|
use crate::graphics::*;
|
||||||
use crate::graphics::indexed::*;
|
use crate::graphics::indexed::*;
|
||||||
use crate::math::*;
|
use crate::math::*;
|
||||||
|
|
||||||
|
@ -76,13 +77,13 @@ impl Bitmap {
|
||||||
|
|
||||||
/// Renders a single character using the font given.
|
/// Renders a single character using the font given.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn print_char<T: Font>(&mut self, ch: char, x: i32, y: i32, opts: FontRenderOpts, font: &T) {
|
pub fn print_char<T: Font>(&mut self, ch: char, x: i32, y: i32, opts: FontRenderOpts<u8>, font: &T) {
|
||||||
font.character(ch)
|
font.character(ch)
|
||||||
.draw(self, x, y, opts);
|
.draw(self, x, y, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the string of text using the font given.
|
/// Renders the string of text using the font given.
|
||||||
pub fn print_string<T: Font>(&mut self, text: &str, x: i32, y: i32, opts: FontRenderOpts, font: &T) {
|
pub fn print_string<T: Font>(&mut self, text: &str, x: i32, y: i32, opts: FontRenderOpts<u8>, font: &T) {
|
||||||
let mut current_x = x;
|
let mut current_x = x;
|
||||||
let mut current_y = y;
|
let mut current_y = y;
|
||||||
for ch in text.chars() {
|
for ch in text.chars() {
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
|
|
||||||
pub use self::bitmap::*;
|
pub use self::bitmap::*;
|
||||||
pub use self::blendmap::*;
|
pub use self::blendmap::*;
|
||||||
pub use self::font::*;
|
|
||||||
pub use self::palette::*;
|
pub use self::palette::*;
|
||||||
|
|
||||||
pub mod bitmap;
|
pub mod bitmap;
|
||||||
pub mod blendmap;
|
pub mod blendmap;
|
||||||
pub mod font;
|
|
||||||
pub mod palette;
|
pub mod palette;
|
|
@ -1,7 +1,9 @@
|
||||||
pub use self::bitmap::*;
|
pub use self::bitmap::*;
|
||||||
pub use self::bitmapatlas::*;
|
pub use self::bitmapatlas::*;
|
||||||
|
pub use self::font::*;
|
||||||
|
|
||||||
pub mod bitmap;
|
pub mod bitmap;
|
||||||
pub mod bitmapatlas;
|
pub mod bitmapatlas;
|
||||||
|
pub mod font;
|
||||||
pub mod indexed;
|
pub mod indexed;
|
||||||
pub mod rgb;
|
pub mod rgb;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//! instance to provide something resembling an old DOS VGA mode 13h style experience (there are differences, however).
|
//! instance to provide something resembling an old DOS VGA mode 13h style experience (there are differences, however).
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
|
//! use ggdt::graphics::*;
|
||||||
//! use ggdt::graphics::indexed::*;
|
//! use ggdt::graphics::indexed::*;
|
||||||
//! use ggdt::system::*;
|
//! use ggdt::system::*;
|
||||||
//!
|
//!
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
use sdl2::video::Window;
|
use sdl2::video::Window;
|
||||||
|
|
||||||
use crate::system::*;
|
use crate::system::*;
|
||||||
|
use crate::graphics::*;
|
||||||
use crate::graphics::indexed::*;
|
use crate::graphics::indexed::*;
|
||||||
|
|
||||||
/// Configuration / builder for configuring and constructing an instance of [`DosLike`].
|
/// Configuration / builder for configuring and constructing an instance of [`DosLike`].
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ggdt::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
use ggdt::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||||
|
use ggdt::graphics::*;
|
||||||
use ggdt::graphics::indexed::*;
|
use ggdt::graphics::indexed::*;
|
||||||
|
|
||||||
fn setup() -> (Bitmap, Palette) {
|
fn setup() -> (Bitmap, Palette) {
|
||||||
|
|
Loading…
Reference in a new issue