From 521df1f54627cc910eaff24c4728c3970b16c2e8 Mon Sep 17 00:00:00 2001 From: scawful Date: Mon, 13 Oct 2025 17:12:36 -0400 Subject: [PATCH] fix(editor): update message preview bitmap depth to 8-bit indexed format - Changed the bitmap depth for message previews from 64 to 8 to support indexed palette mode. - Updated logging to reflect the new depth in message preview creation. - Enhanced Bitmap class with a new method to update surface pixels, ensuring proper pixel data handling in rendering. Benefits: - Improves compatibility with indexed palette formats in message rendering. - Enhances the clarity of logging for bitmap creation processes. --- src/app/editor/message/message_editor.cc | 6 ++-- src/app/editor/message/message_editor.h | 2 +- src/app/gfx/core/bitmap.cc | 42 +++++++++++++++++------ src/app/gfx/core/bitmap.h | 6 ++++ src/zelda3/screen/overworld_map_screen.cc | 3 ++ src/zelda3/screen/title_screen.cc | 6 ++++ 6 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/app/editor/message/message_editor.cc b/src/app/editor/message/message_editor.cc index 7af2ce40..528596ed 100644 --- a/src/app/editor/message/message_editor.cc +++ b/src/app/editor/message/message_editor.cc @@ -419,14 +419,14 @@ void MessageEditor::DrawMessagePreview() { LOG_DEBUG("MessageEditor", "Updated message preview bitmap (size: %zu) and queued texture update", message_preview_.current_preview_data_.size()); } else { - // Create bitmap and queue texture creation + // Create bitmap and queue texture creation with 8-bit indexed depth current_font_gfx16_bitmap_.Create(kCurrentMessageWidth, kCurrentMessageHeight, - 64, message_preview_.current_preview_data_); + 8, message_preview_.current_preview_data_); current_font_gfx16_bitmap_.SetPalette(font_preview_colors_); gfx::Arena::Get().QueueTextureCommand( gfx::Arena::TextureCommandType::CREATE, ¤t_font_gfx16_bitmap_); - LOG_INFO("MessageEditor", "Created message preview bitmap (%dx%d) and queued texture creation", + LOG_INFO("MessageEditor", "Created message preview bitmap (%dx%d) with 8-bit depth and queued texture creation", kCurrentMessageWidth, kCurrentMessageHeight); } } diff --git a/src/app/editor/message/message_editor.h b/src/app/editor/message/message_editor.h index 0ef0f43e..1ba31230 100644 --- a/src/app/editor/message/message_editor.h +++ b/src/app/editor/message/message_editor.h @@ -23,7 +23,7 @@ constexpr int kGfxFont = 0x70000; // 2bpp format constexpr int kCharactersWidth = 0x74ADF; constexpr int kNumMessages = 396; constexpr int kFontGfxMessageSize = 128; -constexpr int kFontGfxMessageDepth = 64; +constexpr int kFontGfxMessageDepth = 8; // Fixed: Must be 8 for indexed palette mode constexpr int kFontGfx16Size = 172 * 4096; constexpr uint8_t kBlockTerminator = 0x80; diff --git a/src/app/gfx/core/bitmap.cc b/src/app/gfx/core/bitmap.cc index 31989a5b..9e09fee0 100644 --- a/src/app/gfx/core/bitmap.cc +++ b/src/app/gfx/core/bitmap.cc @@ -269,8 +269,8 @@ void Bitmap::ApplyStoredPalette() { if (surface_ == nullptr) { return; // Can't apply without surface } - if (surface_->format == nullptr || surface_->format->palette == nullptr) { - return; // Can't apply palette to this surface format + if (surface_->format == nullptr) { + return; // Invalid surface format } if (palette_.empty()) { return; // No palette to apply @@ -279,36 +279,58 @@ void Bitmap::ApplyStoredPalette() { // Invalidate palette cache when palette changes InvalidatePaletteCache(); + // For indexed surfaces, ensure palette exists SDL_Palette *sdl_palette = surface_->format->palette; if (sdl_palette == nullptr) { + // Non-indexed surface or palette not created - can't apply palette + SDL_Log("Warning: Bitmap surface has no palette (non-indexed format?)\n"); return; } SDL_UnlockSurface(surface_); - // Apply all palette colors from the SnesPalette - for (size_t i = 0; i < palette_.size() && i < 256; ++i) { + // Build SDL color array from SnesPalette + // Only set the colors that exist in the palette - don't fill unused entries + std::vector colors(palette_.size()); + for (size_t i = 0; i < palette_.size(); ++i) { const auto& pal_color = palette_[i]; // Get RGB values - stored as 0-255 in ImVec4 (unconventional!) ImVec4 rgb_255 = pal_color.rgb(); - sdl_palette->colors[i].r = static_cast(rgb_255.x); - sdl_palette->colors[i].g = static_cast(rgb_255.y); - sdl_palette->colors[i].b = static_cast(rgb_255.z); + colors[i].r = static_cast(rgb_255.x); + colors[i].g = static_cast(rgb_255.y); + colors[i].b = static_cast(rgb_255.z); // Only apply transparency if explicitly set - // (ROM data won't have this set; transparency is added during rendering) if (pal_color.is_transparent()) { - sdl_palette->colors[i].a = 0; // Fully transparent + colors[i].a = 0; // Fully transparent } else { - sdl_palette->colors[i].a = 255; // Fully opaque + colors[i].a = 255; // Fully opaque } } + // Apply palette to surface using SDL_SetPaletteColors + // Only set the colors we have - leave rest of palette unchanged + // This prevents breaking systems that use small palettes (8-16 colors) + SDL_SetPaletteColors(sdl_palette, colors.data(), 0, static_cast(palette_.size())); + SDL_LockSurface(surface_); } +void Bitmap::UpdateSurfacePixels() { + if (!surface_ || data_.empty()) { + return; + } + + // Copy pixel data from data_ vector to SDL surface + SDL_LockSurface(surface_); + if (surface_->pixels && data_.size() > 0) { + memcpy(surface_->pixels, data_.data(), std::min(data_.size(), static_cast(surface_->pitch * surface_->h))); + } + SDL_UnlockSurface(surface_); +} + void Bitmap::SetPalette(const SnesPalette &palette) { // Store palette even if surface isn't ready yet palette_ = palette; diff --git a/src/app/gfx/core/bitmap.h b/src/app/gfx/core/bitmap.h index 14837f61..da3cf56b 100644 --- a/src/app/gfx/core/bitmap.h +++ b/src/app/gfx/core/bitmap.h @@ -177,6 +177,12 @@ class Bitmap { * @brief Apply the stored palette to the surface (internal helper) */ void ApplyStoredPalette(); + + /** + * @brief Update SDL surface with current pixel data from data_ vector + * Call this after modifying pixel data via mutable_data() + */ + void UpdateSurfacePixels(); /** * @brief Set the palette using SDL colors diff --git a/src/zelda3/screen/overworld_map_screen.cc b/src/zelda3/screen/overworld_map_screen.cc index 53674d73..8127ddc5 100644 --- a/src/zelda3/screen/overworld_map_screen.cc +++ b/src/zelda3/screen/overworld_map_screen.cc @@ -218,6 +218,9 @@ absl::Status OverworldMapScreen::RenderMapLayer(bool use_dark_world) { } } + // Update surface with rendered pixel data + map_bitmap_.UpdateSurfacePixels(); + // Apply appropriate palette map_bitmap_.SetPalette(use_dark_world ? dw_palette_ : lw_palette_); diff --git a/src/zelda3/screen/title_screen.cc b/src/zelda3/screen/title_screen.cc index 3aedd9f1..33635827 100644 --- a/src/zelda3/screen/title_screen.cc +++ b/src/zelda3/screen/title_screen.cc @@ -279,6 +279,9 @@ absl::Status TitleScreen::RenderBG1Layer() { } } } + + // Update surface with rendered pixel data + tiles_bg1_bitmap_.UpdateSurfacePixels(); return absl::OkStatus(); } @@ -332,6 +335,9 @@ absl::Status TitleScreen::RenderBG2Layer() { } } } + + // Update surface with rendered pixel data + tiles_bg2_bitmap_.UpdateSurfacePixels(); return absl::OkStatus(); }