From 33f64f38a55e4aa54bfcabdb76aeb34bfd3aaf8f Mon Sep 17 00:00:00 2001 From: scawful Date: Tue, 7 Oct 2025 11:56:53 -0400 Subject: [PATCH] feat: Enhance Logging and Buffer Management in ROM and Editor Components - Added critical logging for graphics buffer management in LoadAllGraphicsData to prevent data corruption during ROM loads. - Updated logging levels from INFO to DEBUG across various components for consistency and to reduce log verbosity. - Refactored texture creation and palette application logic to allow editors to manage their own rendering, improving flexibility and user experience. - Improved background buffer handling to ensure fresh bitmap creation only when necessary, optimizing performance. - Enhanced debugging output for canvas and performance tracking, aiding in better diagnostics during development. --- src/app/core/project.cc | 28 ++++----- src/app/core/window.cc | 12 ---- .../editor/dungeon/dungeon_canvas_viewer.cc | 24 ++------ src/app/editor/dungeon/dungeon_room_loader.cc | 2 +- src/app/editor/editor_manager.cc | 12 ++-- src/app/editor/overworld/overworld_editor.cc | 40 ++++++------- src/app/editor/system/settings_editor.cc | 2 +- src/app/gfx/background_buffer.cc | 58 +++++++++++++------ src/app/gfx/performance_profiler.cc | 3 +- .../canvas/canvas_performance_integration.cc | 14 ++--- src/app/gui/canvas/canvas_usage_tracker.cc | 8 +-- src/app/gui/canvas_utils.cc | 4 +- src/app/rom.cc | 40 ++++++++----- src/app/zelda3/overworld/overworld.cc | 4 +- 14 files changed, 132 insertions(+), 119 deletions(-) diff --git a/src/app/core/project.cc b/src/app/core/project.cc index 8f847c0b..5b8e624b 100644 --- a/src/app/core/project.cc +++ b/src/app/core/project.cc @@ -127,7 +127,7 @@ absl::Status YazeProject::Open(const std::string& project_path) { #ifdef YAZE_ENABLE_JSON_PROJECT_FORMAT if (first_char == '{') { - LOG_INFO("Project", "Detected JSON format project file"); + LOG_DEBUG("Project", "Detected JSON format project file"); return LoadFromJsonFormat(project_path); } #endif @@ -889,19 +889,19 @@ absl::Status YazeProject::InitializeEmbeddedLabels() { resource_labels = zelda3::Zelda3Labels::ToResourceLabels(); use_embedded_labels = true; - LOG_INFO("Project", "Initialized embedded labels:"); - LOG_INFO("Project", " - %d room names", resource_labels["room"].size()); - LOG_INFO("Project", " - %d entrance names", resource_labels["entrance"].size()); - LOG_INFO("Project", " - %d sprite names", resource_labels["sprite"].size()); - LOG_INFO("Project", " - %d overlord names", resource_labels["overlord"].size()); - LOG_INFO("Project", " - %d item names", resource_labels["item"].size()); - LOG_INFO("Project", " - %d music names", resource_labels["music"].size()); - LOG_INFO("Project", " - %d graphics names", resource_labels["graphics"].size()); - LOG_INFO("Project", " - %d room effect names", resource_labels["room_effect"].size()); - LOG_INFO("Project", " - %d room tag names", resource_labels["room_tag"].size()); - LOG_INFO("Project", " - %d tile type names", resource_labels["tile_type"].size()); - LOG_INFO("Project", " - %d overlord names", resource_labels["overlord"].size()); - LOG_INFO("Project", " - %d item names", resource_labels["item"].size()); + LOG_DEBUG("Project", "Initialized embedded labels:"); + LOG_DEBUG("Project", " - %d room names", resource_labels["room"].size()); + LOG_DEBUG("Project", " - %d entrance names", resource_labels["entrance"].size()); + LOG_DEBUG("Project", " - %d sprite names", resource_labels["sprite"].size()); + LOG_DEBUG("Project", " - %d overlord names", resource_labels["overlord"].size()); + LOG_DEBUG("Project", " - %d item names", resource_labels["item"].size()); + LOG_DEBUG("Project", " - %d music names", resource_labels["music"].size()); + LOG_DEBUG("Project", " - %d graphics names", resource_labels["graphics"].size()); + LOG_DEBUG("Project", " - %d room effect names", resource_labels["room_effect"].size()); + LOG_DEBUG("Project", " - %d room tag names", resource_labels["room_tag"].size()); + LOG_DEBUG("Project", " - %d tile type names", resource_labels["tile_type"].size()); + LOG_DEBUG("Project", " - %d overlord names", resource_labels["overlord"].size()); + LOG_DEBUG("Project", " - %d item names", resource_labels["item"].size()); return absl::OkStatus(); } catch (const std::exception& e) { diff --git a/src/app/core/window.cc b/src/app/core/window.cc index f0cd0dd5..aaa139fb 100644 --- a/src/app/core/window.cc +++ b/src/app/core/window.cc @@ -6,9 +6,6 @@ #include "util/sdl_deleter.h" #include "app/gfx/arena.h" #include "app/gui/style.h" -#include "app/gui/theme_manager.h" -#include "app/test/test_manager.h" -#include "util/log.h" #include "imgui/backends/imgui_impl_sdl2.h" #include "imgui/backends/imgui_impl_sdlrenderer2.h" #include "imgui/imgui.h" @@ -59,15 +56,6 @@ absl::Status CreateWindow(Window& window, int flags) { // Apply original YAZE colors as fallback, then try to load theme system gui::ColorsYaze(); - // Try to initialize theme system (will fallback to ColorsYaze if files fail) - auto& theme_manager = gui::ThemeManager::Get(); - auto status = theme_manager.LoadTheme("YAZE Classic"); - if (!status.ok()) { - // Theme system failed, stick with original ColorsYaze() - LOG_WARN("Window", "Theme system failed, using original ColorsYaze(): %s", - status.message().data()); - } - const int audio_frequency = 48000; SDL_AudioSpec want, have; SDL_memset(&want, 0, sizeof(want)); diff --git a/src/app/editor/dungeon/dungeon_canvas_viewer.cc b/src/app/editor/dungeon/dungeon_canvas_viewer.cc index 19178ec8..cf260190 100644 --- a/src/app/editor/dungeon/dungeon_canvas_viewer.cc +++ b/src/app/editor/dungeon/dungeon_canvas_viewer.cc @@ -7,6 +7,7 @@ #include "app/gui/canvas.h" #include "app/gui/input.h" #include "app/rom.h" +#include "util/log.h" #include "app/zelda3/dungeon/object_drawer.h" #include "app/zelda3/dungeon/object_renderer.h" #include "app/zelda3/dungeon/room.h" @@ -106,13 +107,8 @@ void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) { auto& bg1_bitmap = room.bg1_buffer().bitmap(); bool needs_render = !bg1_bitmap.is_active() || bg1_bitmap.width() == 0; - printf("[DrawCanvas] Room %d: needs_render=%d, bg1_active=%d, blocks=%zu, objects=%zu\n", - room_id, needs_render, bg1_bitmap.is_active(), - room.blocks().size(), room.GetTileObjects().size()); - // Render immediately if needed if (needs_render) { - printf("[DrawCanvas] Rendering room %d graphics...\n", room_id); (void)LoadAndRenderRoomGraphics(room_id); } @@ -683,30 +679,20 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) { auto& bg1_bitmap = room.bg1_buffer().bitmap(); auto& bg2_bitmap = room.bg2_buffer().bitmap(); - printf("[RenderLayers] Room %d: BG1 active=%d, texture=%p\n", - room_id, bg1_bitmap.is_active(), (void*)bg1_bitmap.texture()); - if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0 && bg1_bitmap.height() > 0) { if (!bg1_bitmap.texture()) { - printf("[RenderLayers] Creating BG1 texture...\n"); core::Renderer::Get().RenderBitmap(&bg1_bitmap); } - printf("[RenderLayers] Drawing BG1 bitmap: %dx%d, texture=%p\n", - bg1_bitmap.width(), bg1_bitmap.height(), (void*)bg1_bitmap.texture()); - + // DEBUG: Check SDL texture format Uint32 format; int access, w, h; if (SDL_QueryTexture(bg1_bitmap.texture(), &format, &access, &w, &h) == 0) { - printf("[RenderLayers] BG1 texture format: %s (%u), access: %d, size: %dx%d\n", - SDL_GetPixelFormatName(format), format, access, w, h); + const char* format_name_cstr = SDL_GetPixelFormatName(format); } - + canvas_.DrawBitmap(bg1_bitmap, 0, 0, 1.0f, 255); - } else { - printf("[RenderLayers] BG1 not ready: active=%d, w=%d, h=%d\n", - bg1_bitmap.is_active(), bg1_bitmap.width(), bg1_bitmap.height()); - } + } if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0 && bg2_bitmap.height() > 0) { if (!bg2_bitmap.texture()) { diff --git a/src/app/editor/dungeon/dungeon_room_loader.cc b/src/app/editor/dungeon/dungeon_room_loader.cc index 1a55ee18..2d23bc1b 100644 --- a/src/app/editor/dungeon/dungeon_room_loader.cc +++ b/src/app/editor/dungeon/dungeon_room_loader.cc @@ -40,7 +40,7 @@ absl::Status DungeonRoomLoader::LoadAllRooms(std::array& ro static_cast(std::thread::hardware_concurrency())); const int rooms_per_thread = (kTotalRooms + max_concurrency - 1) / max_concurrency; - LOG_INFO("Dungeon", "Loading %d dungeon rooms using %d threads (%d rooms per thread)", + LOG_DEBUG("Dungeon", "Loading %d dungeon rooms using %d threads (%d rooms per thread)", kTotalRooms, max_concurrency, rooms_per_thread); // Thread-safe data structures for collecting results diff --git a/src/app/editor/editor_manager.cc b/src/app/editor/editor_manager.cc index 8c0d716e..0bc74d46 100644 --- a/src/app/editor/editor_manager.cc +++ b/src/app/editor/editor_manager.cc @@ -682,7 +682,7 @@ absl::Status EditorManager::Update() { // Ensure TestManager always has the current ROM static Rom* last_test_rom = nullptr; if (last_test_rom != current_rom_) { - LOG_INFO("EditorManager", + LOG_DEBUG("EditorManager", "EditorManager::Update - ROM changed, updating TestManager: %p -> " "%p", (void*)last_test_rom, (void*)current_rom_); @@ -2039,7 +2039,7 @@ absl::Status EditorManager::LoadRom() { for (auto& session : sessions_) { if (!session.rom.is_loaded()) { target_session = &session; - LOG_INFO("EditorManager", "Found empty session to populate with ROM: %s", + LOG_DEBUG("EditorManager", "Found empty session to populate with ROM: %s", file_name.c_str()); break; } @@ -2067,7 +2067,7 @@ absl::Status EditorManager::LoadRom() { // Update test manager with current ROM for ROM-dependent tests (only when tests are enabled) #ifdef YAZE_ENABLE_TESTING - LOG_INFO("EditorManager", "Setting ROM in TestManager - %p ('%s')", + LOG_DEBUG("EditorManager", "Setting ROM in TestManager - %p ('%s')", (void*)current_rom_, current_rom_ ? current_rom_->title().c_str() : "null"); test::TestManager::Get().SetCurrentRom(current_rom_); @@ -2113,7 +2113,7 @@ absl::Status EditorManager::LoadAssets() { auto end_time = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); - LOG_INFO("EditorManager", "ROM assets loaded in %lld ms", duration.count()); + LOG_DEBUG("EditorManager", "ROM assets loaded in %lld ms", duration.count()); return absl::OkStatus(); } @@ -2273,7 +2273,7 @@ absl::Status EditorManager::OpenProject() { // Update test manager with current ROM for ROM-dependent tests (only when tests are enabled) #ifdef YAZE_ENABLE_TESTING - LOG_INFO("EditorManager", "Setting ROM in TestManager - %p ('%s')", + LOG_DEBUG("EditorManager", "Setting ROM in TestManager - %p ('%s')", (void*)current_rom_, current_rom_ ? current_rom_->title().c_str() : "null"); test::TestManager::Get().SetCurrentRom(current_rom_); @@ -2537,7 +2537,7 @@ void EditorManager::RemoveSession(size_t index) { sessions_[index].custom_name = "[CLOSED SESSION]"; sessions_[index].filepath = ""; - LOG_INFO("EditorManager", "Marked session as closed: %s (index %zu)", + LOG_DEBUG("EditorManager", "Marked session as closed: %s (index %zu)", session_name.c_str(), index); toast_manager_.Show( absl::StrFormat("Session marked as closed: %s", session_name), diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index f920005e..c0b6b5e4 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -78,7 +78,7 @@ void OverworldEditor::Initialize() { absl::Status OverworldEditor::Load() { gfx::ScopedTimer timer("OverworldEditor::Load"); - LOG_INFO("OverworldEditor", "Loading overworld."); + LOG_DEBUG("OverworldEditor", "Loading overworld."); if (!rom_ || !rom_->is_loaded()) { return absl::FailedPreconditionError("ROM not loaded"); } @@ -100,7 +100,7 @@ absl::Status OverworldEditor::Load() { // Force refresh of the current overworld map to show changes RefreshOverworldMap(); - LOG_INFO("OverworldEditor", "Overworld editor refreshed after Tile16 changes"); + LOG_DEBUG("OverworldEditor", "Overworld editor refreshed after Tile16 changes"); return absl::OkStatus(); }); @@ -807,7 +807,7 @@ void OverworldEditor::CheckForOverworldEdits() { auto tile_data = gfx::GetTilemapData(tile16_blockset_, tile16_id); if (!tile_data.empty()) { RenderUpdatedMapBitmap(tile_position, tile_data); - LOG_INFO("OverworldEditor", + LOG_DEBUG("OverworldEditor", "CheckForOverworldEdits: Updated bitmap at position (%d,%d) " "with tile16_id=%d", x, y, tile16_id); @@ -824,7 +824,7 @@ void OverworldEditor::CheckForOverworldEdits() { // This is commented out for now, will come back to later. // ow_map_canvas_.mutable_selected_tiles()->clear(); // ow_map_canvas_.mutable_points()->clear(); - LOG_INFO("OverworldEditor", + LOG_DEBUG("OverworldEditor", "CheckForOverworldEdits: Rectangle selection applied and cleared"); } } @@ -1469,7 +1469,7 @@ absl::Status OverworldEditor::Save() { absl::Status OverworldEditor::LoadGraphics() { gfx::ScopedTimer timer("LoadGraphics"); - LOG_INFO("OverworldEditor", "Loading overworld."); + LOG_DEBUG("OverworldEditor", "Loading overworld."); // Load the Link to the Past overworld. { gfx::ScopedTimer load_timer("Overworld::Load"); @@ -1477,7 +1477,7 @@ absl::Status OverworldEditor::LoadGraphics() { } palette_ = overworld_.current_area_palette(); - LOG_INFO("OverworldEditor", "Loading overworld graphics (optimized)."); + LOG_DEBUG("OverworldEditor", "Loading overworld graphics (optimized)."); // Phase 1: Create bitmaps without textures for faster loading // This avoids blocking the main thread with GPU texture creation @@ -1488,7 +1488,7 @@ absl::Status OverworldEditor::LoadGraphics() { current_gfx_bmp_, palette_); } - LOG_INFO("OverworldEditor", "Loading overworld tileset (deferred textures)."); + LOG_DEBUG("OverworldEditor", "Loading overworld tileset (deferred textures)."); { gfx::ScopedTimer tileset_timer("CreateBitmapWithoutTexture_Tileset"); Renderer::Get().CreateBitmapWithoutTexture( @@ -1499,7 +1499,7 @@ absl::Status OverworldEditor::LoadGraphics() { // Copy the tile16 data into individual tiles. auto tile16_blockset_data = overworld_.tile16_blockset_data(); - LOG_INFO("OverworldEditor", "Loading overworld tile16 graphics."); + LOG_DEBUG("OverworldEditor", "Loading overworld tile16 graphics."); { gfx::ScopedTimer tilemap_timer("CreateTilemap"); @@ -1517,7 +1517,7 @@ absl::Status OverworldEditor::LoadGraphics() { constexpr int kSpecialWorldEssential = zelda3::kSpecialWorldMapIdStart + kEssentialMapsPerWorld; - LOG_INFO("OverworldEditor", + LOG_DEBUG("OverworldEditor", "Creating bitmaps for essential maps only (first %d maps per world)", kEssentialMapsPerWorld); @@ -2049,7 +2049,7 @@ void OverworldEditor::ForceRefreshGraphics(int map_index) { // Clear blockset cache current_blockset_ = 0xFF; - LOG_INFO("OverworldEditor", "ForceRefreshGraphics: Map %d marked for refresh", map_index); + LOG_DEBUG("OverworldEditor", "ForceRefreshGraphics: Map %d marked for refresh", map_index); } } @@ -2097,7 +2097,7 @@ void OverworldEditor::RefreshSiblingMapGraphics(int map_index, bool include_self // Call RefreshChildMapOnDemand() directly instead of RefreshOverworldMapOnDemand() RefreshChildMapOnDemand(sibling); - LOG_INFO("OverworldEditor", "RefreshSiblingMapGraphics: Refreshed sibling map %d", sibling); + LOG_DEBUG("OverworldEditor", "RefreshSiblingMapGraphics: Refreshed sibling map %d", sibling); } } } @@ -2520,7 +2520,7 @@ absl::Status OverworldEditor::ApplyZSCustomOverworldASM(int target_version) { "ROM is already version %d or higher", current_version)); } - LOG_INFO("OverworldEditor", "Applying ZSCustomOverworld ASM v%d to ROM...", + LOG_DEBUG("OverworldEditor", "Applying ZSCustomOverworld ASM v%d to ROM...", target_version); // Initialize Asar wrapper @@ -2540,7 +2540,7 @@ absl::Status OverworldEditor::ApplyZSCustomOverworldASM(int target_version) { // Use GetResourcePath to handle app bundles and various deployment scenarios std::string asm_file_path = util::GetResourcePath(asm_file_name); - LOG_INFO("OverworldEditor", "Using ASM file: %s", asm_file_path.c_str()); + LOG_DEBUG("OverworldEditor", "Using ASM file: %s", asm_file_path.c_str()); // Verify file exists if (!std::filesystem::exists(asm_file_path)) { @@ -2581,17 +2581,17 @@ absl::Status OverworldEditor::ApplyZSCustomOverworldASM(int target_version) { RETURN_IF_ERROR(UpdateROMVersionMarkers(target_version)); // Log symbols found during patching - LOG_INFO("OverworldEditor", "ASM patch applied successfully. Found %zu symbols:", + LOG_DEBUG("OverworldEditor", "ASM patch applied successfully. Found %zu symbols:", result.symbols.size()); for (const auto& symbol : result.symbols) { - LOG_INFO("OverworldEditor", " %s @ $%06X", symbol.name.c_str(), + LOG_DEBUG("OverworldEditor", " %s @ $%06X", symbol.name.c_str(), symbol.address); } // Refresh overworld data to reflect changes RETURN_IF_ERROR(overworld_.Load(rom_)); - LOG_INFO("OverworldEditor", "ZSCustomOverworld v%d successfully applied to ROM", + LOG_DEBUG("OverworldEditor", "ZSCustomOverworld v%d successfully applied to ROM", target_version); return absl::OkStatus(); @@ -2618,7 +2618,7 @@ absl::Status OverworldEditor::UpdateROMVersionMarkers(int target_version) { (*rom_)[zelda3::OverworldCustomAreaSpecificBGEnabled] = 0x01; (*rom_)[zelda3::OverworldCustomMainPaletteEnabled] = 0x01; - LOG_INFO("OverworldEditor", "Enabled v2+ features: Custom BG colors, Main palettes"); + LOG_DEBUG("OverworldEditor", "Enabled v2+ features: Custom BG colors, Main palettes"); } if (target_version >= 3) { @@ -2628,7 +2628,7 @@ absl::Status OverworldEditor::UpdateROMVersionMarkers(int target_version) { (*rom_)[zelda3::OverworldCustomTileGFXGroupEnabled] = 0x01; (*rom_)[zelda3::OverworldCustomMosaicEnabled] = 0x01; - LOG_INFO("OverworldEditor", + LOG_DEBUG("OverworldEditor", "Enabled v3+ features: Subscreen overlays, Animated GFX, Tile GFX " "groups, Mosaic"); @@ -2652,11 +2652,11 @@ absl::Status OverworldEditor::UpdateROMVersionMarkers(int target_version) { } } - LOG_INFO("OverworldEditor", "Initialized area size data for %zu areas", + LOG_DEBUG("OverworldEditor", "Initialized area size data for %zu areas", large_areas.size()); } - LOG_INFO("OverworldEditor", "ROM version markers updated to v%d", target_version); + LOG_DEBUG("OverworldEditor", "ROM version markers updated to v%d", target_version); return absl::OkStatus(); } diff --git a/src/app/editor/system/settings_editor.cc b/src/app/editor/system/settings_editor.cc index 3ce764c9..24afdd5b 100644 --- a/src/app/editor/system/settings_editor.cc +++ b/src/app/editor/system/settings_editor.cc @@ -384,7 +384,7 @@ void SettingsEditor::DrawAIAgentSettings() { std::filesystem::path path(log_file_path); if (std::filesystem::exists(path)) { std::filesystem::remove(path); - LOG_INFO("Settings", "Log file cleared: %s", log_file_path); + LOG_DEBUG("Settings", "Log file cleared: %s", log_file_path); } } } diff --git a/src/app/gfx/background_buffer.cc b/src/app/gfx/background_buffer.cc index 91b43f54..6a24fe94 100644 --- a/src/app/gfx/background_buffer.cc +++ b/src/app/gfx/background_buffer.cc @@ -40,6 +40,25 @@ void BackgroundBuffer::DrawTile(const TileInfo& tile, uint8_t* canvas, int tile_x = (tile.id_ % 16) * 8; // 16 tiles per row, 8 pixels per tile int tile_y = (tile.id_ / 16) * 8; // Each row is 16 tiles + // DEBUG: For floor tiles, check what we're actually reading + static int debug_count = 0; + if (debug_count < 4 && (tile.id_ == 0xEC || tile.id_ == 0xED || tile.id_ == 0xFC || tile.id_ == 0xFD)) { + printf("[DrawTile] Floor tile 0x%02X at sheet pos (%d,%d), palette=%d, mirror=(%d,%d)\n", + tile.id_, tile_x, tile_y, tile.palette_, tile.horizontal_mirror_, tile.vertical_mirror_); + printf("[DrawTile] First row (8 pixels): "); + for (int i = 0; i < 8; i++) { + int src_index = tile_y * 128 + (tile_x + i); + printf("%d ", tiledata[src_index]); + } + printf("\n[DrawTile] Second row (8 pixels): "); + for (int i = 0; i < 8; i++) { + int src_index = (tile_y + 1) * 128 + (tile_x + i); + printf("%d ", tiledata[src_index]); + } + printf("\n"); + debug_count++; + } + // Dungeon graphics are 3BPP: 8 colors per palette (0-7, 8-15, 16-23, etc.) // NOT 4BPP which would be 16 colors per palette! // Clamp palette to 0-10 (90 colors / 8 = 11.25, so max palette is 10) @@ -78,32 +97,33 @@ void BackgroundBuffer::DrawBackground(std::span gfx16_data) { buffer_.resize(tiles_w * tiles_h); } - // CRITICAL: Always create a fresh bitmap for each DrawBackground call - // This ensures we're rendering the current tilemap state, not stale data - printf("[BG:DrawBackground] Creating fresh bitmap for rendering\n"); - bitmap_.Create(width_, height_, 8, std::vector(width_ * height_, 0)); - - // DEBUG: Check if gfx16_data has actual graphics - if (gfx16_data.size() < 100) { - printf("[BG:DrawBackground] WARNING: gfx16_data is too small (%zu bytes)\n", gfx16_data.size()); - } else { - // Sample first 32 bytes - printf("[BG:DrawBackground] gfx16_data size=%zu, first 32 bytes: ", gfx16_data.size()); - for (size_t i = 0; i < 32 && i < gfx16_data.size(); i++) { - printf("%02X ", gfx16_data[i]); - } - printf("\n"); + // NEVER recreate bitmap here - it should be created by DrawFloor or initialized earlier + // If bitmap doesn't exist, create it ONCE with zeros + if (!bitmap_.is_active() || bitmap_.width() == 0) { + bitmap_.Create(width_, height_, 8, std::vector(width_ * height_, 0)); } // For each tile on the tile buffer int drawn_count = 0; + int skipped_count = 0; + int non_floor_count = 0; for (int yy = 0; yy < tiles_h; yy++) { for (int xx = 0; xx < tiles_w; xx++) { uint16_t word = buffer_[xx + yy * tiles_w]; // Prevent draw if tile == 0xFFFF since it's 0 indexed - if (word == 0xFFFF) continue; + if (word == 0xFFFF) { + skipped_count++; + continue; + } auto tile = gfx::WordToTileInfo(word); + // Count floor tiles vs non-floor + if (tile.id_ >= 0xEE && tile.id_ <= 0xFF) { + // This looks like a floor tile (based on DrawFloor's 14EE pattern) + } else if (word != 0) { + non_floor_count++; + } + // Calculate pixel offset for tile position (xx, yy) in the 512x512 bitmap // Each tile is 8x8, so pixel Y = yy * 8, pixel X = xx * 8 // Linear offset = (pixel_y * width) + pixel_x = (yy * 8 * 512) + (xx * 8) @@ -124,6 +144,11 @@ void BackgroundBuffer::DrawBackground(std::span gfx16_data) { void BackgroundBuffer::DrawFloor(const std::vector& rom_data, int tile_address, int tile_address_floor, uint8_t floor_graphics) { + // Create bitmap ONCE at the start if it doesn't exist + if (!bitmap_.is_active() || bitmap_.width() == 0) { + bitmap_.Create(width_, height_, 8, std::vector(width_ * height_, 0)); + } + auto f = (uint8_t)(floor_graphics << 4); // Create floor tiles from ROM data @@ -155,7 +180,6 @@ void BackgroundBuffer::DrawFloor(const std::vector& rom_data, uint16_t word6 = gfx::TileInfoToWord(floorTile6); uint16_t word7 = gfx::TileInfoToWord(floorTile7); uint16_t word8 = gfx::TileInfoToWord(floorTile8); - for (int xx = 0; xx < 16; xx++) { for (int yy = 0; yy < 32; yy++) { SetTileAt((xx * 4), (yy * 2), word1); diff --git a/src/app/gfx/performance_profiler.cc b/src/app/gfx/performance_profiler.cc index dd9a343c..b0de6755 100644 --- a/src/app/gfx/performance_profiler.cc +++ b/src/app/gfx/performance_profiler.cc @@ -7,6 +7,7 @@ #include #include "app/gfx/memory_pool.h" +#include "util/log.h" namespace yaze { namespace gfx { @@ -43,7 +44,7 @@ void PerformanceProfiler::EndTimer(const std::string& operation_name) { if (timer_iter == active_timers_.end()) { // During shutdown, silently ignore missing timers to avoid log spam if (!is_shutting_down_) { - SDL_Log("Warning: EndTimer called for operation '%s' that was not started", + LOG_DEBUG("PerformanceProfiler", "EndTimer called for operation '%s' that was not started", operation_name.c_str()); } return; diff --git a/src/app/gui/canvas/canvas_performance_integration.cc b/src/app/gui/canvas/canvas_performance_integration.cc index 13cf72c3..3b9ce1ee 100644 --- a/src/app/gui/canvas/canvas_performance_integration.cc +++ b/src/app/gui/canvas/canvas_performance_integration.cc @@ -22,7 +22,7 @@ void CanvasPerformanceIntegration::Initialize(const std::string& canvas_id) { // Initialize performance profiler integration dashboard_ = &gfx::PerformanceDashboard::Get(); - LOG_INFO("CanvasPerformance", + LOG_DEBUG("CanvasPerformance", "Initialized performance integration for canvas: %s", canvas_id_.c_str()); } @@ -34,7 +34,7 @@ void CanvasPerformanceIntegration::StartMonitoring() { frame_timer_active_ = true; frame_timer_ = std::make_unique("canvas_frame_" + canvas_id_); - LOG_INFO("CanvasPerformance", "Started performance monitoring for canvas: %s", + LOG_DEBUG("CanvasPerformance", "Started performance monitoring for canvas: %s", canvas_id_.c_str()); } @@ -57,7 +57,7 @@ void CanvasPerformanceIntegration::StopMonitoring() { frame_timer_active_ = false; } - LOG_INFO("CanvasPerformance", "Stopped performance monitoring for canvas: %s", + LOG_DEBUG("CanvasPerformance", "Stopped performance monitoring for canvas: %s", canvas_id_.c_str()); } @@ -363,12 +363,12 @@ void CanvasPerformanceIntegration::AnalyzePerformance() { // Log trends if (std::abs(frame_time_trend) > 1.0) { - LOG_INFO("CanvasPerformance", "Canvas %s: Frame time trend: %.2f ms/sample", + LOG_DEBUG("CanvasPerformance", "Canvas %s: Frame time trend: %.2f ms/sample", canvas_id_.c_str(), frame_time_trend); } if (std::abs(memory_trend) > 1.0) { - LOG_INFO("CanvasPerformance", "Canvas %s: Memory trend: %.2f MB/sample", + LOG_DEBUG("CanvasPerformance", "Canvas %s: Memory trend: %.2f MB/sample", canvas_id_.c_str(), memory_trend); } } @@ -536,7 +536,7 @@ void CanvasPerformanceManager::RegisterIntegration( const std::string& canvas_id, std::shared_ptr integration) { integrations_[canvas_id] = integration; - LOG_INFO("CanvasPerformance", + LOG_DEBUG("CanvasPerformance", "Registered performance integration for canvas: %s", canvas_id.c_str()); } @@ -604,7 +604,7 @@ void CanvasPerformanceManager::ClearAllIntegrations() { integration->StopMonitoring(); } integrations_.clear(); - LOG_INFO("CanvasPerformance", "Cleared all canvas performance integrations"); + LOG_DEBUG("CanvasPerformance", "Cleared all canvas performance integrations"); } } // namespace canvas diff --git a/src/app/gui/canvas/canvas_usage_tracker.cc b/src/app/gui/canvas/canvas_usage_tracker.cc index 57f2a3c0..4633877a 100644 --- a/src/app/gui/canvas/canvas_usage_tracker.cc +++ b/src/app/gui/canvas/canvas_usage_tracker.cc @@ -31,7 +31,7 @@ void CanvasUsageTracker::SetUsageMode(CanvasUsage usage) { // Record mode change interaction RecordInteraction(CanvasInteraction::kModeChange, GetUsageModeName(usage)); - LOG_INFO("CanvasUsage", "Canvas %s: Usage mode changed to %s", + LOG_DEBUG("CanvasUsage", "Canvas %s: Usage mode changed to %s", canvas_id_.c_str(), GetUsageModeName(usage).c_str()); } } @@ -267,7 +267,7 @@ void CanvasUsageTracker::EndSession() { // Save final stats SaveCurrentStats(); - LOG_INFO("CanvasUsage", "Canvas %s: Session ended. Duration: %s, Operations: %d", + LOG_DEBUG("CanvasUsage", "Canvas %s: Session ended. Duration: %s, Operations: %d", canvas_id_.c_str(), FormatDuration(std::chrono::duration_cast( std::chrono::steady_clock::now() - session_start_)).c_str(), @@ -352,7 +352,7 @@ CanvasUsageManager& CanvasUsageManager::Get() { void CanvasUsageManager::RegisterTracker(const std::string& canvas_id, std::shared_ptr tracker) { trackers_[canvas_id] = tracker; - LOG_INFO("CanvasUsage", "Registered usage tracker for canvas: %s", canvas_id.c_str()); + LOG_DEBUG("CanvasUsage", "Registered usage tracker for canvas: %s", canvas_id.c_str()); } std::shared_ptr CanvasUsageManager::GetTracker(const std::string& canvas_id) { @@ -421,7 +421,7 @@ void CanvasUsageManager::ClearAllTrackers() { tracker->ClearHistory(); } trackers_.clear(); - LOG_INFO("CanvasUsage", "Cleared all canvas usage trackers"); + LOG_DEBUG("CanvasUsage", "Cleared all canvas usage trackers"); } } // namespace canvas diff --git a/src/app/gui/canvas_utils.cc b/src/app/gui/canvas_utils.cc index 2d9f91f4..b55edb2b 100644 --- a/src/app/gui/canvas_utils.cc +++ b/src/app/gui/canvas_utils.cc @@ -85,7 +85,7 @@ bool LoadROMPaletteGroups(Rom* rom, CanvasPaletteManager& palette_manager) { } palette_manager.palettes_loaded = true; - LOG_INFO("Canvas", "Loaded %zu ROM palette groups", + LOG_DEBUG("Canvas", "Loaded %zu ROM palette groups", palette_manager.rom_palette_groups.size()); return true; @@ -116,7 +116,7 @@ bool ApplyPaletteGroup(gfx::Bitmap* bitmap, } Renderer::Get().UpdateBitmap(bitmap); - LOG_INFO("Canvas", "Applied palette group %d, index %d to bitmap", + LOG_DEBUG("Canvas", "Applied palette group %d, index %d to bitmap", group_index, palette_index); return true; diff --git a/src/app/rom.cc b/src/app/rom.cc index f2a3fd5f..9aee71b0 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -23,6 +23,7 @@ #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" #include "app/snes.h" +#include "util/log.h" #include "util/hex.h" #include "util/log.h" #include "util/macro.h" @@ -178,6 +179,11 @@ absl::StatusOr> LoadAllGraphicsData( SDL_Renderer *renderer = Renderer::Get().renderer(); const bool renderer_ready = renderer != nullptr; + // CRITICAL: Clear the graphics buffer before loading to prevent corruption! + // Without this, multiple ROM loads would accumulate corrupted data. + rom.mutable_graphics_buffer()->clear(); + LOG_DEBUG("Graphics", "Cleared graphics buffer, loading %d sheets", kNumGfxSheets); + for (uint32_t i = 0; i < kNumGfxSheets; i++) { if (i >= 115 && i <= 126) { // uncompressed sheets sheet.resize(Uncompressed3BPPSize); @@ -201,22 +207,30 @@ absl::StatusOr> LoadAllGraphicsData( if (bpp3) { auto converted_sheet = gfx::SnesTo8bppSheet(sheet, 3); + graphics_sheets[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight, gfx::kTilesheetDepth, converted_sheet); - if (graphics_sheets[i].is_active()) { - if (i > 115) { - // Apply sprites palette - graphics_sheets[i].SetPaletteWithTransparent( - rom.palette_group().global_sprites[0], 0); - } else { - graphics_sheets[i].SetPaletteWithTransparent( - rom.palette_group().dungeon_main[0], 0); - } - } + + // DON'T apply palettes here! Each editor (Dungeon, Graphics, GfxGroup) + // should apply its own palette when displaying sheets. + // This allows users to preview sheets with different palettes in each editor. + // The bitmap data is stored as indexed (8bpp), and palettes are applied + // at texture creation time by each editor. + + // if (graphics_sheets[i].is_active()) { + // if (i > 115) { + // graphics_sheets[i].SetPaletteWithTransparent( + // rom.palette_group().global_sprites[0], 0); + // } else { + // graphics_sheets[i].SetPaletteWithTransparent( + // rom.palette_group().dungeon_main[0], 0); + // } + // } - if (!defer_render && renderer_ready) { - graphics_sheets[i].CreateTexture(renderer); - } + // Don't create textures here either - let editors create them with their palettes + // if (!defer_render && renderer_ready) { + // graphics_sheets[i].CreateTexture(renderer); + // } for (int j = 0; j < graphics_sheets[i].size(); ++j) { rom.mutable_graphics_buffer()->push_back(graphics_sheets[i].at(j)); diff --git a/src/app/zelda3/overworld/overworld.cc b/src/app/zelda3/overworld/overworld.cc index 19d9d1e1..44c0b7ff 100644 --- a/src/app/zelda3/overworld/overworld.cc +++ b/src/app/zelda3/overworld/overworld.cc @@ -273,7 +273,7 @@ absl::Status Overworld::ConfigureMultiAreaMap(int parent_index, AreaSizeEnum siz "Wide and Tall areas require ZSCustomOverworld v3+"); } - LOG_INFO("Overworld", "ConfigureMultiAreaMap: parent=%d, current_size=%d, new_size=%d, version=%d", + LOG_DEBUG("Overworld", "ConfigureMultiAreaMap: parent=%d, current_size=%d, new_size=%d, version=%d", parent_index, static_cast(overworld_maps_[parent_index].area_size()), static_cast(size), asm_version); @@ -383,7 +383,7 @@ absl::Status Overworld::ConfigureMultiAreaMap(int parent_index, AreaSizeEnum siz } } - LOG_INFO("Overworld", "Configured %s area: parent=%d, old_siblings=%zu, new_siblings=%zu", + LOG_DEBUG("Overworld", "Configured %s area: parent=%d, old_siblings=%zu, new_siblings=%zu", (size == AreaSizeEnum::LargeArea) ? "Large" : (size == AreaSizeEnum::WideArea) ? "Wide" : (size == AreaSizeEnum::TallArea) ? "Tall" : "Small",