diff --git a/Makefile b/Makefile index 9b2114a..a01cbc2 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ endif cocoa: $(BIN)/SameBoy.app quicklook: $(BIN)/SameBoy.qlgenerator -sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/mgb_boot.bin $(BIN)/SDL/cgb0_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders +sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/mgb_boot.bin $(BIN)/SDL/cgb0_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders $(BIN)/SDL/Palettes bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/cgb0_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/mgb_boot.bin $(BIN)/BootROMs/sgb_boot.bin $(BIN)/BootROMs/sgb2_boot.bin tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin $(BIN)/tester/sgb2_boot.bin all: cocoa sdl tester libretro @@ -424,6 +424,10 @@ $(BIN)/SDL/background.bmp: SDL/background.bmp $(BIN)/SDL/Shaders: Shaders -@$(MKDIR) -p $@ cp -rf Shaders/*.fsh $@ + +$(BIN)/SDL/Palettes: Misc/Palettes + -@$(MKDIR) -p $@ + cp -rf Misc/Palettes/*.sbp $@ # Boot ROMs diff --git a/Misc/Palettes/Desert.sbp b/Misc/Palettes/Desert.sbp new file mode 100644 index 0000000..28625ad Binary files /dev/null and b/Misc/Palettes/Desert.sbp differ diff --git a/Misc/Palettes/Evening.sbp b/Misc/Palettes/Evening.sbp new file mode 100644 index 0000000..e11998a --- /dev/null +++ b/Misc/Palettes/Evening.sbp @@ -0,0 +1 @@ +LPBS&6UiS˜‰®ä¦»î©Îõ}ù^¬ÕLŸìH+ \ No newline at end of file diff --git a/Misc/Palettes/Fog.sbp b/Misc/Palettes/Fog.sbp new file mode 100644 index 0000000..a79fe00 Binary files /dev/null and b/Misc/Palettes/Fog.sbp differ diff --git a/Misc/Palettes/Magic Eggplant.sbp b/Misc/Palettes/Magic Eggplant.sbp new file mode 100644 index 0000000..6bd5929 Binary files /dev/null and b/Misc/Palettes/Magic Eggplant.sbp differ diff --git a/Misc/Palettes/Radioactive Pea.sbp b/Misc/Palettes/Radioactive Pea.sbp new file mode 100644 index 0000000..57f9d6a Binary files /dev/null and b/Misc/Palettes/Radioactive Pea.sbp differ diff --git a/Misc/Palettes/Seaweed.sbp b/Misc/Palettes/Seaweed.sbp new file mode 100644 index 0000000..3718efd Binary files /dev/null and b/Misc/Palettes/Seaweed.sbp differ diff --git a/Misc/Palettes/Twilight.sbp b/Misc/Palettes/Twilight.sbp new file mode 100644 index 0000000..a5decc1 Binary files /dev/null and b/Misc/Palettes/Twilight.sbp differ diff --git a/SDL/configuration.h b/SDL/configuration.h index 4ddd6a4..b8bdfbd 100644 --- a/SDL/configuration.h +++ b/SDL/configuration.h @@ -98,6 +98,7 @@ typedef struct { /* v0.15.2 */ bool allow_background_controllers; bool gui_pallete_enabled; // Change the GUI palette only once the user changed the DMG palette + char dmg_palette_name[25]; }; } configuration_t; diff --git a/SDL/gui.c b/SDL/gui.c index 737ceec..c02ae76 100644 --- a/SDL/gui.c +++ b/SDL/gui.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "utils.h" #include "gui.h" #include "font.h" @@ -21,6 +22,9 @@ enum pending_command pending_command; unsigned command_parameter; char *dropped_state_file = NULL; +static char **custom_palettes; +static unsigned n_custom_palettes; + #ifdef __APPLE__ #define MODIFIER_NAME " " CMD_STRING @@ -561,6 +565,9 @@ const char *current_color_temperature(unsigned index) const char *current_palette(unsigned index) { + if (configuration.dmg_palette == 4) { + return configuration.dmg_palette_name; + } return (const char *[]){"Greyscale", "Lime (Game Boy)", "Olive (Pocket)", "Teal (Light)"} [configuration.dmg_palette]; } @@ -653,25 +660,45 @@ static void increase_color_temperature(unsigned index) } } +const GB_palette_t *current_dmg_palette(void) +{ + typedef struct __attribute__ ((packed)) { + uint32_t magic; + uint8_t flags; + struct GB_color_s colors[5]; + int32_t brightness_bias; + uint32_t hue_bias; + uint32_t hue_bias_strength; + } theme_t; + + static theme_t theme; + + if (configuration.dmg_palette == 4) { + char *path = resource_path("Palettes"); + sprintf(path + strlen(path), "/%s.sbp", configuration.dmg_palette_name); + FILE *file = fopen(path, "rb"); + if (!file) return &GB_PALETTE_GREY; + memset(&theme, 0, sizeof(theme)); + fread(&theme, sizeof(theme), 1, file); + fclose(file); +#ifdef GB_BIG_ENDIAN + theme.magic = __builtin_bswap32(theme.magic); +#endif + if (theme.magic != 'SBPL') return &GB_PALETTE_GREY; + return (GB_palette_t *)&theme.colors; + } + + switch (configuration.dmg_palette) { + case 1: return &GB_PALETTE_DMG; + case 2: return &GB_PALETTE_MGB; + case 3: return &GB_PALETTE_GBL; + default: return &GB_PALETTE_GREY; + } +} + static void update_gui_palette(void) { - const GB_palette_t *palette; - switch (configuration.dmg_palette) { - case 1: - palette = &GB_PALETTE_DMG; - break; - - case 2: - palette = &GB_PALETTE_MGB; - break; - - case 3: - palette = &GB_PALETTE_GBL; - break; - - default: - palette = &GB_PALETTE_GREY; - } + const GB_palette_t *palette = current_dmg_palette(); SDL_Color colors[4]; for (unsigned i = 4; i--; ) { @@ -695,7 +722,26 @@ static void update_gui_palette(void) static void cycle_palette(unsigned index) { if (configuration.dmg_palette == 3) { - configuration.dmg_palette = 0; + if (n_custom_palettes == 0) { + configuration.dmg_palette = 0; + } + else { + configuration.dmg_palette = 4; + strcpy(configuration.dmg_palette_name, custom_palettes[0]); + } + } + else if (configuration.dmg_palette == 4) { + for (unsigned i = 0; i < n_custom_palettes; i++) { + if (strcmp(custom_palettes[i], configuration.dmg_palette_name) == 0) { + if (i == n_custom_palettes - 1) { + configuration.dmg_palette = 0; + } + else { + strcpy(configuration.dmg_palette_name, custom_palettes[i + 1]); + } + break; + } + } } else { configuration.dmg_palette++; @@ -707,7 +753,26 @@ static void cycle_palette(unsigned index) static void cycle_palette_backwards(unsigned index) { if (configuration.dmg_palette == 0) { - configuration.dmg_palette = 3; + if (n_custom_palettes == 0) { + configuration.dmg_palette = 3; + } + else { + configuration.dmg_palette = 4; + strcpy(configuration.dmg_palette_name, custom_palettes[n_custom_palettes - 1]); + } + } + else if (configuration.dmg_palette == 4) { + for (unsigned i = 0; i < n_custom_palettes; i++) { + if (strcmp(custom_palettes[i], configuration.dmg_palette_name) == 0) { + if (i == 0) { + configuration.dmg_palette = 3; + } + else { + strcpy(configuration.dmg_palette_name, custom_palettes[i - 1]); + } + break; + } + } } else { configuration.dmg_palette--; @@ -1896,3 +1961,31 @@ void run_gui(bool is_running) } } } + +static void __attribute__ ((constructor)) list_custom_palettes(void) +{ + char *path = resource_path("Palettes"); + if (!path) return; + if (strlen(path) > 1024 - 30) { + // path too long to safely concat filenames + return; + } + DIR *dir = opendir(path); + if (!dir) return; + + struct dirent *ent; + + while ((ent = readdir(dir))) { + unsigned length = strlen(ent->d_name); + if (length < 5 || length > 28) { + continue; + } + if (strcmp(ent->d_name + length - 4, ".sbp")) continue; + ent->d_name[length - 4] = 0; + custom_palettes = realloc(custom_palettes, + sizeof(custom_palettes[0]) * (n_custom_palettes + 1)); + custom_palettes[n_custom_palettes++] = strdup(ent->d_name); + } + + closedir(dir); +} diff --git a/SDL/gui.h b/SDL/gui.h index f23ebd8..835794a 100644 --- a/SDL/gui.h +++ b/SDL/gui.h @@ -64,5 +64,6 @@ extern const char *osd_text; extern unsigned osd_countdown; extern unsigned osd_text_lines; void convert_mouse_coordinates(signed *x, signed *y); +const GB_palette_t *current_dmg_palette(void); #endif diff --git a/SDL/main.c b/SDL/main.c index 5ad3f40..2834ae3 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -161,22 +161,7 @@ static const char *end_capturing_logs(bool show_popup, bool should_exit, uint32_ static void update_palette(void) { - switch (configuration.dmg_palette) { - 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); - } + GB_set_palette(&gb, current_dmg_palette()); } static void screen_size_changed(void) @@ -866,7 +851,7 @@ int main(int argc, char **argv) configuration.highpass_mode %= GB_HIGHPASS_MAX; configuration.model %= MODEL_MAX; configuration.sgb_revision %= SGB_MAX; - configuration.dmg_palette %= 4; + configuration.dmg_palette %= 5; if (configuration.dmg_palette) { configuration.gui_pallete_enabled = true; } @@ -876,6 +861,7 @@ int main(int argc, char **argv) configuration.bootrom_path[sizeof(configuration.bootrom_path) - 1] = 0; configuration.cgb_revision %= GB_MODEL_CGB_E - GB_MODEL_CGB_0 + 1; configuration.audio_driver[15] = 0; + configuration.dmg_palette_name[24] = 0; } if (configuration.model >= MODEL_MAX) { diff --git a/Windows/dirent.c b/Windows/dirent.c new file mode 100755 index 0000000..f5fd8b3 --- /dev/null +++ b/Windows/dirent.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include "dirent.h" + +DIR *opendir(const char *filename) +{ + wchar_t w_filename[MAX_PATH + 3] = {0,}; + unsigned length = MultiByteToWideChar(CP_UTF8, 0, filename, -1, w_filename, MAX_PATH); + if (length) { + w_filename[length - 1] = L'/'; + w_filename[length] = L'*'; + w_filename[length + 1] = 0; + } + DIR *ret = malloc(sizeof(*ret)); + ret->handle = FindFirstFileW(w_filename, &ret->entry); + if (ret->handle == INVALID_HANDLE_VALUE) { + free(ret); + return NULL; + } + + return ret; +} + +int closedir(DIR *dir) +{ + if (dir->handle != INVALID_HANDLE_VALUE) { + FindClose(dir->handle); + } + free(dir); + return 0; +} + +struct dirent *readdir(DIR *dir) +{ + if (dir->handle == INVALID_HANDLE_VALUE) { + return NULL; + } + + WideCharToMultiByte(CP_UTF8, 0, dir->entry.cFileName, -1, + dir->out_entry.d_name, sizeof(dir->out_entry.d_name), + NULL, NULL); + + if (!FindNextFileW(dir->handle, &dir->entry)) { + FindClose(dir->handle); + dir->handle = INVALID_HANDLE_VALUE; + } + + return &dir->out_entry; +} diff --git a/Windows/dirent.h b/Windows/dirent.h new file mode 100755 index 0000000..7102995 --- /dev/null +++ b/Windows/dirent.h @@ -0,0 +1,15 @@ +#include + +struct dirent { + char d_name[MAX_PATH + 1]; +}; + +typedef struct { + HANDLE handle; + WIN32_FIND_DATAW entry; + struct dirent out_entry; +} DIR; + +DIR *opendir(const char *filename); +int closedir(DIR *dir); +struct dirent *readdir(DIR *dir);