1use crate::api::GameBoyEmulatorConfig; 2use crate::ppu::PpuFrameBuffer; 3use crate::{HardwareMode, ppu}; 4use bincode::{Decode, Encode}; 5use gb_config::GbPalette; 6use jgenesis_common::boxedarray::BoxedColorArray; 7use jgenesis_common::frontend::Color; 8use std::iter; 9use std::ops::{Deref, DerefMut};
0/0/0 = black and 255/255/255 = white, so linearly map [0,3] to [255,0]
Render with a light green tint
Render with an intense green tint that somewhat mimics the original Game Boy LCD screen
[round(255 * i / 31) for i in range(32)]
29#[derive(Debug, Clone, Encode, Decode)] 30pub(crate) struct RgbaFrameBuffer(BoxedColorArray<{ ppu::FRAME_BUFFER_LEN }>); 31 32impl RgbaFrameBuffer { 33 pub(crate) fn copy_from( 34 &mut self, 35 ppu_frame_buffer: &PpuFrameBuffer, 36 hardware_mode: HardwareMode, 37 config: &GameBoyEmulatorConfig, 38 ) { 39 match hardware_mode { 40 HardwareMode::Dmg => { 41 self.do_copy(ppu_frame_buffer, dmg_map_color(config)); 42 } 43 HardwareMode::Cgb => { 44 self.do_copy(ppu_frame_buffer, cgb_map_color); 45 } 46 } 47 } 48 49 fn do_copy(&mut self, ppu_frame_buffer: &PpuFrameBuffer, map_color: impl Fn(u16) -> Color) { 50 for (&ppu_color, rgba_color) in iter::zip(ppu_frame_buffer.iter(), self.iter_mut()) { 51 *rgba_color = map_color(ppu_color); 52 } 53 } 54} 55 56fn dmg_map_color(config: &GameBoyEmulatorConfig) -> impl Fn(u16) -> Color { 57 let color_mapping = match config.gb_palette { 58 GbPalette::BlackAndWhite => GB_COLOR_TO_RGB_BW, 59 GbPalette::GreenTint => GB_COLOR_TO_RGB_GREEN_TINT, 60 GbPalette::LimeGreen => GB_COLOR_TO_RGB_LIME_GREEN, 61 GbPalette::Custom => config.gb_custom_palette.map(|(r, g, b)| [r, g, b]), 62 }; 63 64 move |ppu_color| { 65 let [r, g, b] = color_mapping[ppu_color as usize]; 66 Color::rgb(r, g, b) 67 } 68} 69 70fn cgb_map_color(ppu_color: u16) -> Color { 71 let (r, g, b) = parse_cgb_color(ppu_color); 72 Color::rgb(RGB_5_TO_8[r as usize], RGB_5_TO_8[g as usize], RGB_5_TO_8[b as usize]) 73} 74 75pub(crate) fn parse_cgb_color(ppu_color: u16) -> (u8, u8, u8) { 76 let r = ppu_color & 0x1F; 77 let g = (ppu_color >> 5) & 0x1F; 78 let b = (ppu_color >> 10) & 0x1F; 79 80 (r as u8, g as u8, b as u8) 81} 82 83impl Default for RgbaFrameBuffer { 84 fn default() -> Self { 85 Self(BoxedColorArray::new()) 86 } 87} 88 89impl Deref for RgbaFrameBuffer { 90 type Target = [Color; ppu::FRAME_BUFFER_LEN]; 91 92 fn deref(&self) -> &Self::Target { 93 &self.0 94 } 95} 96 97impl DerefMut for RgbaFrameBuffer { 98 fn deref_mut(&mut self) -> &mut Self::Target { 99 &mut self.0 100 } 101}