1use crate::vdp::{Cram, DarkenColors, VdpConfig}; 2use bincode::{Decode, Encode}; 3use jgenesis_common::frontend::Color; 4use std::ops::{Add, AddAssign}; 5 6#[derive(Debug, Clone, Encode, Decode)] 7pub struct ColorTables { 8 pub normal: [u8; 8], 9 pub shadow: [u8; 8], 10 pub highlight: [u8; 8], 11} 12 13impl ColorTables { 14 // Values from http://gendev.spritesmind.net/forum/viewtopic.php?f=22&t=2188 15 pub const NON_LINEAR: Self = Self { 16 normal: [0, 52, 87, 116, 144, 172, 206, 255], 17 shadow: [0, 29, 52, 70, 87, 101, 116, 130], 18 highlight: [130, 144, 158, 172, 187, 206, 228, 255], 19 }; 20 21 pub const LINEAR: Self = Self { 22 normal: [0, 36, 73, 109, 146, 182, 219, 255], // round(i * 255 / 7) 23 shadow: [0, 18, 36, 55, 73, 91, 109, 128], // round(i * 255 / 7 / 2) 24 highlight: [128, 146, 164, 182, 200, 219, 237, 255], // round(255 / 2 + i * 255 / 7 / 2) 25 }; 26 27 // All values -8 relative to NON_LINEAR 28 pub const NON_LINEAR_DARK: Self = Self { 29 normal: [0, 44, 79, 108, 136, 164, 198, 247], 30 shadow: [0, 21, 44, 62, 79, 93, 108, 122], 31 highlight: [122, 136, 150, 164, 179, 198, 220, 247], 32 }; 33 34 // All values -8 relative to LINEAR 35 pub const LINEAR_DARK: Self = Self { 36 normal: [0, 28, 65, 101, 138, 174, 211, 247], 37 shadow: [0, 10, 28, 47, 65, 83, 101, 120], 38 highlight: [120, 138, 156, 174, 192, 211, 229, 247], 39 }; 40 41 pub fn from_config(config: &VdpConfig) -> Self { 42 match (config.non_linear_color_scale, config.color_adjustment) { 43 (true, DarkenColors::No) => Self::NON_LINEAR, 44 (true, DarkenColors::Yes) => Self::NON_LINEAR_DARK, 45 (false, DarkenColors::No) => Self::LINEAR, 46 (false, DarkenColors::Yes) => Self::LINEAR_DARK, 47 } 48 } 49} 50 51#[derive(Debug, Clone, Copy, PartialEq, Eq)] 52pub enum ColorModifier { 53 None, 54 Shadow, 55 Highlight, 56} 57 58impl Add for ColorModifier { 59 type Output = Self; 60 61 #[allow(clippy::unnested_or_patterns)] 62 fn add(self, rhs: Self) -> Self::Output { 63 match (self, rhs) { 64 (Self::None, Self::None) 65 | (Self::Shadow, Self::Highlight) 66 | (Self::Highlight, Self::Shadow) => Self::None, 67 (Self::None, Self::Shadow) 68 | (Self::Shadow, Self::None) 69 | (Self::Shadow, Self::Shadow) => Self::Shadow, 70 (Self::None, Self::Highlight) 71 | (Self::Highlight, Self::None) 72 | (Self::Highlight, Self::Highlight) => Self::Highlight, 73 } 74 } 75} 76 77impl AddAssign for ColorModifier { 78 fn add_assign(&mut self, rhs: Self) { 79 *self = *self + rhs; 80 } 81} 82 83#[inline] 84pub fn gen_to_rgba( 85 r: u8, 86 g: u8, 87 b: u8, 88 a: u8, 89 modifier: ColorModifier, 90 color_tables: &ColorTables, 91) -> Color { 92 let colors = match modifier { 93 ColorModifier::None => color_tables.normal, 94 ColorModifier::Shadow => color_tables.shadow, 95 ColorModifier::Highlight => color_tables.highlight, 96 }; 97 Color::rgba(colors[r as usize], colors[g as usize], colors[b as usize], a) 98} 99 100pub fn resolve(cram: &Cram, palette: u8, color_id: u8) -> u16 { 101 lookup(cram, (palette << 4) | color_id) 102} 103 104pub fn lookup(cram: &Cram, cram_idx: u8) -> u16 { 105 // Use alpha bit to indicate whether pixel is transparent (needed by 32X) 106 // 32X transparency is based on color index being 0 (verified on hardware) 107 let alpha = cram_idx & 0xF != 0; 108 (cram[cram_idx as usize] & 0x7FFF) | (u16::from(alpha) << 15) 109}