Skip to content

Commit ab41d75

Browse files
committed
Add option to load custom palettes. Fix #83
1 parent 01788e9 commit ab41d75

File tree

12 files changed

+218
-17
lines changed

12 files changed

+218
-17
lines changed

platforms/shared/desktop/config.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ void config_read(void)
302302
config_video.scanline_mode = read_int("Video", "ScanlineMode", 0);
303303
config_video.scanline_start = read_int("Video", "ScanlineStart", 11);
304304
config_video.scanline_end = read_int("Video", "ScanlineEnd", 234);
305-
config_video.composite_palette = read_bool("Video", "CompositePalette", false);
305+
config_video.palette = read_int("Video", "Palette", 0);
306306
config_video.fps = read_bool("Video", "FPS", false);
307307
config_video.bilinear = read_bool("Video", "Bilinear", false);
308308
config_video.sprite_limit = read_bool("Video", "SpriteLimit", false);
@@ -555,7 +555,7 @@ void config_write(void)
555555
write_int("Video", "ScanlineMode", config_video.scanline_mode);
556556
write_int("Video", "ScanlineStart", config_video.scanline_start);
557557
write_int("Video", "ScanlineEnd", config_video.scanline_end);
558-
write_bool("Video", "CompositePalette", config_video.composite_palette);
558+
write_int("Video", "Palette", config_video.palette);
559559
write_bool("Video", "FPS", config_video.fps);
560560
write_bool("Video", "Bilinear", config_video.bilinear);
561561
write_bool("Video", "SpriteLimit", config_video.sprite_limit);

platforms/shared/desktop/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct config_Video
8181
int scanline_mode = 0;
8282
int scanline_start = 11;
8383
int scanline_end = 234;
84-
bool composite_palette = false;
84+
int palette = 0;
8585
bool fps = false;
8686
bool bilinear = false;
8787
bool sprite_limit = false;

platforms/shared/desktop/emu.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,14 @@ void emu_debug_set_callback(GeargrafxCore::GG_Debug_Callback callback)
432432
geargrafx->SetDebugCallback(callback);
433433
}
434434

435-
void emu_set_composite_palette(bool enabled)
435+
void emu_set_palette(int palette)
436436
{
437-
geargrafx->GetHuC6260()->SetCompositePalette(enabled);
437+
geargrafx->GetHuC6260()->SetPalette(palette);
438+
}
439+
440+
void emu_set_custom_palette(const u8* data)
441+
{
442+
geargrafx->GetHuC6260()->SetCustomPalette(data);
438443
}
439444

440445
void emu_video_no_sprite_limit(bool enabled)

platforms/shared/desktop/emu.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ EXTERN void emu_debug_step_frame(void);
9797
EXTERN void emu_debug_break(void);
9898
EXTERN void emu_debug_continue(void);
9999
EXTERN void emu_debug_set_callback(GeargrafxCore::GG_Debug_Callback callback);
100-
EXTERN void emu_set_composite_palette(bool enabled);
100+
EXTERN void emu_set_palette(int palette);
101+
EXTERN void emu_set_custom_palette(const u8* data);
101102
EXTERN void emu_video_no_sprite_limit(bool enabled);
102103
EXTERN void emu_set_overscan(int overscan);
103104
EXTERN void emu_set_scanline_start_end(int start, int end);

platforms/shared/desktop/gui.cpp

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ static void push_recent_rom(std::string path);
5454
static void show_status_message(void);
5555
static void show_error_window(void);
5656
static void set_style(void);
57+
static void load_custom_palette_from_settings(void);
5758
static ImVec4 lerp(const ImVec4& a, const ImVec4& b, float t);
5859

5960
bool gui_init(void)
@@ -109,13 +110,14 @@ bool gui_init(void)
109110
gui_audio_mute_cdrom = false;
110111
gui_audio_mute_psg = false;
111112
gui_audio_mute_adpcm = false;
113+
gui_custom_palette_loaded = false;
112114

