feat: Enhance graphics loading and editor synchronization
- Implemented default palette application during graphics data loading to ensure immediate visibility of graphics sheets. - Refactored GraphicsEditor to queue texture creation without palette management, improving performance and clarity. - Introduced NotifySheetModified method in Arena to handle texture updates across all editors, ensuring consistency in graphics rendering. - Enhanced logging for better tracking of graphics sheet modifications and texture operations.
This commit is contained in:
@@ -104,54 +104,22 @@ absl::Status GraphicsEditor::Load() {
|
|||||||
|
|
||||||
LOG_INFO("GraphicsEditor", "Initializing textures for %d graphics sheets", kNumGfxSheets);
|
LOG_INFO("GraphicsEditor", "Initializing textures for %d graphics sheets", kNumGfxSheets);
|
||||||
|
|
||||||
int sheets_initialized = 0;
|
int sheets_queued = 0;
|
||||||
for (int i = 0; i < kNumGfxSheets; i++) {
|
for (int i = 0; i < kNumGfxSheets; i++) {
|
||||||
if (!sheets[i].is_active() || !sheets[i].surface()) {
|
if (!sheets[i].is_active() || !sheets[i].surface()) {
|
||||||
continue; // Skip inactive or surface-less sheets
|
continue; // Skip inactive or surface-less sheets
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which palette group to use based on sheet index
|
// Palettes are now applied during ROM loading in LoadAllGraphicsData()
|
||||||
gfx::SnesPalette sheet_palette;
|
// Just queue texture creation for sheets that don't have textures yet
|
||||||
|
|
||||||
if (i < 113) {
|
|
||||||
// Overworld/Dungeon graphics - use dungeon main palette
|
|
||||||
auto palette_group = rom()->palette_group().dungeon_main;
|
|
||||||
if (palette_group.size() > 0) {
|
|
||||||
sheet_palette = palette_group[0];
|
|
||||||
}
|
|
||||||
} else if (i < 128) {
|
|
||||||
// Sprite graphics - use sprite palettes
|
|
||||||
auto palette_group = rom()->palette_group().sprites_aux1;
|
|
||||||
if (palette_group.size() > 0) {
|
|
||||||
sheet_palette = palette_group[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Auxiliary graphics - use HUD/menu palettes
|
|
||||||
auto palette_group = rom()->palette_group().hud;
|
|
||||||
if (palette_group.size() > 0) {
|
|
||||||
sheet_palette = palette_group.palette(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRITICAL: Apply palette BEFORE queueing texture creation
|
|
||||||
// The palette must be set on the surface before creating the texture
|
|
||||||
if (!sheet_palette.empty()) {
|
|
||||||
sheets[i].SetPalette(sheet_palette);
|
|
||||||
sheets_initialized++;
|
|
||||||
} else {
|
|
||||||
LOG_WARN("GraphicsEditor", "Sheet %d: Empty palette, skipping", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Queue texture creation if not already created
|
|
||||||
if (!sheets[i].texture()) {
|
if (!sheets[i].texture()) {
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
gfx::Arena::Get().QueueTextureCommand(
|
||||||
gfx::Arena::TextureCommandType::CREATE, &sheets[i]);
|
gfx::Arena::TextureCommandType::CREATE, &sheets[i]);
|
||||||
|
sheets_queued++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("GraphicsEditor", "Initialized %d sheets with palettes, queued for texture creation",
|
LOG_INFO("GraphicsEditor", "Queued texture creation for %d graphics sheets", sheets_queued);
|
||||||
sheets_initialized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
@@ -478,19 +446,16 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
|
|||||||
auto draw_tile_event = [&]() {
|
auto draw_tile_event = [&]() {
|
||||||
current_sheet_canvas_.DrawTileOnBitmap(tile_size_, ¤t_bitmap,
|
current_sheet_canvas_.DrawTileOnBitmap(tile_size_, ¤t_bitmap,
|
||||||
current_color_);
|
current_color_);
|
||||||
// Use batch operations for texture updates
|
// Notify Arena that this sheet has been modified for cross-editor synchronization
|
||||||
// current_bitmap.QueueTextureUpdate(core::Renderer::Get().renderer());
|
gfx::Arena::Get().NotifySheetModified(sheet_id);
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
|
||||||
gfx::Arena::TextureCommandType::UPDATE, ¤t_bitmap);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
current_sheet_canvas_.UpdateColorPainter(
|
current_sheet_canvas_.UpdateColorPainter(
|
||||||
nullptr, gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id),
|
nullptr, gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id),
|
||||||
current_color_, draw_tile_event, tile_size_, current_scale_);
|
current_color_, draw_tile_event, tile_size_, current_scale_);
|
||||||
|
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
// Notify Arena that this sheet has been modified for cross-editor synchronization
|
||||||
gfx::Arena::TextureCommandType::UPDATE,
|
gfx::Arena::Get().NotifySheetModified(sheet_id);
|
||||||
&gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id));
|
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
@@ -580,10 +545,8 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
|
|||||||
auto& sheet = gfx::Arena::Get().mutable_gfx_sheets()->data()[i];
|
auto& sheet = gfx::Arena::Get().mutable_gfx_sheets()->data()[i];
|
||||||
if (sheet.is_active() && sheet.surface()) {
|
if (sheet.is_active() && sheet.surface()) {
|
||||||
sheet.SetPaletteWithTransparent(palette, edit_palette_sub_index_);
|
sheet.SetPaletteWithTransparent(palette, edit_palette_sub_index_);
|
||||||
if (sheet.texture()) {
|
// Notify Arena that this sheet has been modified
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
gfx::Arena::Get().NotifySheetModified(i);
|
||||||
gfx::Arena::TextureCommandType::UPDATE, &sheet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -605,13 +568,8 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
|
|||||||
auto& current = gfx::Arena::Get().mutable_gfx_sheets()->data()[current_sheet_];
|
auto& current = gfx::Arena::Get().mutable_gfx_sheets()->data()[current_sheet_];
|
||||||
if (current.is_active() && current.surface()) {
|
if (current.is_active() && current.surface()) {
|
||||||
current.SetPaletteWithTransparent(palette, edit_palette_sub_index_);
|
current.SetPaletteWithTransparent(palette, edit_palette_sub_index_);
|
||||||
if (current.texture()) {
|
// Notify Arena that this sheet has been modified
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
gfx::Arena::Get().NotifySheetModified(current_sheet_);
|
||||||
gfx::Arena::TextureCommandType::UPDATE, ¤t);
|
|
||||||
} else {
|
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
|
||||||
gfx::Arena::TextureCommandType::CREATE, ¤t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
refresh_graphics_ = false;
|
refresh_graphics_ = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||||
#include "util/hex.h"
|
#include "util/hex.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
namespace yaze {
|
namespace yaze {
|
||||||
namespace editor {
|
namespace editor {
|
||||||
@@ -124,7 +125,7 @@ void MessageEditor::Initialize() {
|
|||||||
gfx::Arena::Get().QueueTextureCommand(
|
gfx::Arena::Get().QueueTextureCommand(
|
||||||
gfx::Arena::TextureCommandType::CREATE, &font_gfx_bitmap_);
|
gfx::Arena::TextureCommandType::CREATE, &font_gfx_bitmap_);
|
||||||
|
|
||||||
printf("[MessageEditor] Font bitmap created and texture queued\n");
|
LOG_INFO("MessageEditor", "Font bitmap created and texture queued");
|
||||||
*current_font_gfx16_bitmap_.mutable_palette() = font_preview_colors_;
|
*current_font_gfx16_bitmap_.mutable_palette() = font_preview_colors_;
|
||||||
|
|
||||||
auto load_font = LoadFontGraphics(*rom());
|
auto load_font = LoadFontGraphics(*rom());
|
||||||
@@ -372,13 +373,32 @@ void MessageEditor::DrawDictionary() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MessageEditor::DrawMessagePreview() {
|
void MessageEditor::DrawMessagePreview() {
|
||||||
|
// Render the message to the preview bitmap
|
||||||
message_preview_.DrawMessagePreview(current_message_);
|
message_preview_.DrawMessagePreview(current_message_);
|
||||||
|
|
||||||
|
// Validate preview data before updating
|
||||||
|
if (message_preview_.current_preview_data_.empty()) {
|
||||||
|
LOG_WARN("MessageEditor", "Preview data is empty, skipping bitmap update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (current_font_gfx16_bitmap_.is_active()) {
|
if (current_font_gfx16_bitmap_.is_active()) {
|
||||||
current_font_gfx16_bitmap_.mutable_data() =
|
// CRITICAL: Use set_data() to properly update both data_ AND surface_
|
||||||
message_preview_.current_preview_data_;
|
// mutable_data() returns a reference but doesn't update the surface!
|
||||||
// Queue texture update via Arena's deferred system
|
current_font_gfx16_bitmap_.set_data(message_preview_.current_preview_data_);
|
||||||
|
|
||||||
|
// Validate surface was updated
|
||||||
|
if (!current_font_gfx16_bitmap_.surface()) {
|
||||||
|
LOG_ERROR("MessageEditor", "Bitmap surface is null after set_data()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue texture update so changes are visible immediately
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
gfx::Arena::Get().QueueTextureCommand(
|
||||||
gfx::Arena::TextureCommandType::UPDATE, ¤t_font_gfx16_bitmap_);
|
gfx::Arena::TextureCommandType::UPDATE, ¤t_font_gfx16_bitmap_);
|
||||||
|
|
||||||
|
LOG_DEBUG("MessageEditor", "Updated message preview bitmap (size: %zu) and queued texture update",
|
||||||
|
message_preview_.current_preview_data_.size());
|
||||||
} else {
|
} else {
|
||||||
// Create bitmap and queue texture creation
|
// Create bitmap and queue texture creation
|
||||||
current_font_gfx16_bitmap_.Create(kCurrentMessageWidth, kCurrentMessageHeight,
|
current_font_gfx16_bitmap_.Create(kCurrentMessageWidth, kCurrentMessageHeight,
|
||||||
@@ -386,6 +406,9 @@ void MessageEditor::DrawMessagePreview() {
|
|||||||
current_font_gfx16_bitmap_.SetPalette(font_preview_colors_);
|
current_font_gfx16_bitmap_.SetPalette(font_preview_colors_);
|
||||||
gfx::Arena::Get().QueueTextureCommand(
|
gfx::Arena::Get().QueueTextureCommand(
|
||||||
gfx::Arena::TextureCommandType::CREATE, ¤t_font_gfx16_bitmap_);
|
gfx::Arena::TextureCommandType::CREATE, ¤t_font_gfx16_bitmap_);
|
||||||
|
|
||||||
|
LOG_INFO("MessageEditor", "Created message preview bitmap (%dx%d) and queued texture creation",
|
||||||
|
kCurrentMessageWidth, kCurrentMessageHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "app/gfx/backend/irenderer.h"
|
#include "app/gfx/backend/irenderer.h"
|
||||||
|
#include "util/log.h"
|
||||||
#include "util/sdl_deleter.h"
|
#include "util/sdl_deleter.h"
|
||||||
|
|
||||||
namespace yaze {
|
namespace yaze {
|
||||||
@@ -79,7 +80,7 @@ void Arena::ProcessTextureQueue(IRenderer* renderer) {
|
|||||||
should_remove = false; // Retry next frame
|
should_remove = false; // Retry next frame
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
printf("[Arena] ERROR: Exception during texture creation\n");
|
LOG_ERROR("Arena", "Exception during texture creation");
|
||||||
should_remove = true; // Remove bad command
|
should_remove = true; // Remove bad command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +95,7 @@ void Arena::ProcessTextureQueue(IRenderer* renderer) {
|
|||||||
active_renderer->UpdateTexture(command.bitmap->texture(), *command.bitmap);
|
active_renderer->UpdateTexture(command.bitmap->texture(), *command.bitmap);
|
||||||
processed++;
|
processed++;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
printf("[Arena] ERROR: Exception during texture update\n");
|
LOG_ERROR("Arena", "Exception during texture update");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -106,7 +107,7 @@ void Arena::ProcessTextureQueue(IRenderer* renderer) {
|
|||||||
command.bitmap->set_texture(nullptr);
|
command.bitmap->set_texture(nullptr);
|
||||||
processed++;
|
processed++;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
printf("[Arena] ERROR: Exception during texture destruction\n");
|
LOG_ERROR("Arena", "Exception during texture destruction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -179,6 +180,29 @@ void Arena::Shutdown() {
|
|||||||
texture_command_queue_.clear();
|
texture_command_queue_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Arena::NotifySheetModified(int sheet_index) {
|
||||||
|
if (sheet_index < 0 || sheet_index >= 223) {
|
||||||
|
LOG_WARN("Arena", "Invalid sheet index %d, ignoring notification", sheet_index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& sheet = gfx_sheets_[sheet_index];
|
||||||
|
if (!sheet.is_active() || !sheet.surface()) {
|
||||||
|
LOG_DEBUG("Arena", "Sheet %d not active or no surface, skipping notification", sheet_index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue texture update so changes are visible in all editors
|
||||||
|
if (sheet.texture()) {
|
||||||
|
QueueTextureCommand(TextureCommandType::UPDATE, &sheet);
|
||||||
|
LOG_DEBUG("Arena", "Queued texture update for modified sheet %d", sheet_index);
|
||||||
|
} else {
|
||||||
|
// Create texture if it doesn't exist
|
||||||
|
QueueTextureCommand(TextureCommandType::CREATE, &sheet);
|
||||||
|
LOG_DEBUG("Arena", "Queued texture creation for modified sheet %d", sheet_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
@@ -96,6 +96,13 @@ class Arena {
|
|||||||
* @return Pointer to mutable array of 223 Bitmap objects
|
* @return Pointer to mutable array of 223 Bitmap objects
|
||||||
*/
|
*/
|
||||||
auto mutable_gfx_sheets() { return &gfx_sheets_; }
|
auto mutable_gfx_sheets() { return &gfx_sheets_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify Arena that a graphics sheet has been modified
|
||||||
|
* @param sheet_index Index of the modified sheet (0-222)
|
||||||
|
* @details This ensures textures are updated across all editors
|
||||||
|
*/
|
||||||
|
void NotifySheetModified(int sheet_index);
|
||||||
|
|
||||||
// Background buffer access for SNES layer rendering
|
// Background buffer access for SNES layer rendering
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -206,6 +206,36 @@ absl::StatusOr<std::array<gfx::Bitmap, kNumGfxSheets>> LoadAllGraphicsData(
|
|||||||
graphics_sheets[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
|
graphics_sheets[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
|
||||||
gfx::kTilesheetDepth, converted_sheet);
|
gfx::kTilesheetDepth, converted_sheet);
|
||||||
|
|
||||||
|
// Apply default palette based on sheet index to prevent white sheets
|
||||||
|
// This ensures graphics are visible immediately after loading
|
||||||
|
if (!rom.palette_group().empty()) {
|
||||||
|
gfx::SnesPalette default_palette;
|
||||||
|
|
||||||
|
if (i < 113) {
|
||||||
|
// Overworld/Dungeon graphics - use dungeon main palette
|
||||||
|
auto palette_group = rom.palette_group().dungeon_main;
|
||||||
|
if (palette_group.size() > 0) {
|
||||||
|
default_palette = palette_group[0];
|
||||||
|
}
|
||||||
|
} else if (i < 128) {
|
||||||
|
// Sprite graphics - use sprite palettes
|
||||||
|
auto palette_group = rom.palette_group().sprites_aux1;
|
||||||
|
if (palette_group.size() > 0) {
|
||||||
|
default_palette = palette_group[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Auxiliary graphics - use HUD/menu palettes
|
||||||
|
auto palette_group = rom.palette_group().hud;
|
||||||
|
if (palette_group.size() > 0) {
|
||||||
|
default_palette = palette_group.palette(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply palette if we have one
|
||||||
|
if (!default_palette.empty()) {
|
||||||
|
graphics_sheets[i].SetPalette(default_palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int j = 0; j < graphics_sheets[i].size(); ++j) {
|
for (int j = 0; j < graphics_sheets[i].size(); ++j) {
|
||||||
rom.mutable_graphics_buffer()->push_back(graphics_sheets[i].at(j));
|
rom.mutable_graphics_buffer()->push_back(graphics_sheets[i].at(j));
|
||||||
|
|||||||
Reference in New Issue
Block a user