use game_toolkit_dosvideo::prelude::*;
const SCALE: i32 = 2;
const VIEWS: [&str; 4] = ["comparison", "overlay", "built-in", "reference"];
struct FontDiff {
ours: &'static Font,
reference: Font,
differing: Vec<u8>,
view: usize,
screen: Bitmap,
}
impl FontDiff {
fn draw(&mut self) {
let s = &mut self.screen;
s.clear(0);
let label = Font::cga();
let h = i32::from(self.reference.height());
s.text(
2,
2,
&format!("8x{h}: {} of 256 glyphs differ", self.differing.len()),
15,
None,
label,
);
s.text(
2,
11,
&format!("view: {} 1-4/Tab view, Esc quit", VIEWS[self.view]),
7,
None,
label,
);
let panels = if self.view == 0 { 2 } else { 1 };
let cell_w = 8 * SCALE + 2;
let entry_w = panels * cell_w + 18;
let entry_h = h * SCALE + 12;
let per_row = (318 / entry_w) as usize;
for (i, &code) in self.differing.iter().enumerate() {
let x = 2 + (i % per_row) as i32 * entry_w;
let y = 24 + (i / per_row) as i32 * entry_h;
if y + entry_h > 200 {
s.text(2, 192, "(more glyphs than fit)", 40, None, label);
break;
}
s.text(x, y, &format!("{code:02X}"), 7, None, label);
let (a, b) = (self.ours.glyph(code), self.reference.glyph(code));
for panel in 0..panels {
let px = x + panel * cell_w;
for row in 0..h as usize {
for col in 0..8 {
let bit = 0x80 >> col;
let (on_a, on_b) = (a[row] & bit != 0, b[row] & bit != 0);
let c = match self.view {
0 => {
let on = if panel == 0 { on_a } else { on_b };
match (on_a == on_b, on) {
(true, true) => 15,
(true, false) => 20,
(false, true) => 40,
(false, false) => 4,
}
}
1 => match (on_a, on_b) {
(true, true) => 15,
(true, false) => 40,
(false, true) => 52,
(false, false) => 20,
},
2 if on_a => 15,
3 if on_b => 15,
_ => 20,
};
s.fill_rect(
px + col * SCALE,
y + 9 + row as i32 * SCALE,
SCALE,
SCALE,
c,
);
}
}
}
}
}
}
impl DosGame for FontDiff {
fn init(dos: &mut Dos) -> anyhow::Result<Self> {
let path = std::env::args()
.nth(1)
.ok_or_else(|| anyhow::anyhow!("usage: font_diff <reference font .bin>"))?;
let data = std::fs::read(&path)?;
let height = u8::try_from(data.len() / 256)?;
let reference = Font::from_raw(height, &data)
.ok_or_else(|| anyhow::anyhow!("{path}: not 256 glyphs of whole rows"))?;
let ours = match height {
16 => Font::vga(),
14 => Font::ega(),
8 => Font::cga(),
h => anyhow::bail!("no built-in 8x{h} font to compare with"),
};
let differing = (0..=255)
.filter(|&c| ours.glyph(c) != reference.glyph(c))
.collect();
dos.set_mode(0x13);
let mut app = Self {
ours,
reference,
differing,
view: 0,
screen: Bitmap::new(320, 200),
};
app.draw();
Ok(app)
}
fn step(&mut self, dos: &mut Dos) {
while let Some(k) = dos.getch() {
let view = match k.scan {
sc::ESC => {
dos.exit();
None
}
sc::TAB => Some((self.view + 1) % VIEWS.len()),
s @ sc::N1..=sc::N4 => Some((s - sc::N1) as usize),
_ => None,
};
if let Some(v) = view {
self.view = v;
self.draw();
}
}
dos.wait_vretrace();
dos.blit13(&self.screen);
}
}
const KEYS: &[(&str, &str)] = &[
("1-4", "view: comparison, overlay, built-in, reference"),
("Tab", "next view"),
("Esc", "quit"),
];
fn main() -> anyhow::Result<()> {
env_logger::init();
run::<FontDiff>(DosConfig::new("font diff", Adapter::Vga).with_keys(KEYS))
}