113115
emu_audio_mute(!config_audio.enable);
114116
emu_audio_huc6280a(config_audio.huc6280a);
115117
emu_audio_psg_volume(config_audio.psg_volume);
116118
emu_audio_cdrom_volume(config_audio.cdrom_volume);
117119
emu_audio_adpcm_volume(config_audio.adpcm_volume);
118-
emu_set_composite_palette(config_video.composite_palette);
120+
emu_set_palette(config_video.palette);
119121
emu_video_no_sprite_limit(config_video.sprite_limit);
120122
emu_set_overscan(config_debug.debug ? 0 : config_video.overscan);
121123
emu_set_scanline_start_end(
@@ -133,7 +135,7 @@ bool gui_init(void)
133135
emu_set_preload_cdrom(config_emulator.preload_cdrom);
134136
emu_set_backup_ram(config_emulator.backup_ram);
135137
emu_set_mb128_mode((GG_MB128_Mode)config_emulator.mb128_mode);
136-
emu_set_composite_palette(config_video.composite_palette);
138+
emu_set_palette(config_video.palette);
137139
emu_set_turbo_tap(config_input.turbo_tap);
138140
for (int i = 0; i < GG_MAX_GAMEPADS; i++)
139141
{
@@ -164,6 +166,8 @@ bool gui_init(void)
164166
if (strlen(gui_gameexpress_bios_path) > 0)
165167
gui_load_bios(gui_gameexpress_bios_path, false);
166168

169+
load_custom_palette_from_settings();
170+
167171
gui_hes_init();
168172
gui_debug_init();
169173
gui_init_menus();
@@ -337,6 +341,75 @@ void gui_load_bios(const char* path, bool syscard)
337341
gui_action_reset();
338342
}
339343

344+
void gui_load_palette(const char* path)
345+
{
346+
using namespace std;
347+
string fullpath(path);
348+
string filename;
349+
350+
size_t pos = fullpath.find_last_of("/\\");
351+
if (pos != string::npos)
352+
filename = fullpath.substr(pos + 1);
353+
else
354+
filename = fullpath;
355+
356+
ifstream file(path, ios::binary | ios::ate);
357+
if (!file.is_open())
358+
{
359+
std::string message("Error opening palette file:\n");
360+
message += filename;
361+
gui_set_error_message(message.c_str());
362+
return;
363+
}
364+
365+
streamsize size = file.tellg();
366+
if (size != 0x600)
367+
{
368+
file.close();
369+
std::string message("Invalid palette file size:\n");
370+
message += filename;
371+
message += "\n\nPalette files must be exactly 1536 bytes (0x600).";
372+
gui_set_error_message(message.c_str());
373+
return;
374+
}
375+
376+
file.seekg(0, ios::beg);
377+
u8 palette_data[0x600];
378+
if (!file.read(reinterpret_cast<char*>(palette_data), 0x600))
379+
{
380+
file.close();
381+
std::string message("Error reading palette file:\n");
382+
message += filename;
383+
gui_set_error_message(message.c_str());
384+
return;
385+
}
386+
file.close();
387+
388+
emu_set_custom_palette(palette_data);
389+
390+
std::string dest_path = config_root_path;
391+
dest_path += "custom_palette.pal";
392+
393+
ofstream dest_file(dest_path, ios::binary);
394+
if (dest_file.is_open())
395+
{
396+
dest_file.write(reinterpret_cast<const char*>(palette_data), 0x600);
397+
dest_file.close();
398+
}
399+
else
400+
{
401+
Log("Warning: Could not save custom palette to %s", dest_path.c_str());
402+
}
403+
404+
config_video.palette = 2;
405+
emu_set_palette(config_video.palette);
406+
gui_custom_palette_loaded = true;
407+
408+
std::string message("Custom palette loaded: ");
409+
message += filename;
410+
gui_set_status_message(message.c_str(), 3000);
411+
}
412+
340413
void gui_load_rom(const char* path)
341414
{
342415
using namespace std;
@@ -730,6 +803,41 @@ static void set_style(void)
730803
style.Colors[ImGuiCol_TabDimmedSelectedOverline] = lerp(style.Colors[ImGuiCol_TabSelected], style.Colors[ImGuiCol_TitleBg], 0.20f);
731804
}
732805

806+
static void load_custom_palette_from_settings(void)
807+
{
808+
using namespace std;
809+
string palette_path = config_root_path;
810+
palette_path += "custom_palette.pal";
811+
812+
ifstream file(palette_path, ios::binary | ios::ate);
813+
if (!file.is_open())
814+
{
815+
return;
816+
}
817+
818+
streamsize size = file.tellg();
819+
if (size != 0x600)
820+
{
821+
file.close();
822+
Log("Invalid custom palette file size: %s", palette_path.c_str());
823+
return;
824+
}
825+
826+
file.seekg(0, ios::beg);
827+
u8 palette_data[0x600];
828+
if (!file.read(reinterpret_cast<char*>(palette_data), 0x600))
829+
{
830+
file.close();
831+
Log("Error reading custom palette file: %s", palette_path.c_str());
832+
return;
833+
}
834+
file.close();
835+
836+
emu_set_custom_palette(palette_data);
837+
gui_custom_palette_loaded = true;
838+
Log("Custom palette loaded from: %s", palette_path.c_str());
839+
}
840+
733841
static ImVec4 lerp(const ImVec4& a, const ImVec4& b, float t)
734842
{
735843
return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t);

platforms/shared/desktop/gui.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ EXTERN int* gui_configured_button;
101101
EXTERN config_Hotkey* gui_configured_hotkey;
102102
EXTERN bool gui_dialog_in_use;
103103
EXTERN bool gui_shortcut_open_rom;
104+
EXTERN bool gui_custom_palette_loaded;
104105
EXTERN bool gui_audio_mute_cdrom;
105106
EXTERN bool gui_audio_mute_psg;
106107
EXTERN bool gui_audio_mute_adpcm;
@@ -111,6 +112,7 @@ EXTERN void gui_render(void);
111112
EXTERN void gui_shortcut(gui_ShortCutEvent event);
112113
EXTERN void gui_load_rom(const char* path);
113114
EXTERN void gui_load_bios(const char* path, bool syscard);
115+
EXTERN void gui_load_palette(const char* path);
114116
EXTERN void gui_set_status_message(const char* message, u32 milliseconds);
115117
EXTERN void gui_set_error_message(const char* message);
116118

platforms/shared/desktop/gui_filedialogs.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,28 @@ void gui_file_dialog_save_log(void)
471471
}
472472
}
473473

