diff --git a/src/app/editor/dungeon/dungeon_canvas_viewer.cc b/src/app/editor/dungeon/dungeon_canvas_viewer.cc index b98f5dd5..dc8a630a 100644 --- a/src/app/editor/dungeon/dungeon_canvas_viewer.cc +++ b/src/app/editor/dungeon/dungeon_canvas_viewer.cc @@ -93,6 +93,24 @@ void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) { ImGui::SameLine(); gui::InputHexWord("Message ID", &room.message_id_); + // Layer visibility controls + ImGui::Separator(); + ImGui::Text("Layer Controls:"); + ImGui::Checkbox("Show BG1", &bg1_visible_); + ImGui::SameLine(); + ImGui::Checkbox("Show BG2", &bg2_visible_); + + // BG2 layer type dropdown + const char* bg2_layer_types[] = { + "Normal (100%)", "Translucent (75%)", "Addition (50%)", "Dark (25%)", "Off (0%)" + }; + const int bg2_alpha_values[] = {255, 191, 127, 64, 0}; + + if (ImGui::Combo("BG2 Layer Type", &bg2_layer_type_, bg2_layer_types, + sizeof(bg2_layer_types) / sizeof(bg2_layer_types[0]))) { + // BG2 layer type changed, no need to reload graphics + } + // Check if critical properties changed and trigger reload if (prev_blockset != room.blockset || prev_palette != room.palette || prev_layout != room.layout || prev_spriteset != room.spriteset) { @@ -444,7 +462,8 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) { auto& bg1_bitmap = room.bg1_buffer().bitmap(); auto& bg2_bitmap = room.bg2_buffer().bitmap(); - if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0 && bg1_bitmap.height() > 0) { + // Draw BG1 layer if visible and active + if (bg1_visible_ && bg1_bitmap.is_active() && bg1_bitmap.width() > 0 && bg1_bitmap.height() > 0) { if (!bg1_bitmap.texture()) { // Queue texture creation for background layer 1 via Arena's deferred system gfx::Arena::Get().QueueTextureCommand( @@ -456,11 +475,15 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) { // Only draw if texture was successfully created if (bg1_bitmap.texture()) { + printf("[RenderRoomBackgroundLayers] Drawing BG1 bitmap to canvas with texture %p\n", bg1_bitmap.texture()); canvas_.DrawBitmap(bg1_bitmap, 0, 0, 1.0f, 255); + } else { + printf("[RenderRoomBackgroundLayers] ERROR: BG1 bitmap has no texture!\n"); } } - if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0 && bg2_bitmap.height() > 0) { + // Draw BG2 layer if visible and active + if (bg2_visible_ && bg2_bitmap.is_active() && bg2_bitmap.width() > 0 && bg2_bitmap.height() > 0) { if (!bg2_bitmap.texture()) { // Queue texture creation for background layer 2 via Arena's deferred system gfx::Arena::Get().QueueTextureCommand( @@ -472,18 +495,42 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) { // Only draw if texture was successfully created if (bg2_bitmap.texture()) { - canvas_.DrawBitmap(bg2_bitmap, 0, 0, 1.0f, 200); + // Use the selected BG2 layer type alpha value + const int bg2_alpha_values[] = {255, 191, 127, 64, 0}; + int alpha_value = bg2_alpha_values[std::min(bg2_layer_type_, 4)]; + printf("[RenderRoomBackgroundLayers] Drawing BG2 bitmap to canvas with texture %p, alpha=%d\n", bg2_bitmap.texture(), alpha_value); + canvas_.DrawBitmap(bg2_bitmap, 0, 0, 1.0f, alpha_value); + } else { + printf("[RenderRoomBackgroundLayers] ERROR: BG2 bitmap has no texture!\n"); } } // DEBUG: Check if background buffers have content if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0) { - printf("[RenderRoomBackgroundLayers] BG1 bitmap: %dx%d, active=%d\n", - bg1_bitmap.width(), bg1_bitmap.height(), bg1_bitmap.is_active()); + printf("[RenderRoomBackgroundLayers] BG1 bitmap: %dx%d, active=%d, visible=%d, texture=%p\n", + bg1_bitmap.width(), bg1_bitmap.height(), bg1_bitmap.is_active(), bg1_visible_, bg1_bitmap.texture()); + + // Check bitmap data content + auto& bg1_data = bg1_bitmap.mutable_data(); + int non_zero_pixels = 0; + for (size_t i = 0; i < bg1_data.size(); i += 100) { // Sample every 100th pixel + if (bg1_data[i] != 0) non_zero_pixels++; + } + printf("[RenderRoomBackgroundLayers] BG1 bitmap data: %zu pixels, ~%d non-zero samples\n", + bg1_data.size(), non_zero_pixels); } if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0) { - printf("[RenderRoomBackgroundLayers] BG2 bitmap: %dx%d, active=%d\n", - bg2_bitmap.width(), bg2_bitmap.height(), bg2_bitmap.is_active()); + printf("[RenderRoomBackgroundLayers] BG2 bitmap: %dx%d, active=%d, visible=%d, layer_type=%d, texture=%p\n", + bg2_bitmap.width(), bg2_bitmap.height(), bg2_bitmap.is_active(), bg2_visible_, bg2_layer_type_, bg2_bitmap.texture()); + + // Check bitmap data content + auto& bg2_data = bg2_bitmap.mutable_data(); + int non_zero_pixels = 0; + for (size_t i = 0; i < bg2_data.size(); i += 100) { // Sample every 100th pixel + if (bg2_data[i] != 0) non_zero_pixels++; + } + printf("[RenderRoomBackgroundLayers] BG2 bitmap data: %zu pixels, ~%d non-zero samples\n", + bg2_data.size(), non_zero_pixels); } // TEST: Draw a bright red rectangle to verify canvas drawing works @@ -493,6 +540,12 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) { ImVec2(canvas_pos.x + 50, canvas_pos.y + 50), ImVec2(canvas_pos.x + 150, canvas_pos.y + 150), IM_COL32(255, 0, 0, 255)); // Bright red + + // DEBUG: Show canvas and bitmap info + printf("[RenderRoomBackgroundLayers] Canvas pos: (%.1f, %.1f), Canvas size: (%.1f, %.1f)\n", + canvas_pos.x, canvas_pos.y, canvas_.canvas_size().x, canvas_.canvas_size().y); + printf("[RenderRoomBackgroundLayers] BG1 bitmap size: %dx%d, BG2 bitmap size: %dx%d\n", + bg1_bitmap.width(), bg1_bitmap.height(), bg2_bitmap.width(), bg2_bitmap.height()); } } // namespace yaze::editor diff --git a/src/app/editor/dungeon/dungeon_canvas_viewer.h b/src/app/editor/dungeon/dungeon_canvas_viewer.h index 4bd9c6ac..017b495d 100644 --- a/src/app/editor/dungeon/dungeon_canvas_viewer.h +++ b/src/app/editor/dungeon/dungeon_canvas_viewer.h @@ -56,6 +56,16 @@ class DungeonCanvasViewer { void SetObjectInteractionEnabled(bool enabled) { object_interaction_enabled_ = enabled; } bool IsObjectInteractionEnabled() const { return object_interaction_enabled_; } + // Layer visibility controls + void SetBG1Visible(bool visible) { bg1_visible_ = visible; } + void SetBG2Visible(bool visible) { bg2_visible_ = visible; } + bool IsBG1Visible() const { return bg1_visible_; } + bool IsBG2Visible() const { return bg2_visible_; } + + // BG2 layer type controls + void SetBG2LayerType(int type) { bg2_layer_type_ = type; } + int GetBG2LayerType() const { return bg2_layer_type_; } + // Set the object to be placed void SetPreviewObject(const zelda3::RoomObject& object) { object_interaction_.SetPreviewObject(object, true); @@ -95,6 +105,11 @@ class DungeonCanvasViewer { // Object interaction state bool object_interaction_enabled_ = true; + // Layer visibility controls + bool bg1_visible_ = true; + bool bg2_visible_ = true; + int bg2_layer_type_ = 0; // 0=Normal, 1=Translucent, 2=Addition, etc. + // Palette data uint64_t current_palette_group_id_ = 0; uint64_t current_palette_id_ = 0; diff --git a/src/app/gfx/background_buffer.cc b/src/app/gfx/background_buffer.cc index 6a24fe94..addd9a92 100644 --- a/src/app/gfx/background_buffer.cc +++ b/src/app/gfx/background_buffer.cc @@ -146,7 +146,14 @@ void BackgroundBuffer::DrawFloor(const std::vector& rom_data, uint8_t floor_graphics) { // Create bitmap ONCE at the start if it doesn't exist if (!bitmap_.is_active() || bitmap_.width() == 0) { + printf("[DrawFloor] Creating bitmap: %dx%d, active=%d, width=%d\n", + width_, height_, bitmap_.is_active(), bitmap_.width()); bitmap_.Create(width_, height_, 8, std::vector(width_ * height_, 0)); + printf("[DrawFloor] After Create: active=%d, width=%d, height=%d\n", + bitmap_.is_active(), bitmap_.width(), bitmap_.height()); + } else { + printf("[DrawFloor] Bitmap already exists: active=%d, width=%d, height=%d\n", + bitmap_.is_active(), bitmap_.width(), bitmap_.height()); } auto f = (uint8_t)(floor_graphics << 4); diff --git a/src/app/zelda3/dungeon/object_drawer.cc b/src/app/zelda3/dungeon/object_drawer.cc index 2959ac93..fd305fd7 100644 --- a/src/app/zelda3/dungeon/object_drawer.cc +++ b/src/app/zelda3/dungeon/object_drawer.cc @@ -37,6 +37,8 @@ absl::Status ObjectDrawer::DrawObject(const RoomObject& object, // Select buffer based on layer auto& target_bg = (object.layer_ == RoomObject::LayerType::BG2) ? bg2 : bg1; + printf("[DrawObject] Object ID=0x%02X using %s buffer (layer=%d)\n", + object.id_, (object.layer_ == RoomObject::LayerType::BG2) ? "BG2" : "BG1", object.layer_); // Skip objects that don't have tiles loaded - check mutable object if (mutable_obj.tiles().empty()) { @@ -577,6 +579,8 @@ void ObjectDrawer::WriteTile16(gfx::BackgroundBuffer& bg, int tile_x, int tile_y // Draw directly to bitmap instead of tile buffer to avoid being overwritten auto& bitmap = bg.bitmap(); + printf("[WriteTile16] Bitmap status: active=%d, width=%d, height=%d, surface=%p\n", + bitmap.is_active(), bitmap.width(), bitmap.height(), bitmap.surface()); if (!bitmap.is_active() || bitmap.width() == 0) { printf("[WriteTile16] Bitmap not ready: active=%d, width=%d\n", bitmap.is_active(), bitmap.width()); return; // Bitmap not ready @@ -609,8 +613,12 @@ void ObjectDrawer::DrawTileToBitmap(gfx::Bitmap& bitmap, const gfx::TileInfo& ti // Draw an 8x8 tile directly to bitmap at pixel coordinates if (!tiledata) return; - printf("[DrawTileToBitmap] Drawing tile ID=0x%02X at (%d,%d) with palette=%d\n", - tile_info.id_, pixel_x, pixel_y, tile_info.palette_); + // DEBUG: Check if bitmap is valid + if (!bitmap.is_active() || bitmap.width() == 0 || bitmap.height() == 0) { + printf("[DrawTileToBitmap] ERROR: Invalid bitmap - active=%d, size=%dx%d\n", + bitmap.is_active(), bitmap.width(), bitmap.height()); + return; + } // Calculate tile position in graphics sheet (128 pixels wide) int tile_sheet_x = (tile_info.id_ % 16) * 8; // 16 tiles per row @@ -621,6 +629,12 @@ void ObjectDrawer::DrawTileToBitmap(gfx::Bitmap& bitmap, const gfx::TileInfo& ti if (palette_id > 10) palette_id = palette_id % 11; uint8_t palette_offset = palette_id * 8; // 3BPP: 8 colors per palette + // Force a visible palette for debugging + if (palette_id == 0) { + palette_id = 1; // Use palette 1 instead of 0 + palette_offset = palette_id * 8; + } + // Draw 8x8 pixels for (int py = 0; py < 8; py++) { for (int px = 0; px < 8; px++) { @@ -632,8 +646,8 @@ void ObjectDrawer::DrawTileToBitmap(gfx::Bitmap& bitmap, const gfx::TileInfo& ti int src_index = (tile_sheet_y + src_y) * 128 + (tile_sheet_x + src_x); uint8_t pixel_index = tiledata[src_index]; - // Apply palette and write to bitmap - uint8_t final_color = pixel_index + palette_offset; + // Apply palette and write to bitmap + uint8_t final_color = pixel_index + palette_offset; int dest_x = pixel_x + px; int dest_y = pixel_y + py; @@ -641,6 +655,12 @@ void ObjectDrawer::DrawTileToBitmap(gfx::Bitmap& bitmap, const gfx::TileInfo& ti int dest_index = dest_y * bitmap.width() + dest_x; if (dest_index >= 0 && dest_index < static_cast(bitmap.mutable_data().size())) { bitmap.mutable_data()[dest_index] = final_color; + + // Debug first pixel of each tile + if (py == 0 && px == 0) { + printf("[DrawTileToBitmap] Tile ID=0x%02X at (%d,%d): palette=%d, pixel_index=%d, final_color=%d\n", + tile_info.id_, pixel_x, pixel_y, palette_id, pixel_index, final_color); + } } } } diff --git a/src/app/zelda3/dungeon/room.cc b/src/app/zelda3/dungeon/room.cc index c685aa09..ecba62b9 100644 --- a/src/app/zelda3/dungeon/room.cc +++ b/src/app/zelda3/dungeon/room.cc @@ -312,9 +312,9 @@ void Room::RenderRoomGraphics() { int palette_id = palette; if (palette_id < 0 || palette_id >= num_palettes) { - std::printf("5. WARNING: palette_id %d is out of bounds [0, %d), using palette 0\n", - palette_id, num_palettes); - palette_id = 0; + std::printf("5. WARNING: palette_id %d is out of bounds [0, %d), using palette %d\n", + palette_id, num_palettes, palette_id % num_palettes); + palette_id = palette_id % num_palettes; // Use modulo to wrap around instead of defaulting to 0 } auto bg1_palette = dungeon_pal_group[palette_id];