yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
palette_editor_widget.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <map>
5
6#include "absl/strings/str_format.h"
13#include "util/log.h"
14
15#include <string>
16#include <vector>
17
18namespace yaze {
19namespace gui {
20
21namespace {
22
23const char* RomPaletteGroupNameGetter(void* user_data, int idx) {
24 auto* names = static_cast<std::vector<std::string>*>(user_data);
25 if (!names || idx < 0 || idx >= static_cast<int>(names->size())) {
26 return nullptr;
27 }
28 return (*names)[idx].c_str();
29}
30
31} // namespace
32
33// Merged implementation from PaletteWidget and PaletteEditorWidget
34
36 game_data_ = game_data;
37 rom_ = nullptr;
39 if (game_data_) {
41 }
44}
45
47 rom_ = rom;
48 game_data_ = nullptr;
50 // Legacy mode - no palette loading without game_data
53}
54
55// --- Embedded Draw Method (from simple editor) ---
57 if (!game_data_) {
58 ImGui::TextColored(ImVec4(1, 0, 0, 1), "GameData not loaded");
59 return;
60 }
61
62 ImGui::BeginGroup();
63
65 ImGui::Separator();
66
67 auto& dungeon_pal_group = game_data_->palette_groups.dungeon_main;
68 if (dungeon_pal_group.empty()) {
69 ImGui::TextDisabled("Dungeon palettes unavailable");
70 ImGui::EndGroup();
71 return;
72 }
73
75 std::clamp(current_palette_id_, 0,
76 static_cast<int>(dungeon_pal_group.size()) - 1);
77 if (current_palette_id_ >= 0 &&
78 current_palette_id_ < (int)dungeon_pal_group.size()) {
79 auto palette = dungeon_pal_group[current_palette_id_];
82 } else {
83 DrawPaletteGrid(palette, 15);
84 dungeon_pal_group[current_palette_id_] = palette;
85 }
86 }
87
88 ImGui::Separator();
89
90 if (selected_color_index_ >= 0) {
93 } else {
95 }
96 } else {
97 ImGui::TextDisabled("Select a color to edit");
98 }
99
100 ImGui::EndGroup();
101}
102
104 if (!game_data_)
105 return;
106 auto& dungeon_pal_group = game_data_->palette_groups.dungeon_main;
107 int num_palettes = dungeon_pal_group.size();
108 if (num_palettes <= 0) {
109 ImGui::TextDisabled("No dungeon palettes");
110 return;
111 }
112
113 current_palette_id_ = std::clamp(current_palette_id_, 0, num_palettes - 1);
114
115 ImGui::Text("Dungeon Palette:");
116 ImGui::SameLine();
117 ImGui::SetNextItemWidth(std::min(180.0f, ImGui::GetContentRegionAvail().x));
118
119 if (ImGui::BeginCombo(
120 "##PaletteSelect",
121 absl::StrFormat("Palette %d", current_palette_id_).c_str())) {
122 for (int i = 0; i < num_palettes; i++) {
123 bool is_selected = (current_palette_id_ == i);
124 if (ImGui::Selectable(absl::StrFormat("Palette %d", i).c_str(),
125 is_selected)) {
128 }
129 if (is_selected) {
130 ImGui::SetItemDefaultFocus();
131 }
132 }
133 ImGui::EndCombo();
134 }
135}
136
138 if (!game_data_)
139 return;
140 auto& dungeon_pal_group = game_data_->palette_groups.dungeon_main;
141 if (dungeon_pal_group.empty()) {
142 return;
143 }
145 static_cast<int>(dungeon_pal_group.size()) - 1);
146 ImGui::SeparatorText(
147 absl::StrFormat("Edit Color %d", selected_color_index_).c_str());
148
149 auto palette = dungeon_pal_group[current_palette_id_];
150 if (selected_color_index_ < 0 ||
151 selected_color_index_ >= static_cast<int>(palette.size())) {
153 return;
154 }
155 auto original_color = palette[selected_color_index_];
156
157 // Use standardized SnesColorEdit4 for consistency
159 "Color", &palette[selected_color_index_],
160 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_PickerHueWheel)) {
161 // Update the palette group with the modified palette
162 dungeon_pal_group[current_palette_id_] = palette;
163
164 // Update editing_color_ to match (for consistency with other parts of the
165 // widget)
168
171 }
172 }
173
174 ImGui::Text("RGB (0-255): (%d, %d, %d)",
175 static_cast<int>(editing_color_.x * 255),
176 static_cast<int>(editing_color_.y * 255),
177 static_cast<int>(editing_color_.z * 255));
178 ImGui::Text("SNES BGR555: 0x%04X", original_color.snes());
179
180 if (gui::ThemedButton("Reset to Original")) {
182 ImVec4(original_color.rgb().x / 255.0f, original_color.rgb().y / 255.0f,
183 original_color.rgb().z / 255.0f, 1.0f);
184 // Also reset the actual palette color
185 palette[selected_color_index_] = original_color;
186 dungeon_pal_group[current_palette_id_] = palette;
189 }
190 }
191}
192
194 gfx::SnesPalette** palette, int* color_index, std::string* source_label) {
195 if (!game_data_ || !palette || !color_index || selected_color_index_ < 0) {
196 return false;
197 }
198
199 const int display_index = selected_color_index_;
200 if (display_index < 32) {
202 return false;
203 }
205 *color_index = display_index;
206 if (source_label) {
207 *source_label = "HUD / floor-ceiling";
208 }
209 return true;
210 }
211
212 const int local_index = display_index - 32;
213 const int row = local_index / 16;
214 const int col = local_index % 16;
215 if (row < 0 || row >= 6 || col == 0) {
216 return false;
217 }
218
219 auto& dungeon_pal_group = game_data_->palette_groups.dungeon_main;
220 if (dungeon_pal_group.empty() || current_palette_id_ < 0 ||
221 current_palette_id_ >= static_cast<int>(dungeon_pal_group.size())) {
222 return false;
223 }
224
225 *palette = dungeon_pal_group.mutable_palette(current_palette_id_);
226 *color_index = row * 15 + (col - 1);
227 if (source_label) {
228 *source_label = absl::StrFormat("Dungeon row %d", row + 2);
229 }
230 return true;
231}
232
234 ImGui::TextDisabled(
235 "Rows 0-1: HUD / floor / ceiling | Rows 2-7: Dungeon main");
236 const float swatch_size = ComputeSwatchSize(/*columns=*/16, 14.0f, 28.0f);
237
238 gfx::SnesPalette* dungeon_palette = nullptr;
241 static_cast<int>(game_data_->palette_groups.dungeon_main.size())) {
242 dungeon_palette =
244 }
245
246 gfx::SnesPalette* hud_palette = nullptr;
249 }
250
251 for (int i = 0; i < 128; ++i) {
252 if (i % 16 != 0) {
253 ImGui::SameLine();
254 }
255
256 gfx::SnesColor color(0);
257 bool editable = false;
258 std::string tooltip_label = "Reserved / transparent";
259 int source_index = -1;
260
261 if (i < 32 && hud_palette && i < static_cast<int>(hud_palette->size())) {
262 color = (*hud_palette)[i];
263 editable = true;
264 tooltip_label = "HUD / floor-ceiling";
265 source_index = i;
266 } else if (i >= 32 && dungeon_palette) {
267 const int local_index = i - 32;
268 const int row = local_index / 16;
269 const int col = local_index % 16;
270 if (row < 6 && col > 0) {
271 source_index = row * 15 + (col - 1);
272 if (source_index < static_cast<int>(dungeon_palette->size())) {
273 color = (*dungeon_palette)[source_index];
274 editable = true;
275 tooltip_label = absl::StrFormat("Dungeon row %d", row + 2);
276 }
277 }
278 }
279
280 ImVec4 display_color = color.rgb();
281 ImGui::PushID(i);
282 if (!editable) {
283 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
284 }
285 const bool clicked =
286 ImGui::ColorButton("##render_color", display_color,
287 ImGuiColorEditFlags_NoTooltip,
288 ImVec2(swatch_size, swatch_size));
289 if (!editable) {
290 ImGui::PopStyleVar();
291 }
292
293 if (clicked && editable) {
296 temp_color_ = display_color;
297 editing_color_ = display_color;
298 }
299
300 if (ImGui::IsItemHovered()) {
301 if (editable) {
302 ImGui::SetTooltip("%s\nSlot %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)",
303 tooltip_label.c_str(), source_index, color.snes(),
304 static_cast<int>(display_color.x * 255),
305 static_cast<int>(display_color.y * 255),
306 static_cast<int>(display_color.z * 255));
307 } else {
308 ImGui::SetTooltip("%s", tooltip_label.c_str());
309 }
310 }
311 ImGui::PopID();
312 }
313}
314
315float PaletteEditorWidget::ComputeSwatchSize(int columns, float min_size,
316 float max_size) const {
317 const float available_width = std::max(ImGui::GetContentRegionAvail().x, 1.0f);
318 const float spacing =
319 std::max(ImGui::GetStyle().ItemSpacing.x, 2.0f) * (columns - 1);
320 const float raw = (available_width - spacing) / std::max(columns, 1);
321 return std::clamp(raw, min_size, max_size);
322}
323
325 gfx::SnesPalette* palette = nullptr;
326 int color_index = -1;
327 std::string source_label;
328 if (!ResolveDungeonRenderSelection(&palette, &color_index, &source_label) ||
329 !palette || color_index < 0 ||
330 color_index >= static_cast<int>(palette->size())) {
333 return;
334 }
335
336 ImGui::SeparatorText(
337 absl::StrFormat("%s Color %d", source_label, color_index).c_str());
338
339 auto original_color = (*palette)[color_index];
341 "Color", &(*palette)[color_index],
342 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_PickerHueWheel)) {
343 editing_color_ = gui::ConvertSnesColorToImVec4((*palette)[color_index]);
346 }
347 }
348
349 ImGui::Text("RGB (0-255): (%d, %d, %d)",
350 static_cast<int>(editing_color_.x * 255),
351 static_cast<int>(editing_color_.y * 255),
352 static_cast<int>(editing_color_.z * 255));
353 ImGui::Text("SNES BGR555: 0x%04X", original_color.snes());
354
355 if (gui::ThemedButton("Reset to Original")) {
356 editing_color_ = ImVec4(original_color.rgb().x / 255.0f,
357 original_color.rgb().y / 255.0f,
358 original_color.rgb().z / 255.0f, 1.0f);
359 (*palette)[color_index] = original_color;
362 }
363 }
364}
365
366// --- Modal/Popup Methods (from feature-rich widget) ---
367
369 const std::string& title) {
370 if (ImGui::BeginPopupModal(title.c_str(), nullptr,
371 ImGuiWindowFlags_AlwaysAutoResize)) {
372 ImGui::Text("Enhanced Palette Editor");
373 ImGui::Separator();
374
375 DrawPaletteGrid(palette);
376 ImGui::Separator();
377
378 if (ImGui::CollapsingHeader("Palette Analysis")) {
379 DrawPaletteAnalysis(palette);
380 }
381
382 if (ImGui::CollapsingHeader("ROM Palette Manager") && rom_) {
384
385 if (gui::PrimaryButton("Apply ROM Palette") && !rom_palette_groups_.empty()) {
387 static_cast<int>(rom_palette_groups_.size())) {
389 }
390 }
391 }
392
393 ImGui::Separator();
394
395 if (gui::ThemedButton("Save Backup")) {
396 SavePaletteBackup(palette);
397 }
398 ImGui::SameLine();
399 if (gui::ThemedButton("Restore Backup")) {
400 RestorePaletteBackup(palette);
401 }
402 ImGui::SameLine();
403 if (gui::ThemedButton("Close")) {
404 ImGui::CloseCurrentPopup();
405 }
406
407 ImGui::EndPopup();
408 }
409}
410
413 return;
414
415 if (ImGui::Begin("ROM Palette Manager", &show_rom_manager_)) {
416 if (!rom_) {
417 ImGui::Text("No ROM loaded");
418 ImGui::End();
419 return;
420 }
421
424 }
425
427
428 if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
429 ImGui::Separator();
430 ImGui::Text("Preview of %s:",
432
433 const auto& preview_palette = rom_palette_groups_[current_group_index_];
434 DrawPaletteGrid(const_cast<gfx::SnesPalette&>(preview_palette));
435 DrawPaletteAnalysis(preview_palette);
436 }
437 }
438 ImGui::End();
439}
440
442 const std::string& title) {
444 return;
445
446 if (ImGui::Begin(title.c_str(), &show_color_analysis_)) {
447 ImGui::Text("Bitmap Color Analysis");
448 ImGui::Separator();
449
450 if (!bitmap.is_active()) {
451 ImGui::Text("Bitmap is not active");
452 ImGui::End();
453 return;
454 }
455
456 std::map<uint8_t, int> pixel_counts;
457 const auto& data = bitmap.vector();
458
459 for (uint8_t pixel : data) {
460 uint8_t palette_index = pixel & 0x0F;
461 pixel_counts[palette_index]++;
462 }
463
464 ImGui::Text("Bitmap Size: %d x %d (%zu pixels)", bitmap.width(),
465 bitmap.height(), data.size());
466
467 ImGui::Separator();
468 ImGui::Text("Pixel Distribution:");
469
470 int total_pixels = static_cast<int>(data.size());
471 plotting::PlotStyleScope plot_style(
472 gui::ThemeManager::Get().GetCurrentTheme());
473 plotting::PlotConfig plot_cfg{.id = "Pixel Distribution",
474 .x_label = "Palette Index",
475 .y_label = "Count",
476 .flags = ImPlotFlags_NoBoxSelect,
477 .x_axis_flags = ImPlotAxisFlags_AutoFit,
478 .y_axis_flags = ImPlotAxisFlags_AutoFit};
479 std::vector<double> x;
480 std::vector<double> y;
481 x.reserve(pixel_counts.size());
482 y.reserve(pixel_counts.size());
483 for (const auto& [index, count] : pixel_counts) {
484 x.push_back(static_cast<double>(index));
485 y.push_back(static_cast<double>(count));
486 }
487 plotting::PlotGuard plot(plot_cfg);
488 if (plot && !x.empty()) {
489 ImPlot::PlotBars("Usage", x.data(), y.data(), static_cast<int>(x.size()),
490 0.67, 0.0, ImPlotBarsFlags_None);
491 }
492 }
493 ImGui::End();
494}
495
497 int palette_index) {
498 if (!bitmap || !rom_palettes_loaded_ || group_index < 0 ||
499 group_index >= static_cast<int>(rom_palette_groups_.size())) {
500 return false;
501 }
502
503 try {
504 const auto& selected_palette = rom_palette_groups_[group_index];
505 SavePaletteBackup(bitmap->palette());
506
507 if (palette_index >= 0 && palette_index < 8) {
508 bitmap->SetPaletteWithTransparent(selected_palette, palette_index);
509 } else {
510 bitmap->SetPalette(selected_palette);
511 }
512
515
516 current_group_index_ = group_index;
517 current_palette_index_ = palette_index;
518 return true;
519 } catch (const std::exception& e) {
520 return false;
521 }
522}
523
526 current_group_index_ >= static_cast<int>(rom_palette_groups_.size())) {
527 return nullptr;
528 }
530}
531
535
537 if (backup_palette_.size() == 0) {
538 return false;
539 }
540 palette = backup_palette_;
541 return true;
542}
543
544// Unified grid drawing function
546 const float swatch_size =
547 ComputeSwatchSize(cols, /*min_size=*/16.0f, /*max_size=*/30.0f);
548 for (int i = 0; i < static_cast<int>(palette.size()); i++) {
549 if (i % cols != 0)
550 ImGui::SameLine();
551
552 auto color = palette[i];
553 ImVec4 display_color = color.rgb();
554
555 ImGui::PushID(i);
556 if (ImGui::ColorButton("##color", display_color,
557 ImGuiColorEditFlags_NoTooltip,
558 ImVec2(swatch_size, swatch_size))) {
561 temp_color_ = display_color;
562 editing_color_ = display_color;
563 }
564
565 if (ImGui::BeginPopupContextItem()) {
566 ImGui::Text("Color %d (0x%04X)", i, color.snes());
567 ImGui::Separator();
568 if (ImGui::MenuItem("Edit Color")) {
571 temp_color_ = display_color;
572 editing_color_ = display_color;
573 }
574 if (ImGui::MenuItem("Reset to Black")) {
575 palette[i] = gfx::SnesColor(0);
578 }
579 }
580 ImGui::EndPopup();
581 }
582
583 if (ImGui::IsItemHovered()) {
584 ImGui::SetTooltip("Color %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)", i,
585 color.snes(), static_cast<int>(display_color.x * 255),
586 static_cast<int>(display_color.y * 255),
587 static_cast<int>(display_color.z * 255));
588 }
589
590 ImGui::PopID();
591 }
592
593 if (editing_color_index_ >= 0) {
594 // Use a unique ID for the popup to prevent conflicts
595 std::string popup_id =
596 gui::MakePopupIdWithInstance("PaletteEditorWidget", "EditColor", this);
597
598 ImGui::OpenPopup(popup_id.c_str());
599 if (ImGui::BeginPopupModal(popup_id.c_str(), nullptr,
600 ImGuiWindowFlags_AlwaysAutoResize)) {
601 ImGui::Text("Editing Color %d", editing_color_index_);
602 if (ImGui::ColorEdit4(
603 "Color", &temp_color_.x,
604 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_DisplayRGB)) {
605 auto new_snes_color = gfx::SnesColor(temp_color_);
606 palette[editing_color_index_] = new_snes_color;
609 }
612 }
613 }
614 if (gui::PrimaryButton("Apply")) {
616 ImGui::CloseCurrentPopup();
617 }
618 ImGui::SameLine();
619 if (gui::ThemedButton("Cancel")) {
621 ImGui::CloseCurrentPopup();
622 }
623 ImGui::EndPopup();
624 }
625 }
626}
627
631 }
632
633 if (rom_palette_groups_.empty()) {
634 ImGui::Text("No ROM palettes available");
635 return;
636 }
637
638 ImGui::Text("Palette Group:");
639 if (ImGui::Combo("##PaletteGroup", &current_group_index_,
640 RomPaletteGroupNameGetter, &palette_group_names_,
641 static_cast<int>(palette_group_names_.size()))) {
642 }
643
644 ImGui::Text("Palette Index:");
645 ImGui::SliderInt("##PaletteIndex", &current_palette_index_, 0, 7, "%d");
646
647 if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
648 ImGui::Text("Preview:");
649 const auto& preview_palette = rom_palette_groups_[current_group_index_];
650 for (int i = 0; i < 8 && i < static_cast<int>(preview_palette.size());
651 i++) {
652 if (i > 0)
653 ImGui::SameLine();
654 auto color = preview_palette[i];
655 ImVec4 display_color = color.rgb();
656 ImGui::ColorButton(("##preview" + std::to_string(i)).c_str(),
657 display_color, ImGuiColorEditFlags_NoTooltip,
658 ImVec2(20, 20));
659 }
660 }
661}
662
664 int color_index) {
665 ImVec4 rgba = color.rgb();
666
667 ImGui::PushID(color_index);
668
669 if (ImGui::ColorEdit4(
670 "##color_edit", &rgba.x,
671 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_DisplayRGB)) {
672 color = gfx::SnesColor(rgba);
673 }
674
675 ImGui::Text("SNES Color: 0x%04X", color.snes());
676
677 int r = (color.snes() & 0x1F);
678 int g = (color.snes() >> 5) & 0x1F;
679 int b = (color.snes() >> 10) & 0x1F;
680
681 if (ImGui::SliderInt("Red", &r, 0, 31)) {
682 uint16_t new_color = (color.snes() & 0xFFE0) | (r & 0x1F);
683 color = gfx::SnesColor(new_color);
684 }
685 if (ImGui::SliderInt("Green", &g, 0, 31)) {
686 uint16_t new_color = (color.snes() & 0xFC1F) | ((g & 0x1F) << 5);
687 color = gfx::SnesColor(new_color);
688 }
689 if (ImGui::SliderInt("Blue", &b, 0, 31)) {
690 uint16_t new_color = (color.snes() & 0x83FF) | ((b & 0x1F) << 10);
691 color = gfx::SnesColor(new_color);
692 }
693
694 ImGui::PopID();
695}
696
698 ImGui::Text("Palette Information:");
699 ImGui::Text("Size: %zu colors", palette.size());
700
701 std::map<uint16_t, int> color_frequency;
702 for (int i = 0; i < static_cast<int>(palette.size()); i++) {
703 color_frequency[palette[i].snes()]++;
704 }
705
706 ImGui::Text("Unique Colors: %zu", color_frequency.size());
707
708 if (color_frequency.size() < palette.size()) {
709 ImGui::TextColored(ImVec4(1, 1, 0, 1),
710 "Warning: Duplicate colors detected!");
711 if (ImGui::TreeNode("Duplicate Colors")) {
712 for (const auto& [snes_color, count] : color_frequency) {
713 if (count > 1) {
714 ImVec4 display_color = gfx::SnesColor(snes_color).rgb();
715 ImGui::ColorButton(("##dup" + std::to_string(snes_color)).c_str(),
716 display_color, ImGuiColorEditFlags_NoTooltip,
717 ImVec2(16, 16));
718 ImGui::SameLine();
719 ImGui::Text("0x%04X appears %d times", snes_color, count);
720 }
721 }
722 ImGui::TreePop();
723 }
724 }
725
726 // Visual histogram of color reuse
727 {
728 plotting::PlotStyleScope plot_style(
729 gui::ThemeManager::Get().GetCurrentTheme());
730 plotting::PlotConfig plot_cfg{.id = "Palette Color Frequency",
731 .x_label = "Color Index",
732 .y_label = "Count",
733 .flags = ImPlotFlags_NoBoxSelect,
734 .x_axis_flags = ImPlotAxisFlags_AutoFit,
735 .y_axis_flags = ImPlotAxisFlags_AutoFit};
736 std::vector<double> x;
737 std::vector<double> y;
738 x.reserve(color_frequency.size());
739 y.reserve(color_frequency.size());
740 for (const auto& [snes_color, count] : color_frequency) {
741 x.push_back(static_cast<double>(snes_color));
742 y.push_back(static_cast<double>(count));
743 }
744 plotting::PlotGuard plot(plot_cfg);
745 if (plot && !x.empty()) {
746 ImPlot::PlotBars("Count", x.data(), y.data(), static_cast<int>(x.size()),
747 0.5, 0.0, ImPlotBarsFlags_None);
748 }
749 }
750
751 float total_brightness = 0.0f;
752 float min_brightness = 1.0f;
753 float max_brightness = 0.0f;
754
755 for (int i = 0; i < static_cast<int>(palette.size()); i++) {
756 ImVec4 color = palette[i].rgb();
757 float brightness = (color.x + color.y + color.z) / 3.0f;
758 total_brightness += brightness;
759 min_brightness = std::min(min_brightness, brightness);
760 max_brightness = std::max(max_brightness, brightness);
761 }
762
763 float avg_brightness = total_brightness / palette.size();
764
765 ImGui::Separator();
766 ImGui::Text("Brightness Analysis:");
767 ImGui::Text("Average: %.2f", avg_brightness);
768 ImGui::Text("Range: %.2f - %.2f", min_brightness, max_brightness);
769
770 ImGui::Text("Brightness Distribution:");
771 ImGui::ProgressBar(avg_brightness, ImVec2(-1, 0), "Avg");
772}
773
776 return;
777
778 try {
779 const auto& palette_groups = game_data_->palette_groups;
781 palette_group_names_.clear();
782
783 if (palette_groups.overworld_main.size() > 0) {
784 rom_palette_groups_.push_back(palette_groups.overworld_main[0]);
785 palette_group_names_.push_back("Overworld Main");
786 }
787 if (palette_groups.overworld_aux.size() > 0) {
788 rom_palette_groups_.push_back(palette_groups.overworld_aux[0]);
789 palette_group_names_.push_back("Overworld Aux");
790 }
791 if (palette_groups.overworld_animated.size() > 0) {
792 rom_palette_groups_.push_back(palette_groups.overworld_animated[0]);
793 palette_group_names_.push_back("Overworld Animated");
794 }
795 if (palette_groups.dungeon_main.size() > 0) {
796 rom_palette_groups_.push_back(palette_groups.dungeon_main[0]);
797 palette_group_names_.push_back("Dungeon Main");
798 }
799 if (palette_groups.global_sprites.size() > 0) {
800 rom_palette_groups_.push_back(palette_groups.global_sprites[0]);
801 palette_group_names_.push_back("Global Sprites");
802 }
803 if (palette_groups.armors.size() > 0) {
804 rom_palette_groups_.push_back(palette_groups.armors[0]);
805 palette_group_names_.push_back("Armor");
806 }
807 if (palette_groups.swords.size() > 0) {
808 rom_palette_groups_.push_back(palette_groups.swords[0]);
809 palette_group_names_.push_back("Swords");
810 }
811
813 } catch (const std::exception& e) {
814 LOG_ERROR("Enhanced Palette Editor", "Failed to load ROM palettes");
815 }
816}
817
818} // namespace gui
819} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:36
static Arena & Get()
Definition arena.cc:21
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
const SnesPalette & palette() const
Definition bitmap.h:368
const std::vector< uint8_t > & vector() const
Definition bitmap.h:381
bool is_active() const
Definition bitmap.h:384
int height() const
Definition bitmap.h:374
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
Definition bitmap.cc:384
int width() const
Definition bitmap.h:373
void SetPaletteWithTransparent(const SnesPalette &palette, size_t index, int length=7)
Set the palette with a transparent color.
Definition bitmap.cc:456
SNES Color container.
Definition snes_color.h:110
constexpr ImVec4 rgb() const
Get RGB values (WARNING: stored as 0-255 in ImVec4)
Definition snes_color.h:183
constexpr uint16_t snes() const
Get SNES 15-bit color.
Definition snes_color.h:193
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
std::vector< gfx::SnesPalette > rom_palette_groups_
std::function< void(int palette_id)> on_palette_changed_
bool RestorePaletteBackup(gfx::SnesPalette &palette)
void ShowPaletteEditor(gfx::SnesPalette &palette, const std::string &title="Palette Editor")
bool ApplyROMPalette(gfx::Bitmap *bitmap, int group_index, int palette_index)
const gfx::SnesPalette * GetSelectedROMPalette() const
void SavePaletteBackup(const gfx::SnesPalette &palette)
void ShowColorAnalysis(const gfx::Bitmap &bitmap, const std::string &title="Color Analysis")
void Initialize(zelda3::GameData *game_data)
bool ResolveDungeonRenderSelection(gfx::SnesPalette **palette, int *color_index, std::string *source_label)
void DrawColorEditControls(gfx::SnesColor &color, int color_index)
void DrawPaletteAnalysis(const gfx::SnesPalette &palette)
float ComputeSwatchSize(int columns, float min_size, float max_size) const
std::vector< std::string > palette_group_names_
void DrawPaletteGrid(gfx::SnesPalette &palette, int cols=15)
static ThemeManager & Get()
#define LOG_ERROR(category, format,...)
Definition log.h:109
const char * RomPaletteGroupNameGetter(void *user_data, int idx)
bool PrimaryButton(const char *label, const ImVec2 &size, const char *panel_id, const char *anim_id)
Draw a primary action button (accented color).
std::string MakePopupIdWithInstance(const std::string &editor_name, const std::string &popup_name, const void *instance)
Generate popup ID with instance pointer for guaranteed uniqueness.
Definition popup_id.h:45
bool ThemedButton(const char *label, const ImVec2 &size, const char *panel_id, const char *anim_id)
Draw a standard text button with theme colors.
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
Definition color.cc:22
IMGUI_API bool SnesColorEdit4(absl::string_view label, gfx::SnesColor *color, ImGuiColorEditFlags flags)
Definition color.cc:57
SNES color in 15-bit RGB format (BGR555)
gfx::PaletteGroupMap palette_groups
Definition game_data.h:91