font.rsannotatedfont.rssource68 lines · 1.8 KB · raw
1//! Sega CD font rendering / color calculation registers
2
3use bincode::{Decode, Encode};
4use jgenesis_common::num::{GetBit, U16Ext};
5
6#[derive(Debug, Clone, Default, Encode, Decode)]
7pub struct FontRegisters {
8    color_0: u8,
9    color_1: u8,
10    font_bits: u16,
11}
12
13impl FontRegisters {
14    pub fn new() -> Self {
15        Self::default()
16    }
17
18    pub fn read_color(&self) -> u8 {
19        (self.color_1 << 4) | self.color_0
20    }
21
22    pub fn write_color(&mut self, color_byte: u8) {
23        self.color_0 = color_byte & 0x0F;
24        self.color_1 = color_byte >> 4;
25    }
26
27    pub fn font_bits(&self) -> u16 {
28        self.font_bits
29    }
30
31    pub fn write_font_bits(&mut self, font_bits: u16) {
32        self.font_bits = font_bits;
33    }
34
35    pub fn write_font_bits_msb(&mut self, font_bits_msb: u8) {
36        self.font_bits.set_msb(font_bits_msb);
37    }
38
39    pub fn write_font_bits_lsb(&mut self, font_bits_lsb: u8) {
40        self.font_bits.set_lsb(font_bits_lsb);
41    }
42
43    pub fn read_font_data(&self, address: u32) -> u16 {
44        // Font data registers are mapped at $FF8050-$FF8057
45        // $FF8050-$FF8051: Bit 15-12 data
46        // $FF8052-$FF8053: Bit 11-8 data
47        // $FF8054-$FF8055: Bit 7-4 data
48        // $FF8056-$FF8057: Bit 3-0 data
49        let word_idx = (address & 0x07) >> 1;
50        let base_font_bit = ((3 - word_idx) << 2) as u8;
51
52        (0..16)
53            .map(|i| {
54                let font_bit_idx = base_font_bit + (i >> 2);
55                let font_color_idx = i & 0x03;
56
57                let bit = if self.font_bits.bit(font_bit_idx) {
58                    self.color_1.bit(font_color_idx)
59                } else {
60                    self.color_0.bit(font_color_idx)
61                };
62
63                u16::from(bit) << i
64            })
65            .reduce(|a, b| a | b)
66            .unwrap()
67    }
68}