1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
//! Render a simple ASCII bitmap font.
//!
//! Requires the `font` feature flag.
use blit::{prelude::SubRect, Blit, BlitBuffer, BlitOptions, ToBlitBuffer};
use vek::{Extent2, Vec2};
/// Pixel font loaded from an image.
#[derive(Debug)]
pub struct Font {
/// Image to render.
sprite: BlitBuffer,
/// Size of a single character.
char_size: Extent2<u8>,
}
impl Font {
/// Construct the font from a bitmap with an alpha channel.
pub fn from_buffer_with_alpha<B>(buffer: B, alpha: u8, char_size: Extent2<u8>) -> Self
where
B: ToBlitBuffer,
{
let sprite = buffer.to_blit_buffer_with_alpha(alpha);
Self { sprite, char_size }
}
/// Construct the font from a bitmap where a single color is the alpha mask.
pub fn from_buffer_with_mask_color<B>(
buffer: B,
mask_color: u32,
char_size: Extent2<u8>,
) -> Self
where
B: ToBlitBuffer,
{
let sprite = buffer.to_blit_buffer_with_mask_color(mask_color);
Self { sprite, char_size }
}
/// Render ASCII text on a pixel buffer.
///
/// Start from the top-left.
pub fn render(
&self,
text: &str,
position: Vec2<f64>,
canvas: &mut [u32],
canvas_size: Extent2<usize>,
) {
// First character in the image
let char_start = '!';
let char_end = '~';
let pos: Vec2<i32> = position.as_() - (self.char_size.w as i32, 0);
let mut x = pos.x;
let mut y = pos.y;
// Draw each character from the string
text.chars().for_each(|ch| {
// Move the cursor
x += self.char_size.w as i32;
// Don't draw characters that are not in the picture
if ch < char_start || ch > char_end {
if ch == '\n' {
x = pos.x;
y += self.char_size.h as i32;
} else if ch == '\t' {
x += self.char_size.w as i32 * 3;
}
return;
}
// The sub rectangle offset of the character is based on the starting character and counted using the ASCII index
let char_offset = (ch as u8 - char_start as u8) as u32 * self.char_size.w as u32;
// Draw the character
self.sprite.blit(
canvas,
canvas_size.into_tuple().into(),
&BlitOptions::new_position(x, y).with_sub_rect(SubRect::new(
char_offset,
0,
self.char_size.into_tuple(),
)),
);
});
}
/// Render ASCII text on a pixel buffer.
///
/// Center the text around the point.
/// Currently does not support multi-line strings yet.
pub fn render_centered(
&self,
text: &str,
position: Vec2<f64>,
canvas: &mut [u32],
canvas_size: Extent2<usize>,
) {
self.render(
text,
position
- Vec2::new(
(text.len() as f64 * self.char_size.w as f64) / 2.0,
self.char_size.h as f64 / 2.0,
),
canvas,
canvas_size,
)
}
}