use super::super::drawable::*;
use super::super::transform::*;
use super::Font;
use coord::{Coord, ToUnsigned};
const FONT_IMAGE: &[u8] = include_bytes!("../../data/font8x16_1bpp.raw");
const CHAR_HEIGHT: u32 = 16;
const CHAR_WIDTH: u32 = 8;
const FIRST_CHARCODE: u32 = 32; const FONT_IMAGE_WIDTH: u32 = 128;
const CHARS_PER_ROW: u32 = FONT_IMAGE_WIDTH / CHAR_WIDTH;
#[derive(Debug, Clone, Copy)]
pub struct Font8x16<'a> {
pub pos: Coord,
text: &'a str,
color: u8,
}
impl<'a> Font<'a> for Font8x16<'a> {
fn render_str(text: &'a str, color: u8) -> Font8x16<'a> {
Self {
pos: Coord::new(0, 0),
text,
color,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Font8x16Iterator<'a> {
char_walk_x: u32,
char_walk_y: u32,
current_char: Option<char>,
idx: usize,
pos: Coord,
text: &'a str,
color: u8,
}
impl<'a> IntoIterator for &'a Font8x16<'a> {
type IntoIter = Font8x16Iterator<'a>;
type Item = Pixel;
fn into_iter(self) -> Self::IntoIter {
Font8x16Iterator {
current_char: self.text.chars().next(),
idx: 0,
text: self.text,
char_walk_x: 0,
char_walk_y: 0,
pos: self.pos,
color: self.color,
}
}
}
impl<'a> Iterator for Font8x16Iterator<'a> {
type Item = Pixel;
fn next(&mut self) -> Option<Self::Item> {
if self.pos[0] + ((self.text.len() as i32 * CHAR_WIDTH as i32)) < 0
|| self.pos[1] + (CHAR_HEIGHT as i32) < 0
{
return None;
}
if let Some(current_char) = self.current_char {
let pixel = loop {
let char_offset = current_char as u32 - FIRST_CHARCODE;
let row = char_offset / CHARS_PER_ROW;
let char_x = (char_offset - (row * CHARS_PER_ROW)) * CHAR_WIDTH;
let char_y = row * CHAR_HEIGHT;
let bitmap_bit_index = char_x
+ (FONT_IMAGE_WIDTH * char_y)
+ self.char_walk_x
+ (self.char_walk_y * FONT_IMAGE_WIDTH);
let bitmap_byte = bitmap_bit_index / 8;
let bitmap_bit = 7 - (bitmap_bit_index % 8);
let color = if (FONT_IMAGE[bitmap_byte as usize] >> bitmap_bit) & 1 == 1 {
self.color
} else {
0 };
self.char_walk_x += 1;
if self.char_walk_x >= CHAR_WIDTH {
self.char_walk_x = 0;
self.char_walk_y += 1;
if self.char_walk_y >= CHAR_HEIGHT {
self.char_walk_y = 0;
self.idx += 1;
self.current_char = self.text.chars().skip(self.idx).next();
}
}
let x =
self.pos[0] + (CHAR_WIDTH * self.idx as u32) as i32 + self.char_walk_x as i32;
let y = self.pos[1] + self.char_walk_y as i32;
if x >= 0 && y >= 0 {
break Some((Coord::new(x, y).to_unsigned(), color));
}
};
pixel
} else {
None
}
}
}
impl<'a> Drawable for Font8x16<'a> {}
impl<'a> Transform for Font8x16<'a> {
fn translate(&self, by: Coord) -> Self {
Self {
pos: self.pos + by,
..*self
}
}
fn translate_mut(&mut self, by: Coord) -> &mut Self {
self.pos += by;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn off_screen_text_does_not_infinite_loop() {
let text = Font8x16::render_str("Hello World!", 1).translate(Coord::new(5, -20));
let mut it = text.into_iter();
assert_eq!(it.next(), None);
}
}