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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -7,12 +7,30 @@
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
|
||||
/**
|
||||
* @brief Convert SnesColor to standard ImVec4 for display
|
||||
*
|
||||
* IMPORTANT: SnesColor.rgb() returns 0-255 values in ImVec4 (unconventional!)
|
||||
* This function converts them to standard ImGui format (0.0-1.0)
|
||||
*
|
||||
* @param color SnesColor with internal 0-255 storage
|
||||
* @return ImVec4 with standard 0.0-1.0 RGBA values for ImGui
|
||||
*/
|
||||
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor& color) {
|
||||
return ImVec4(color.rgb().x / 255.0f, color.rgb().y / 255.0f,
|
||||
color.rgb().z / 255.0f, 1.0f);
|
||||
// SnesColor stores RGB as 0-255 in ImVec4, convert to standard 0-1 range
|
||||
ImVec4 rgb_255 = color.rgb();
|
||||
return ImVec4(rgb_255.x / 255.0f, rgb_255.y / 255.0f,
|
||||
rgb_255.z / 255.0f, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert standard ImVec4 to SnesColor
|
||||
*
|
||||
* @param color ImVec4 with standard 0.0-1.0 RGBA values
|
||||
* @return SnesColor with converted values
|
||||
*/
|
||||
gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4& color) {
|
||||
// SnesColor constructor expects 0-1 range and handles conversion internally
|
||||
return gfx::SnesColor(color);
|
||||
}
|
||||
|
||||
@@ -52,6 +70,165 @@ IMGUI_API bool SnesColorEdit4(absl::string_view label, gfx::SnesColor* color,
|
||||
return changed;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// New Standardized Palette Widgets
|
||||
// ============================================================================
|
||||
|
||||
IMGUI_API bool InlinePaletteSelector(gfx::SnesPalette &palette,
|
||||
int num_colors,
|
||||
int* selected_index) {
|
||||
bool selection_made = false;
|
||||
int colors_to_show = std::min(num_colors, static_cast<int>(palette.size()));
|
||||
|
||||
ImGui::BeginGroup();
|
||||
for (int n = 0; n < colors_to_show; n++) {
|
||||
ImGui::PushID(n);
|
||||
if (n > 0 && (n % 8) != 0) {
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
|
||||
}
|
||||
|
||||
bool is_selected = selected_index && (*selected_index == n);
|
||||
if (is_selected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 1.0f, 0.0f, 1.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f);
|
||||
}
|
||||
|
||||
if (SnesColorButton("##palettesel", palette[n],
|
||||
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker,
|
||||
ImVec2(20, 20))) {
|
||||
if (selected_index) {
|
||||
*selected_index = n;
|
||||
selection_made = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_selected) {
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
return selection_made;
|
||||
}
|
||||
|
||||
IMGUI_API absl::Status InlinePaletteEditor(gfx::SnesPalette &palette,
|
||||
const std::string &title,
|
||||
ImGuiColorEditFlags flags) {
|
||||
if (!title.empty()) {
|
||||
ImGui::Text("%s", title.c_str());
|
||||
}
|
||||
|
||||
static int selected_color = 0;
|
||||
static ImVec4 current_color = ImVec4(0, 0, 0, 1.0f);
|
||||
|
||||
// Color picker
|
||||
ImGui::Separator();
|
||||
if (ImGui::ColorPicker4("##colorpicker", (float*)¤t_color,
|
||||
ImGuiColorEditFlags_NoSidePreview |
|
||||
ImGuiColorEditFlags_NoSmallPreview)) {
|
||||
gfx::SnesColor snes_color(current_color);
|
||||
palette.UpdateColor(selected_color, snes_color);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Palette grid
|
||||
ImGui::BeginGroup();
|
||||
for (int n = 0; n < palette.size(); n++) {
|
||||
ImGui::PushID(n);
|
||||
if ((n % 8) != 0) {
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
|
||||
}
|
||||
|
||||
if (flags == 0) {
|
||||
flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker;
|
||||
}
|
||||
|
||||
if (SnesColorButton("##palettedit", palette[n], flags, ImVec2(20, 20))) {
|
||||
selected_color = n;
|
||||
current_color = ConvertSnesColorToImVec4(palette[n]);
|
||||
}
|
||||
|
||||
// Context menu
|
||||
if (ImGui::BeginPopupContextItem()) {
|
||||
if (ImGui::MenuItem("Copy as SNES")) {
|
||||
std::string clipboard = absl::StrFormat("$%04X", palette[n].snes());
|
||||
ImGui::SetClipboardText(clipboard.c_str());
|
||||
}
|
||||
if (ImGui::MenuItem("Copy as RGB")) {
|
||||
auto rgb = palette[n].rgb();
|
||||
std::string clipboard = absl::StrFormat("(%d,%d,%d)",
|
||||
(int)rgb.x, (int)rgb.y, (int)rgb.z);
|
||||
ImGui::SetClipboardText(clipboard.c_str());
|
||||
}
|
||||
if (ImGui::MenuItem("Copy as Hex")) {
|
||||
auto rgb = palette[n].rgb();
|
||||
std::string clipboard = absl::StrFormat("#%02X%02X%02X",
|
||||
(int)rgb.x, (int)rgb.y, (int)rgb.z);
|
||||
ImGui::SetClipboardText(clipboard.c_str());
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
IMGUI_API bool PopupPaletteEditor(const char* popup_id,
|
||||
gfx::SnesPalette &palette,
|
||||
ImGuiColorEditFlags flags) {
|
||||
bool modified = false;
|
||||
|
||||
if (ImGui::BeginPopup(popup_id)) {
|
||||
static int selected_color = 0;
|
||||
static ImVec4 current_color = ImVec4(0, 0, 0, 1.0f);
|
||||
|
||||
// Compact color picker
|
||||
if (ImGui::ColorPicker4("##popuppicker", (float*)¤t_color,
|
||||
ImGuiColorEditFlags_NoSidePreview |
|
||||
ImGuiColorEditFlags_NoSmallPreview)) {
|
||||
gfx::SnesColor snes_color(current_color);
|
||||
palette.UpdateColor(selected_color, snes_color);
|
||||
modified = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Palette grid
|
||||
ImGui::BeginGroup();
|
||||
for (int n = 0; n < palette.size() && n < 64; n++) { // Limit to 64 for popup
|
||||
ImGui::PushID(n);
|
||||
if ((n % 8) != 0) {
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
|
||||
}
|
||||
|
||||
if (SnesColorButton("##popuppal", palette[n],
|
||||
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker,
|
||||
ImVec2(20, 20))) {
|
||||
selected_color = n;
|
||||
current_color = ConvertSnesColorToImVec4(palette[n]);
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Legacy Functions (for compatibility)
|
||||
// ============================================================================
|
||||
|
||||
IMGUI_API bool DisplayPalette(gfx::SnesPalette& palette, bool loaded) {
|
||||
static ImVec4 color = ImVec4(0, 0, 0, 255.f);
|
||||
ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
|
||||
|
||||
@@ -45,6 +45,44 @@ IMGUI_API bool SnesColorButton(absl::string_view id, gfx::SnesColor &color,
|
||||
IMGUI_API bool SnesColorEdit4(absl::string_view label, gfx::SnesColor *color,
|
||||
ImGuiColorEditFlags flags = 0);
|
||||
|
||||
// ============================================================================
|
||||
// Palette Widget Functions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief Small inline palette selector - just color buttons for selection
|
||||
* @param palette Palette to display
|
||||
* @param num_colors Number of colors to show (default 8)
|
||||
* @param selected_index Pointer to store selected color index (optional)
|
||||
* @return True if a color was selected
|
||||
*/
|
||||
IMGUI_API bool InlinePaletteSelector(gfx::SnesPalette &palette,
|
||||
int num_colors = 8,
|
||||
int* selected_index = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Full inline palette editor with color picker and copy options
|
||||
* @param palette Palette to edit
|
||||
* @param title Display title
|
||||
* @param flags ImGui color edit flags
|
||||
* @return Status of the operation
|
||||
*/
|
||||
IMGUI_API absl::Status InlinePaletteEditor(gfx::SnesPalette &palette,
|
||||
const std::string &title = "",
|
||||
ImGuiColorEditFlags flags = 0);
|
||||
|
||||
/**
|
||||
* @brief Popup palette editor - same as inline but in a popup
|
||||
* @param popup_id ID for the popup window
|
||||
* @param palette Palette to edit
|
||||
* @param flags ImGui color edit flags
|
||||
* @return True if palette was modified
|
||||
*/
|
||||
IMGUI_API bool PopupPaletteEditor(const char* popup_id,
|
||||
gfx::SnesPalette &palette,
|
||||
ImGuiColorEditFlags flags = 0);
|
||||
|
||||
// Legacy functions (kept for compatibility, will be deprecated)
|
||||
IMGUI_API bool DisplayPalette(gfx::SnesPalette &palette, bool loaded);
|
||||
|
||||
IMGUI_API absl::Status DisplayEditablePalette(gfx::SnesPalette &palette,
|
||||
|
||||
Reference in New Issue
Block a user