diff --git a/Core/display.c b/Core/display.c index d5a29b862..b250707ac 100644 --- a/Core/display.c +++ b/Core/display.c @@ -5,6 +5,58 @@ #include #include "gb.h" +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}}}; + +void GB_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->object_palettes_rgb[4] = gb->object_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->object_palettes_rgb[5] = gb->object_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->object_palettes_rgb[6] = gb->object_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->object_palettes_rgb[7] = gb->object_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; + GB_update_dmg_palette(gb); +} + +const GB_palette_t *GB_get_palette(GB_gameboy_t *gb) +{ + return gb->dmg_palette; +} + +void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback) +{ + gb->vblank_callback = callback; +} + +void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback) +{ + + gb->rgb_encode_callback = callback; + GB_update_dmg_palette(gb); + + for (unsigned i = 0; i < 32; i++) { + GB_palette_changed(gb, true, i * 2); + GB_palette_changed(gb, false, i * 2); + } +} + /* FIFO functions */ static inline unsigned fifo_size(GB_fifo_t *fifo) diff --git a/Core/display.h b/Core/display.h index 6ec55bce3..7980961dd 100644 --- a/Core/display.h +++ b/Core/display.h @@ -4,6 +4,17 @@ #include #include +typedef struct { + struct GB_color_s { + 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 enum { GB_VBLANK_TYPE_NORMAL_FRAME, // An actual Vblank-triggered frame GB_VBLANK_TYPE_LCD_OFF, // An artificial frame pushed while the LCD was off @@ -11,6 +22,23 @@ typedef enum { GB_VBLANK_TYPE_REPEAT, // A frame that would not render on actual hardware, but the screen should retain the previous frame } GB_vblank_type_t; +typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb, GB_vblank_type_t type); +typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b); + +typedef struct { + uint8_t pixel; // Color, 0-3 + uint8_t palette; // Palette, 0 - 7 (CGB); 0-1 in DMG (or just 0 for BG) + uint8_t priority; // Object priority – 0 in DMG, OAM index in CGB + bool bg_priority; // For object FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit +} GB_fifo_item_t; + +#define GB_FIFO_LENGTH 8 +typedef struct { + GB_fifo_item_t fifo[GB_FIFO_LENGTH]; + uint8_t read_end; + uint8_t size; +} GB_fifo_t; + #ifdef GB_INTERNAL internal void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force); internal void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index); @@ -18,13 +46,13 @@ internal void GB_STAT_update(GB_gameboy_t *gb); internal void GB_lcd_off(GB_gameboy_t *gb); internal void GB_display_vblank(GB_gameboy_t *gb, GB_vblank_type_t type); internal void GB_update_wx_glitch(GB_gameboy_t *gb); +internal void GB_update_dmg_palette(GB_gameboy_t *gb); #define GB_display_sync(gb) GB_display_run(gb, 0, true) enum { GB_OBJECT_PRIORITY_X, GB_OBJECT_PRIORITY_INDEX, }; - #endif typedef enum { @@ -66,13 +94,19 @@ typedef enum { static const GB_color_correction_mode_t __attribute__((deprecated("Use GB_COLOR_CORRECTION_MODERN_BALANCED instead"))) GB_COLOR_CORRECTION_EMULATE_HARDWARE = GB_COLOR_CORRECTION_MODERN_BALANCED; static const GB_color_correction_mode_t __attribute__((deprecated("Use GB_COLOR_CORRECTION_MODERN_BOOST_CONTRAST instead"))) GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS = GB_COLOR_CORRECTION_MODERN_BOOST_CONTRAST; -void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index); -void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type); -uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *object_height); -uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border); +void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback); +void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback); +void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette); +const GB_palette_t *GB_get_palette(GB_gameboy_t *gb); void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode); void GB_set_light_temperature(GB_gameboy_t *gb, double temperature); + bool GB_is_odd_frame(GB_gameboy_t *gb); +uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border); + +void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index); +void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type); +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *object_height); void GB_set_object_rendering_disabled(GB_gameboy_t *gb, bool disabled); void GB_set_background_rendering_disabled(GB_gameboy_t *gb, bool disabled); diff --git a/Core/gb.c b/Core/gb.c index 9e9ca4959..f5360e667 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -1245,11 +1245,6 @@ uint32_t *GB_get_pixels_output(GB_gameboy_t *gb) return gb->screen; } -void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback) -{ - gb->vblank_callback = callback; -} - void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback) { gb->log_callback = callback; @@ -1292,53 +1287,6 @@ void GB_set_lcd_status_callback(GB_gameboy_t *gb, GB_lcd_status_callback_t callb gb->lcd_status_callback = callback; } -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->object_palettes_rgb[4] = gb->object_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->object_palettes_rgb[5] = gb->object_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->object_palettes_rgb[6] = gb->object_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->object_palettes_rgb[7] = gb->object_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); -} - -const GB_palette_t *GB_get_palette(GB_gameboy_t *gb) -{ - return gb->dmg_palette; -} - -void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback) -{ - - gb->rgb_encode_callback = callback; - update_dmg_palette(gb); - - for (unsigned i = 0; i < 32; i++) { - GB_palette_changed(gb, true, i * 2); - GB_palette_changed(gb, false, i * 2); - } -} - void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback) { gb->infrared_callback = callback; @@ -1747,9 +1695,8 @@ static void GB_reset_internal(GB_gameboy_t *gb, bool quick) gb->ram_size = 0x2000; gb->vram_size = 0x2000; memset(gb->vram, 0, gb->vram_size); - gb->object_priority = GB_OBJECT_PRIORITY_X; - - update_dmg_palette(gb); + gb->object_priority = GB_OBJECT_PRIORITY_X; + GB_update_dmg_palette(gb); } gb->serial_mask = 0x80; diff --git a/Core/gb.h b/Core/gb.h index 1827508e7..960899ccc 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -66,17 +66,6 @@ extern "C" { l, h #endif -typedef struct { - struct GB_color_s { - 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; @@ -276,11 +265,9 @@ typedef enum { #endif -typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb, GB_vblank_type_t type); typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes); typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb); typedef void (*GB_debugger_reload_callback_t)(GB_gameboy_t *gb); -typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b); typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on); typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, double rumble_amplitude); typedef void (*GB_serial_transfer_bit_start_callback_t)(GB_gameboy_t *gb, bool bit_to_send); @@ -299,20 +286,6 @@ typedef void (*GB_lcd_status_callback_t)(GB_gameboy_t *gb, bool on); struct GB_breakpoint_s; struct GB_watchpoint_s; -typedef struct { - uint8_t pixel; // Color, 0-3 - uint8_t palette; // Palette, 0 - 7 (CGB); 0-1 in DMG (or just 0 for BG) - uint8_t priority; // Object priority – 0 in DMG, OAM index in CGB - bool bg_priority; // For object FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit -} GB_fifo_item_t; - -#define GB_FIFO_LENGTH 8 -typedef struct { - GB_fifo_item_t fifo[GB_FIFO_LENGTH]; - uint8_t read_end; - uint8_t size; -} GB_fifo_t; - typedef struct { uint32_t magic; uint8_t track_count; @@ -970,12 +943,10 @@ void GB_set_border_mode(GB_gameboy_t *gb, GB_border_mode_t border_mode); void GB_set_infrared_input(GB_gameboy_t *gb, bool state); -void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback); void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback); void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback); void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback); void GB_set_debugger_reload_callback(GB_gameboy_t *gb, GB_debugger_reload_callback_t callback); -void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback); 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); @@ -986,9 +957,6 @@ void GB_set_execution_callback(GB_gameboy_t *gb, GB_execution_callback_t callbac void GB_set_lcd_line_callback(GB_gameboy_t *gb, GB_lcd_line_callback_t callback); void GB_set_lcd_status_callback(GB_gameboy_t *gb, GB_lcd_status_callback_t callback); -void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette); -const GB_palette_t *GB_get_palette(GB_gameboy_t *gb); - /* 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); diff --git a/Core/random.h b/Core/random.h index 6bdacee11..28676f0da 100644 --- a/Core/random.h +++ b/Core/random.h @@ -2,8 +2,11 @@ #include #include +#include "defs.h" -uint8_t GB_random(void); -uint32_t GB_random32(void); +#ifdef GB_INTERNAL +internal uint8_t GB_random(void); +internal uint32_t GB_random32(void); +#endif void GB_random_seed(uint64_t seed); void GB_random_set_enabled(bool enable);