Add DMG color palettes (Cocoa)

This commit is contained in:
Lior Halphon 2020-01-29 14:19:11 +02:00
parent 95af00a752
commit 163a5ea20c
7 changed files with 143 additions and 30 deletions

View File

@ -184,6 +184,27 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
}
}
- (void) updatePalette
{
switch ([[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"]) {
case 1:
GB_set_palette(&gb, &GB_PALETTE_DMG);
break;
case 2:
GB_set_palette(&gb, &GB_PALETTE_MGB);
break;
case 3:
GB_set_palette(&gb, &GB_PALETTE_GBL);
break;
default:
GB_set_palette(&gb, &GB_PALETTE_GREY);
break;
}
}
- (void) initCommon
{
GB_init(&gb, [self internalModel]);
@ -193,6 +214,7 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
GB_set_async_input_callback(&gb, (GB_input_callback_t) asyncConsoleInput);
GB_set_color_correction_mode(&gb, (GB_color_correction_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorCorrection"]);
[self updatePalette];
GB_set_rgb_encode_callback(&gb, rgbEncode);
GB_set_camera_get_pixel_callback(&gb, cameraGetPixel);
GB_set_camera_update_request_callback(&gb, cameraRequestUpdate);
@ -452,6 +474,12 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
name:@"GBColorCorrectionChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updatePalette)
name:@"GBColorPaletteChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateRewindLength)
name:@"GBRewindLengthChanged"

View File

@ -7,6 +7,7 @@
@property (strong) IBOutlet NSButton *aspectRatioCheckbox;
@property (strong) IBOutlet NSPopUpButton *highpassFilterPopupButton;
@property (strong) IBOutlet NSPopUpButton *colorCorrectionPopupButton;
@property (nonatomic, strong) IBOutlet NSPopUpButton *colorPalettePopupButton;
@property (strong) IBOutlet NSPopUpButton *rewindPopupButton;
@property (strong) IBOutlet NSButton *configureJoypadButton;
@property (strong) IBOutlet NSButton *skipButton;

View File

@ -14,6 +14,7 @@
NSPopUpButton *_graphicsFilterPopupButton;
NSPopUpButton *_highpassFilterPopupButton;
NSPopUpButton *_colorCorrectionPopupButton;
NSPopUpButton *_colorPalettePopupButton;
NSPopUpButton *_rewindPopupButton;
NSButton *_aspectRatioCheckbox;
NSEventModifierFlags previousModifiers;
@ -84,6 +85,18 @@
return _colorCorrectionPopupButton;
}
- (void)setColorPalettePopupButton:(NSPopUpButton *)colorPalettePopupButton
{
_colorPalettePopupButton = colorPalettePopupButton;
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"];
[_colorPalettePopupButton selectItemAtIndex:mode];
}
- (NSPopUpButton *)colorPalettePopupButton
{
return _colorPalettePopupButton;
}
- (void)setRewindPopupButton:(NSPopUpButton *)rewindPopupButton
{
_rewindPopupButton = rewindPopupButton;
@ -199,6 +212,14 @@
}
- (IBAction)colorPaletteChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
forKey:@"GBColorPalette"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorPaletteChanged" object:nil];
}
- (IBAction)rewindLengthChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])

View File

@ -63,6 +63,7 @@
<outlet property="bootROMsFolderItem" destination="Dzv-Gc-zoL" id="yhV-ZI-avD"/>
<outlet property="cgbPopupButton" destination="dlD-sk-SHO" id="4tg-SR-e17"/>
<outlet property="colorCorrectionPopupButton" destination="VEz-N4-uP6" id="EO2-Vt-JFJ"/>
<outlet property="colorPalettePopupButton" destination="Iwr-eI-SD1" id="Xzc-RZ-JtV"/>
<outlet property="configureJoypadButton" destination="Qa7-Z7-yfO" id="RaX-P3-oCX"/>
<outlet property="controlsTableView" destination="UDd-IJ-fxX" id="a1D-Md-yXv"/>
<outlet property="delegate" destination="-2" id="ASc-vN-Zbq"/>
@ -78,11 +79,11 @@
<point key="canvasLocation" x="183" y="354"/>
</window>
<customView id="sRK-wO-K6R">
<rect key="frame" x="0.0" y="0.0" width="292" height="166"/>
<rect key="frame" x="0.0" y="0.0" width="292" height="213"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T91-rh-rRp">
<rect key="frame" x="18" y="129" width="256" height="17"/>
<rect key="frame" x="18" y="176" width="256" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Graphics Filter:" id="pXg-WY-8Q5">
<font key="font" metaFont="system"/>
@ -91,7 +92,7 @@
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6pP-kK-EEC">
<rect key="frame" x="30" y="97" width="234" height="26"/>
<rect key="frame" x="30" y="144" width="234" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Nearest Neighbor (Pixelated)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="neN-eo-LA7" id="I1w-05-lGl">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
@ -127,7 +128,7 @@
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wc3-2K-6CD">
<rect key="frame" x="18" y="75" width="256" height="17"/>
<rect key="frame" x="18" y="122" width="256" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Color Correction:" id="5Si-hz-EK3">
<font key="font" metaFont="system"/>
@ -136,7 +137,7 @@
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VEz-N4-uP6">
<rect key="frame" x="30" y="43" width="234" height="26"/>
<rect key="frame" x="30" y="90" width="234" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Disabled" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="D2J-wV-1vu" id="fNJ-Fi-yOm">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
@ -156,6 +157,36 @@
<action selector="colorCorrectionChanged:" target="QvC-M9-y7g" id="Oq4-B5-nO6"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8fG-zm-hpr">
<rect key="frame" x="18" y="68" width="252" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Color Palette for Monochrome Models:" id="LAN-8Y-T7H">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Iwr-eI-SD1">
<rect key="frame" x="30" y="39" width="229" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Greyscale" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Ajr-5r-iIk" id="rEU-jh-m3j">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="dHJ-3R-Ora">
<items>
<menuItem title="Greyscale" state="on" id="Ajr-5r-iIk">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Lime (Game Boy)" id="snU-ht-fQq"/>
<menuItem title="Olive (Pocket)" id="MQi-yt-nsT"/>
<menuItem title="Teal (Light)" id="xlg-6i-Fhl"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="colorPaletteChanged:" target="QvC-M9-y7g" id="ui3-rg-PTs"/>
</connections>
</popUpButton>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfj-tg-7OP">
<rect key="frame" x="18" y="18" width="256" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -168,7 +199,7 @@
</connections>
</button>
</subviews>
<point key="canvasLocation" x="-176" y="589"/>
<point key="canvasLocation" x="-176" y="612.5"/>
</customView>
<customView id="ymk-46-SX7">
<rect key="frame" x="0.0" y="0.0" width="292" height="320"/>

View File

@ -142,9 +142,17 @@ static void display_vblank(GB_gameboy_t *gb)
}
}
else {
uint32_t color = (gb->io_registers[GB_IO_LCDC] & 0x80) && gb->stopped && GB_is_cgb(gb) ?
gb->rgb_encode_callback(gb, 0, 0, 0) :
gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
uint32_t color = 0;
if (GB_is_cgb(gb)) {
color = (gb->io_registers[GB_IO_LCDC] & 0x80) && gb->stopped ?
gb->rgb_encode_callback(gb, 0, 0, 0) :
gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
}
else {
color = (gb->io_registers[GB_IO_LCDC] & 0x80) && gb->stopped ?
gb->background_palettes_rgb[3] :
gb->background_palettes_rgb[4];
}
for (unsigned i = 0; i < WIDTH * LINES; i++) {
gb ->screen[i] = color;
}

View File

@ -573,21 +573,41 @@ void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback)
#endif
}
const GB_palette_t GB_PALETTE_GREY = {{{0x00, 0x00, 0x00}, {0x55, 0x55, 0x55}, {0xaa, 0xaa, 0xaa}, {0xff ,0xff, 0xff}, {0xff ,0xff, 0xff}}};
const GB_palette_t GB_PALETTE_DMG = {{{0x08, 0x18, 0x10}, {0x39, 0x61, 0x39}, {0x84, 0xa5, 0x63}, {0xc6, 0xde, 0x8c}, {0xd2 ,0xe6 ,0xa6}}};
const GB_palette_t GB_PALETTE_MGB = {{{0x07, 0x10, 0x0e}, {0x3a, 0x4c, 0x3a}, {0x81, 0x8d, 0x66}, {0xc2, 0xce, 0x93}, {0xcf, 0xda, 0xac}}};
const GB_palette_t GB_PALETTE_GBL = {{{0x0a, 0x1c, 0x15}, {0x35, 0x78, 0x62}, {0x56, 0xb4, 0x95}, {0x7f, 0xe2, 0xc3}, {0x91, 0xea, 0xd0}}};
static void update_dmg_palette(GB_gameboy_t *gb)
{
const GB_palette_t *palette = gb->dmg_palette ?: &GB_PALETTE_GREY;
if (gb->rgb_encode_callback && !GB_is_cgb(gb)) {
gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] =
gb->rgb_encode_callback(gb, palette->colors[3].r, palette->colors[3].g, palette->colors[3].b);
gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] =
gb->rgb_encode_callback(gb, palette->colors[2].r, palette->colors[2].g, palette->colors[2].b);
gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] =
gb->rgb_encode_callback(gb, palette->colors[1].r, palette->colors[1].g, palette->colors[1].b);
gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] =
gb->rgb_encode_callback(gb, palette->colors[0].r, palette->colors[0].g, palette->colors[0].b);
// LCD off color
gb->background_palettes_rgb[4] =
gb->rgb_encode_callback(gb, palette->colors[4].r, palette->colors[4].g, palette->colors[4].b);
}
}
void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette)
{
gb->dmg_palette = palette;
update_dmg_palette(gb);
}
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback)
{
if (!gb->rgb_encode_callback && !GB_is_cgb(gb)) {
gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] =
callback(gb, 0xFF, 0xFF, 0xFF);
gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] =
callback(gb, 0xAA, 0xAA, 0xAA);
gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] =
callback(gb, 0x55, 0x55, 0x55);
gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] =
callback(gb, 0, 0, 0);
}
gb->rgb_encode_callback = callback;
update_dmg_palette(gb);
for (unsigned i = 0; i < 32; i++) {
GB_palette_changed(gb, true, i * 2);
@ -882,16 +902,7 @@ void GB_reset(GB_gameboy_t *gb)
gb->vram_size = 0x2000;
memset(gb->vram, 0, gb->vram_size);
if (gb->rgb_encode_callback) {
gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] =
gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] =
gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA);
gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] =
gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55);
gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] =
gb->rgb_encode_callback(gb, 0, 0, 0);
}
update_dmg_palette(gb);
}
reset_ram(gb);

