feat(gfx): enhance Bitmap class with palette management and metadata support

- Added methods for applying palettes based on metadata, allowing for flexible palette handling in different bitmap types.
- Introduced a new BitmapMetadata struct to track source format and palette requirements.
- Enhanced ApplyStoredPalette and SetPaletteWithTransparent methods for improved palette application and transparency handling.
- Updated SDL surface pixel management with a new UpdateSurfacePixels method for better pixel data handling.

Benefits:
- Improves the rendering capabilities of the Bitmap class by supporting various palette formats.
- Enhances user experience with more intuitive palette management in graphics operations.
This commit is contained in:
scawful
2025-10-13 17:06:10 -04:00
parent 1314d9daf9
commit 668fdc8068
10 changed files with 600 additions and 66 deletions

View File

@@ -351,6 +351,43 @@ void CanvasContextMenu::RenderPaletteOperationsMenu(Rom* rom, gfx::Bitmap* bitma
DisplayEditablePalette(*bitmap->mutable_palette(), "Palette", true, 8);
ImGui::EndMenu();
}
ImGui::Separator();
// Palette Help submenu
if (ImGui::BeginMenu(ICON_MD_HELP " Palette Help")) {
ImGui::TextColored(ImVec4(0.7F, 0.9F, 1.0F, 1.0F), "Bitmap Metadata");
ImGui::Separator();
const auto& meta = bitmap->metadata();
ImGui::Text("Source BPP: %d", meta.source_bpp);
ImGui::Text("Palette Format: %s", meta.palette_format == 0 ? "Full" : "Sub-palette");
ImGui::Text("Source Type: %s", meta.source_type.c_str());
ImGui::Text("Expected Colors: %d", meta.palette_colors);
ImGui::Text("Actual Palette Size: %zu", bitmap->palette().size());
ImGui::Separator();
ImGui::TextColored(ImVec4(1.0F, 0.9F, 0.6F, 1.0F), "Palette Application Method");
if (meta.palette_format == 0) {
ImGui::TextWrapped("Full palette (SetPalette) - all colors applied directly");
} else {
ImGui::TextWrapped("Sub-palette (SetPaletteWithTransparent) - color 0 is transparent, 1-7 from palette");
}
ImGui::Separator();
ImGui::TextColored(ImVec4(0.6F, 1.0F, 0.6F, 1.0F), "Documentation");
if (ImGui::MenuItem("Palette System Architecture")) {
ImGui::SetClipboardText("yaze/docs/palette-system-architecture.md");
// TODO: Open file in system viewer
}
if (ImGui::MenuItem("User Palette Guide")) {
ImGui::SetClipboardText("yaze/docs/user-palette-guide.md");
// TODO: Open file in system viewer
}
ImGui::EndMenu();
}
ImGui::EndMenu();
}
}

View File

@@ -93,7 +93,7 @@ bool LoadROMPaletteGroups(Rom* rom, CanvasPaletteManager& palette_manager) {
}
}
bool ApplyPaletteGroup(gfx::IRenderer* renderer, gfx::Bitmap* bitmap, const CanvasPaletteManager& palette_manager,
bool ApplyPaletteGroup(gfx::IRenderer* renderer, gfx::Bitmap* bitmap, CanvasPaletteManager& palette_manager,
int group_index, int palette_index) {
if (!bitmap) return false;
@@ -110,11 +110,13 @@ bool ApplyPaletteGroup(gfx::IRenderer* renderer, gfx::Bitmap* bitmap, const Canv
bitmap->SetPaletteWithTransparent(palette, palette_index);
}
bitmap->set_modified(true);
palette_manager.palette_dirty = true;
// Queue texture update via Arena's deferred system
if (renderer) {
// Queue texture update only if live_update is enabled
if (palette_manager.live_update_enabled && renderer) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, bitmap);
palette_manager.palette_dirty = false; // Clear dirty flag after update
}
return true;
}

View File

@@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include "app/gfx/resource/arena.h"
#include "app/gfx/types/snes_palette.h"
#include "app/rom.h"
#include "imgui/imgui.h"
@@ -62,6 +63,10 @@ struct CanvasPaletteManager {
int current_group_index = 0;
int current_palette_index = 0;
// Live update control
bool live_update_enabled = true; // Enable/disable live texture updates
bool palette_dirty = false; // Track if palette has changed
void Clear() {
rom_palette_groups.clear();
palette_group_names.clear();
@@ -69,6 +74,8 @@ struct CanvasPaletteManager {
palettes_loaded = false;
current_group_index = 0;
current_palette_index = 0;
live_update_enabled = true;
palette_dirty = false;
}
};
@@ -95,9 +102,20 @@ int GetTileIdFromPosition(ImVec2 mouse_pos, float tile_size, float scale, int ti
// Palette management utilities
bool LoadROMPaletteGroups(Rom* rom, CanvasPaletteManager& palette_manager);
bool ApplyPaletteGroup(gfx::IRenderer* renderer, gfx::Bitmap* bitmap, const CanvasPaletteManager& palette_manager,
bool ApplyPaletteGroup(gfx::IRenderer* renderer, gfx::Bitmap* bitmap, CanvasPaletteManager& palette_manager,
int group_index, int palette_index);
/**
* @brief Apply pending palette updates (when live_update is disabled)
*/
inline void ApplyPendingPaletteUpdates(gfx::IRenderer* renderer, gfx::Bitmap* bitmap, CanvasPaletteManager& palette_manager) {
if (palette_manager.palette_dirty && bitmap && renderer) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, bitmap);
palette_manager.palette_dirty = false;
}
}
// Drawing utility functions (moved from Canvas class)
void DrawCanvasRect(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling,
int x, int y, int w, int h, ImVec4 color, float global_scale);