474+
void gui_file_dialog_load_palette(void)
475+
{
476+
nfdchar_t *outPath;
477+
nfdfilteritem_t filterItem[1] = { { "Palette Files", "pal,bin" } };
478+
nfdopendialogu8args_t args = { };
479+
args.filterList = filterItem;
480+
args.filterCount = 1;
481+
args.defaultPath = config_emulator.last_open_path.c_str();
482+
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);
483+
484+
nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
485+
if (result == NFD_OKAY)
486+
{
487+
gui_load_palette(outPath);
488+
NFD_FreePath(outPath);
489+
}
490+
else if (result != NFD_CANCEL)
491+
{
492+
Error("Load Palette Error: %s", NFD_GetError());
493+
}
494+
}
495+
474496
static void file_dialog_set_native_window(SDL_Window* window, nfdwindowhandle_t* native_window)
475497
{
476498
if (!NFD_GetNativeWindowFromSDLWindow(window, native_window))

platforms/shared/desktop/gui_filedialogs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ EXTERN void gui_file_dialog_save_background(int vdc);
4545
EXTERN void gui_file_dialog_save_memory_dump(bool binary);
4646
EXTERN void gui_file_dialog_save_disassembler(bool full);
4747
EXTERN void gui_file_dialog_save_log(void);
48+
EXTERN void gui_file_dialog_load_palette(void);
4849

4950
#undef GUI_FILEDIALOGS_IMPORT
5051
#undef EXTERN

platforms/shared/desktop/gui_menus.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -750,14 +750,46 @@ static void menu_video(void)
750750

751751
ImGui::Separator();
752752

753-
if (ImGui::MenuItem("Disable Sprite Limit", "", &config_video.sprite_limit))
753+
if (ImGui::BeginMenu("Color Palette"))
754754
{
755-
emu_video_no_sprite_limit(config_video.sprite_limit);
755+
ImGui::PushItemWidth(180.0f);
756+
if (ImGui::Combo("##palette", &config_video.palette, "Standard RGB\0Composite RGB\0Custom\0\0"))
757+
{
758+
emu_set_palette(config_video.palette);
759+
}
760+
ImGui::PopItemWidth();
761+
762+
if (ImGui::MenuItem("Load Custom Palette..."))
763+
{
764+
gui_file_dialog_load_palette();
765+
}
766+
if (ImGui::IsItemHovered())
767+
{
768+
ImGui::BeginTooltip();
769+
ImGui::Text("Format: 512 RGB entries (R, G, B)");
770+
ImGui::Text("Size: 1536 bytes (0x600)");
771+
ImGui::Text("Extensions: .pal, .bin");
772+
ImGui::EndTooltip();
773+
}
774+
775+
ImGui::Separator();
776+
777+
if (gui_custom_palette_loaded)
778+
{
779+
ImGui::TextColored(ImVec4(0.10f, 0.90f, 0.10f, 1.0f), "Custom palette loaded");
780+
}
781+
else
782+
{
783+
ImGui::TextColored(ImVec4(0.50f, 0.50f, 0.50f, 1.0f), "No custom palette loaded");
784+
}
785+
ImGui::EndMenu();
756786
}
757787

758-
if (ImGui::MenuItem("Composite Colors", "", &config_video.composite_palette))
788+
ImGui::Separator();
789+
790+
if (ImGui::MenuItem("Disable Sprite Limit", "", &config_video.sprite_limit))
759791
{
760-
emu_set_composite_palette(config_video.composite_palette);
792+
emu_video_no_sprite_limit(config_video.sprite_limit);
761793
}
762794

763795
ImGui::MenuItem("Bilinear Filtering", "", &config_video.bilinear);

src/huc6260.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,18 @@ void HuC6260::InitPalettes()
6666
m_rgba888_palette[0][i][2] = blue;
6767
m_rgba888_palette[0][i][3] = 255;
6868

69+
// Custom palette defaults to standard RGB
70+
m_rgba888_palette[2][i][0] = red;
71+
m_rgba888_palette[2][i][1] = green;
72+
m_rgba888_palette[2][i][2] = blue;
73+
m_rgba888_palette[2][i][3] = 255;
74+
6975
green = ((i >> 6) & 0x07) * 63 / 7;
7076
red = ((i >> 3) & 0x07) * 31 / 7;
7177
blue = (i & 0x07) * 31 / 7;
7278
u16 rgb565 = (red << 11) | (green << 5) | blue;
7379
m_rgb565_palette[0][i] = rgb565;
80+
m_rgb565_palette[2][i] = rgb565;
7481

7582
m_rgba888_palette[1][i][0] = k_rgb888_palette_composite[i][0];
7683
m_rgba888_palette[1][i][1] = k_rgb888_palette_composite[i][1];
@@ -288,6 +295,27 @@ void HuC6260::AdjustForMultipleDividers()
288295
memcpy(m_frame_buffer, m_scale_buffer, dominant_width * 242 * bytes_per_pixel);
289296
}
290297

298+
void HuC6260::SetCustomPalette(const u8* data)
299+
{
300+
for (int i = 0; i < 512; i++)
301+
{
302+
u8 red = data[i * 3];
303+
u8 green = data[i * 3 + 1];
304+
u8 blue = data[i * 3 + 2];
305+
306+
m_rgba888_palette[2][i][0] = red;
307+
m_rgba888_palette[2][i][1] = green;
308+
m_rgba888_palette[2][i][2] = blue;
309+
m_rgba888_palette[2][i][3] = 255;
310+
311+
u8 green565 = green * 63 / 255;
312+
u8 red565 = red * 31 / 255;
313+
u8 blue565 = blue * 31 / 255;
314+
u16 rgb565 = (red565 << 11) | (green565 << 5) | blue565;
315+
m_rgb565_palette[2][i] = rgb565;
316+
}
317+
}
318+
291319
void HuC6260::SaveState(std::ostream& stream)
292320
{
293321
using namespace std;

0 commit comments

Comments
 (0)