View File

@ -50,6 +50,17 @@
#error Unable to detect endianess
#endif
typedef struct {
struct {
uint8_t r,g,b;
} colors[5];
} GB_palette_t;
extern const GB_palette_t GB_PALETTE_GREY;
extern const GB_palette_t GB_PALETTE_DMG;
extern const GB_palette_t GB_PALETTE_MGB;
extern const GB_palette_t GB_PALETTE_GBL;
typedef union {
struct {
uint8_t seconds;
@ -61,7 +72,6 @@ typedef union {
uint8_t data[5];
} GB_rtc_time_t;
typedef enum {
// GB_MODEL_DMG_0 = 0x000,
// GB_MODEL_DMG_A = 0x001,
@ -513,6 +523,7 @@ struct GB_gameboy_internal_s {
uint32_t *screen;
uint32_t background_palettes_rgb[0x20];
uint32_t sprite_palettes_rgb[0x20];
const GB_palette_t *dmg_palette;
GB_color_correction_mode_t color_correction_mode;
bool keys[4][GB_KEY_MAX];
@ -696,6 +707,8 @@ void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback)
void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback);
void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback);
void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette);
/* These APIs are used when using internal clock */
void GB_set_serial_transfer_bit_start_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_start_callback_t callback);
void GB_set_serial_transfer_bit_end_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_end_callback_t callback);