From 8481cd93661432beb4d8b0d2d1d06f29acdea58d Mon Sep 17 00:00:00 2001 From: scawful Date: Thu, 9 Oct 2025 23:50:12 -0400 Subject: [PATCH] refactor: Update Dungeon Rendering Logic for Enhanced Tile Management (WIP) - Refactored DungeonCanvasViewer to utilize LoadLayoutTilesToBuffer for rendering layout tiles, improving the separation of concerns in the rendering process. - Updated ObjectDrawer to draw using 8x8 tiles instead of 16x16, enhancing tile rendering accuracy and efficiency. - Modified Room and RoomLayoutObject classes to support room-specific graphics buffers, ensuring correct tile usage during rendering. - Removed legacy methods and classes related to tile handling, streamlining the codebase and improving maintainability. --- .../editor/dungeon/dungeon_canvas_viewer.cc | 28 +- src/app/zelda3/dungeon/object_drawer.cc | 321 +++++++++++------- src/app/zelda3/dungeon/object_drawer.h | 7 +- src/app/zelda3/dungeon/room.cc | 79 ++++- src/app/zelda3/dungeon/room.h | 1 + src/app/zelda3/dungeon/room_layout.cc | 44 ++- src/app/zelda3/dungeon/room_layout.h | 4 +- src/app/zelda3/dungeon/room_object.cc | 108 +----- src/app/zelda3/dungeon/room_object.h | 118 +------ 9 files changed, 348 insertions(+), 362 deletions(-) diff --git a/src/app/editor/dungeon/dungeon_canvas_viewer.cc b/src/app/editor/dungeon/dungeon_canvas_viewer.cc index e51d644e..91b5890a 100644 --- a/src/app/editor/dungeon/dungeon_canvas_viewer.cc +++ b/src/app/editor/dungeon/dungeon_canvas_viewer.cc @@ -393,8 +393,8 @@ std::pair DungeonCanvasViewer::CanvasToRoomCoordinates(int canvas_x, bool DungeonCanvasViewer::IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin) const { // Check if coordinates are within canvas bounds with optional margin - auto canvas_width = canvas_.width(); - auto canvas_height = canvas_.height(); + auto canvas_width = canvas_.width() * canvas_.global_scale(); + auto canvas_height = canvas_.height() * canvas_.global_scale(); return (canvas_x >= -margin && canvas_y >= -margin && canvas_x <= canvas_width + margin && canvas_y <= canvas_height + margin); @@ -606,7 +606,7 @@ absl::Status DungeonCanvasViewer::LoadAndRenderRoomGraphics(int room_id) { } void DungeonCanvasViewer::DrawRoomBackgroundLayers(int room_id) { - if (room_id < 0 || room_id >= 128 || !rooms_) return; + if (room_id < 0 || room_id >= zelda3::NumberOfRooms || !rooms_) return; auto& room = (*rooms_)[room_id]; auto& layer_settings = GetRoomLayerSettings(room_id); @@ -628,8 +628,10 @@ void DungeonCanvasViewer::DrawRoomBackgroundLayers(int room_id) { // Only draw if texture was successfully created if (bg1_bitmap.texture()) { - LOG_DEBUG("DungeonCanvasViewer", "Drawing BG1 bitmap to canvas with texture %p", bg1_bitmap.texture()); - canvas_.DrawBitmap(bg1_bitmap, 0, 0, 1.0f, 255); + // Use canvas global scale so bitmap scales with zoom + float scale = canvas_.global_scale(); + LOG_DEBUG("DungeonCanvasViewer", "Drawing BG1 bitmap to canvas with texture %p, scale=%.2f", bg1_bitmap.texture(), scale); + canvas_.DrawBitmap(bg1_bitmap, 0, 0, scale, 255); } else { LOG_DEBUG("DungeonCanvasViewer", "ERROR: BG1 bitmap has no texture!"); } @@ -651,8 +653,10 @@ void DungeonCanvasViewer::DrawRoomBackgroundLayers(int room_id) { // 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(layer_settings.bg2_layer_type, 4)]; - LOG_DEBUG("DungeonCanvasViewer", "Drawing BG2 bitmap to canvas with texture %p, alpha=%d", bg2_bitmap.texture(), alpha_value); - canvas_.DrawBitmap(bg2_bitmap, 0, 0, 1.0f, alpha_value); + // Use canvas global scale so bitmap scales with zoom + float scale = canvas_.global_scale(); + LOG_DEBUG("DungeonCanvasViewer", "Drawing BG2 bitmap to canvas with texture %p, alpha=%d, scale=%.2f", bg2_bitmap.texture(), alpha_value, scale); + canvas_.DrawBitmap(bg2_bitmap, 0, 0, scale, alpha_value); } else { LOG_DEBUG("DungeonCanvasViewer", "ERROR: BG2 bitmap has no texture!"); } @@ -686,17 +690,9 @@ void DungeonCanvasViewer::DrawRoomBackgroundLayers(int room_id) { bg2_data.size(), non_zero_pixels); } - // TEST: Draw a bright red rectangle to verify canvas drawing works - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); - draw_list->AddRectFilled( - 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 LOG_DEBUG("DungeonCanvasViewer", "Canvas pos: (%.1f, %.1f), Canvas size: (%.1f, %.1f)", - canvas_pos.x, canvas_pos.y, canvas_.canvas_size().x, canvas_.canvas_size().y); + canvas_.zero_point().x, canvas_.zero_point().y, canvas_.width(), canvas_.height()); LOG_DEBUG("DungeonCanvasViewer", "BG1 bitmap size: %dx%d, BG2 bitmap size: %dx%d", bg1_bitmap.width(), bg1_bitmap.height(), bg2_bitmap.width(), bg2_bitmap.height()); } diff --git a/src/app/zelda3/dungeon/object_drawer.cc b/src/app/zelda3/dungeon/object_drawer.cc index 07d75b01..d9397f2f 100644 --- a/src/app/zelda3/dungeon/object_drawer.cc +++ b/src/app/zelda3/dungeon/object_drawer.cc @@ -9,7 +9,8 @@ namespace yaze { namespace zelda3 { -ObjectDrawer::ObjectDrawer(Rom* rom) : rom_(rom) { +ObjectDrawer::ObjectDrawer(Rom* rom, const uint8_t* room_gfx_buffer) + : rom_(rom), room_gfx_buffer_(room_gfx_buffer) { InitializeDrawRoutines(); } @@ -54,8 +55,11 @@ absl::Status ObjectDrawer::DrawObject(const RoomObject& object, int routine_id = GetDrawRoutineId(object.id_); if (routine_id < 0 || routine_id >= static_cast(draw_routines_.size())) { - // Fallback to simple 1x1 drawing - WriteTile16(target_bg, object.x_, object.y_, mutable_obj.tiles()[0]); + // Fallback to simple 1x1 drawing using first 8x8 tile + if (!mutable_obj.tiles().empty()) { + const auto& tile16 = mutable_obj.tiles()[0]; + WriteTile8(target_bg, object.x_, object.y_, tile16.tile0_); + } return absl::OkStatus(); } @@ -245,11 +249,13 @@ void ObjectDrawer::DrawRightwards2x2_1to15or32(const RoomObject& obj, gfx::Backg if (size == 0) size = 32; // Special case for object 0x00 for (int s = 0; s < size; s++) { - if (tiles.size() >= 4) { - WriteTile16(bg, obj.x_ + (s * 2), obj.y_, tiles[0]); // Top-left - WriteTile16(bg, obj.x_ + (s * 2) + 1, obj.y_, tiles[1]); // Top-right - WriteTile16(bg, obj.x_ + (s * 2), obj.y_ + 1, tiles[2]); // Bottom-left - WriteTile16(bg, obj.x_ + (s * 2) + 1, obj.y_ + 1, tiles[3]); // Bottom-right + if (tiles.size() >= 1) { + // Draw 2x2 pattern using 8x8 tiles from the first Tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + (s * 2), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 2), obj.y_ + 1, tile16.tile2_); // Bottom-left + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_ + 1, tile16.tile3_); // Bottom-right } } } @@ -261,14 +267,18 @@ void ObjectDrawer::DrawRightwards2x4_1to15or26(const RoomObject& obj, gfx::Backg if (size == 0) size = 26; // Special case for (int s = 0; s < size; s++) { - if (tiles.size() >= 8) { - // Draw 2x4 pattern - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 2; x++) { - int tile_index = y * 2 + x; - WriteTile16(bg, obj.x_ + (s * 2) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Draw 2x4 pattern using 8x8 tiles from the first Tile16 + const auto& tile16 = tiles[0]; + // For 2x4, we'll use the same tile16 pattern repeated + WriteTile8(bg, obj.x_ + (s * 2), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 2), obj.y_ + 1, tile16.tile2_); // Mid-left + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_ + 1, tile16.tile3_); // Mid-right + WriteTile8(bg, obj.x_ + (s * 2), obj.y_ + 2, tile16.tile0_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_ + 2, tile16.tile1_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 2), obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) } } } @@ -279,14 +289,17 @@ void ObjectDrawer::DrawRightwards2x4spaced4_1to16(const RoomObject& obj, gfx::Ba int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 8) { - // Draw 2x4 pattern with spacing - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 2; x++) { - int tile_index = y * 2 + x; - WriteTile16(bg, obj.x_ + (s * 6) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Draw 2x4 pattern with spacing using 8x8 tiles from first Tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + (s * 6), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 1, tile16.tile2_); // Mid-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 1, tile16.tile3_); // Mid-right + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 2, tile16.tile0_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 2, tile16.tile1_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) } } } @@ -304,11 +317,13 @@ void ObjectDrawer::DrawRightwards2x2_1to16(const RoomObject& obj, gfx::Backgroun int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 4) { - WriteTile16(bg, obj.x_ + (s * 2), obj.y_, tiles[0]); - WriteTile16(bg, obj.x_ + (s * 2) + 1, obj.y_, tiles[1]); - WriteTile16(bg, obj.x_ + (s * 2), obj.y_ + 1, tiles[2]); - WriteTile16(bg, obj.x_ + (s * 2) + 1, obj.y_ + 1, tiles[3]); + if (tiles.size() >= 1) { + // Draw 2x2 pattern using 8x8 tiles from first Tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + (s * 2), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 2), obj.y_ + 1, tile16.tile2_); // Bottom-left + WriteTile8(bg, obj.x_ + (s * 2) + 1, obj.y_ + 1, tile16.tile3_); // Bottom-right } } } @@ -319,9 +334,15 @@ void ObjectDrawer::DrawDiagonalAcute_1to16(const RoomObject& obj, gfx::Backgroun int size = obj.size_ & 0x0F; for (int s = 0; s < size + 6; s++) { - if (tiles.size() >= 5) { + if (tiles.size() >= 1) { + // Use first tile16 for diagonal pattern + const auto& tile16 = tiles[0]; for (int i = 0; i < 5; i++) { - WriteTile16(bg, obj.x_ + s, obj.y_ + (i - s), tiles[i]); + // Cycle through the 4 tiles in the tile16 + const gfx::TileInfo& tile_info = (i % 4 == 0) ? tile16.tile0_ : + (i % 4 == 1) ? tile16.tile1_ : + (i % 4 == 2) ? tile16.tile2_ : tile16.tile3_; + WriteTile8(bg, obj.x_ + s, obj.y_ + (i - s), tile_info); } } } @@ -333,9 +354,15 @@ void ObjectDrawer::DrawDiagonalGrave_1to16(const RoomObject& obj, gfx::Backgroun int size = obj.size_ & 0x0F; for (int s = 0; s < size + 6; s++) { - if (tiles.size() >= 5) { + if (tiles.size() >= 1) { + // Use first tile16 for diagonal pattern + const auto& tile16 = tiles[0]; for (int i = 0; i < 5; i++) { - WriteTile16(bg, obj.x_ + s, obj.y_ + (i + s), tiles[i]); + // Cycle through the 4 tiles in the tile16 + const gfx::TileInfo& tile_info = (i % 4 == 0) ? tile16.tile0_ : + (i % 4 == 1) ? tile16.tile1_ : + (i % 4 == 2) ? tile16.tile2_ : tile16.tile3_; + WriteTile8(bg, obj.x_ + s, obj.y_ + (i + s), tile_info); } } } @@ -359,9 +386,11 @@ void ObjectDrawer::DrawRightwards1x2_1to16_plus2(const RoomObject& obj, gfx::Bac int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 2) { - WriteTile16(bg, obj.x_ + s + 2, obj.y_, tiles[0]); - WriteTile16(bg, obj.x_ + s + 2, obj.y_ + 1, tiles[1]); + if (tiles.size() >= 1) { + // Use first tile16 for 1x2 pattern + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + s + 2, obj.y_, tile16.tile0_); + WriteTile8(bg, obj.x_ + s + 2, obj.y_ + 1, tile16.tile2_); } } } @@ -373,7 +402,9 @@ void ObjectDrawer::DrawRightwardsHasEdge1x1_1to16_plus3(const RoomObject& obj, g for (int s = 0; s < size; s++) { if (tiles.size() >= 1) { - WriteTile16(bg, obj.x_ + s + 3, obj.y_, tiles[0]); + // Use first 8x8 tile from first tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + s + 3, obj.y_, tile16.tile0_); } } } @@ -385,7 +416,9 @@ void ObjectDrawer::DrawRightwardsHasEdge1x1_1to16_plus2(const RoomObject& obj, g for (int s = 0; s < size; s++) { if (tiles.size() >= 1) { - WriteTile16(bg, obj.x_ + s + 2, obj.y_, tiles[0]); + // Use first 8x8 tile from first tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + s + 2, obj.y_, tile16.tile0_); } } } @@ -396,9 +429,11 @@ void ObjectDrawer::DrawRightwardsTopCorners1x2_1to16_plus13(const RoomObject& ob int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 2) { - WriteTile16(bg, obj.x_ + s + 13, obj.y_, tiles[0]); - WriteTile16(bg, obj.x_ + s + 13, obj.y_ + 1, tiles[1]); + if (tiles.size() >= 1) { + // Use first tile16 for 1x2 pattern + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + s + 13, obj.y_, tile16.tile0_); + WriteTile8(bg, obj.x_ + s + 13, obj.y_ + 1, tile16.tile2_); } } } @@ -409,9 +444,11 @@ void ObjectDrawer::DrawRightwardsBottomCorners1x2_1to16_plus13(const RoomObject& int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 2) { - WriteTile16(bg, obj.x_ + s + 13, obj.y_ + 1, tiles[0]); - WriteTile16(bg, obj.x_ + s + 13, obj.y_ + 2, tiles[1]); + if (tiles.size() >= 1) { + // Use first tile16 for 1x2 pattern + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + s + 13, obj.y_ + 1, tile16.tile0_); + WriteTile8(bg, obj.x_ + s + 13, obj.y_ + 2, tile16.tile2_); } } } @@ -421,7 +458,9 @@ void ObjectDrawer::CustomDraw(const RoomObject& obj, gfx::BackgroundBuffer& bg, // Pattern: Custom draw routine (objects 0x31-0x32) // For now, fall back to simple 1x1 if (tiles.size() >= 1) { - WriteTile16(bg, obj.x_, obj.y_, tiles[0]); + // Use first 8x8 tile from first tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_, obj.y_, tile16.tile0_); } } @@ -431,14 +470,26 @@ void ObjectDrawer::DrawRightwards4x4_1to16(const RoomObject& obj, gfx::Backgroun int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 16) { - // Draw 4x4 block - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - int tile_index = y * 4 + x; - WriteTile16(bg, obj.x_ + (s * 4) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Use first tile16 for 4x4 pattern (repeat the 2x2 pattern) + const auto& tile16 = tiles[0]; + // Draw 2x2 pattern repeated to make 4x4 + WriteTile8(bg, obj.x_ + (s * 4), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 4), obj.y_ + 1, tile16.tile2_); // Bottom-left + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_ + 1, tile16.tile3_); // Bottom-right + WriteTile8(bg, obj.x_ + (s * 4) + 2, obj.y_, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 3, obj.y_, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 2, obj.y_ + 1, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 3, obj.y_ + 1, tile16.tile3_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 4), obj.y_ + 2, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_ + 2, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 4), obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 2, obj.y_ + 2, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 3, obj.y_ + 2, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 2, obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 3, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) } } } @@ -450,7 +501,9 @@ void ObjectDrawer::DrawRightwards1x1Solid_1to16_plus3(const RoomObject& obj, gfx for (int s = 0; s < size; s++) { if (tiles.size() >= 1) { - WriteTile16(bg, obj.x_ + s + 3, obj.y_, tiles[0]); + // Use first 8x8 tile from first tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_ + s + 3, obj.y_, tile16.tile0_); } } } @@ -460,7 +513,9 @@ void ObjectDrawer::DrawDoorSwitcherer(const RoomObject& obj, gfx::BackgroundBuff // Pattern: Door switcher (object 0x35) // Special door logic - simplified for now if (tiles.size() >= 1) { - WriteTile16(bg, obj.x_, obj.y_, tiles[0]); + // Use first 8x8 tile from first tile16 + const auto& tile16 = tiles[0]; + WriteTile8(bg, obj.x_, obj.y_, tile16.tile0_); } } @@ -470,14 +525,26 @@ void ObjectDrawer::DrawRightwardsDecor4x4spaced2_1to16(const RoomObject& obj, gf int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 16) { - // Draw 4x4 block with spacing - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - int tile_index = y * 4 + x; - WriteTile16(bg, obj.x_ + (s * 6) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Use first tile16 for 4x4 pattern with spacing + const auto& tile16 = tiles[0]; + // Draw 2x2 pattern repeated to make 4x4 with spacing + WriteTile8(bg, obj.x_ + (s * 6), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 1, tile16.tile2_); // Bottom-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 1, tile16.tile3_); // Bottom-right + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_ + 1, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_ + 1, tile16.tile3_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 2, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 2, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_ + 2, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_ + 2, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) } } } @@ -488,14 +555,16 @@ void ObjectDrawer::DrawRightwardsStatue2x3spaced2_1to16(const RoomObject& obj, g int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 6) { - // Draw 2x3 statue - for (int y = 0; y < 3; y++) { - for (int x = 0; x < 2; x++) { - int tile_index = y * 2 + x; - WriteTile16(bg, obj.x_ + (s * 4) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Use first tile16 for 2x3 statue pattern + const auto& tile16 = tiles[0]; + // Draw 2x3 pattern using 8x8 tiles + WriteTile8(bg, obj.x_ + (s * 4), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 4), obj.y_ + 1, tile16.tile2_); // Mid-left + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_ + 1, tile16.tile3_); // Mid-right + WriteTile8(bg, obj.x_ + (s * 4), obj.y_ + 2, tile16.tile0_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 4) + 1, obj.y_ + 2, tile16.tile1_); // Bottom-right (repeat) } } } @@ -506,14 +575,18 @@ void ObjectDrawer::DrawRightwardsPillar2x4spaced4_1to16(const RoomObject& obj, g int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 8) { - // Draw 2x4 pillar - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 2; x++) { - int tile_index = y * 2 + x; - WriteTile16(bg, obj.x_ + (s * 6) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Use first tile16 for 2x4 pillar pattern + const auto& tile16 = tiles[0]; + // Draw 2x4 pattern using 8x8 tiles + WriteTile8(bg, obj.x_ + (s * 6), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 1, tile16.tile2_); // Mid-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 1, tile16.tile3_); // Mid-right + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 2, tile16.tile0_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 2, tile16.tile1_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 3, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 3, tile16.tile3_); // Bottom-right (repeat) } } } @@ -524,14 +597,22 @@ void ObjectDrawer::DrawRightwardsDecor4x3spaced4_1to16(const RoomObject& obj, gf int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 12) { - // Draw 4x3 decoration - for (int y = 0; y < 3; y++) { - for (int x = 0; x < 4; x++) { - int tile_index = y * 4 + x; - WriteTile16(bg, obj.x_ + (s * 6) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Use first tile16 for 4x3 decoration pattern + const auto& tile16 = tiles[0]; + // Draw 4x3 pattern using 8x8 tiles + WriteTile8(bg, obj.x_ + (s * 6), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 1, tile16.tile2_); // Mid-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 1, tile16.tile3_); // Mid-right + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_ + 1, tile16.tile2_); // Mid-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_ + 1, tile16.tile3_); // Mid-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 2, tile16.tile0_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 2, tile16.tile1_); // Bottom-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_ + 2, tile16.tile0_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_ + 2, tile16.tile1_); // Bottom-right (repeat) } } } @@ -542,14 +623,18 @@ void ObjectDrawer::DrawRightwardsDoubled2x2spaced2_1to16(const RoomObject& obj, int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 8) { - // Draw doubled 2x2 pattern - for (int y = 0; y < 2; y++) { - for (int x = 0; x < 4; x++) { - int tile_index = y * 4 + x; - WriteTile16(bg, obj.x_ + (s * 6) + x, obj.y_ + y, tiles[tile_index]); - } - } + if (tiles.size() >= 1) { + // Use first tile16 for doubled 2x2 pattern + const auto& tile16 = tiles[0]; + // Draw doubled 2x2 pattern using 8x8 tiles + WriteTile8(bg, obj.x_ + (s * 6), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_, tile16.tile0_); // Top-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_, tile16.tile1_); // Top-right (repeat) + WriteTile8(bg, obj.x_ + (s * 6), obj.y_ + 1, tile16.tile2_); // Bottom-left + WriteTile8(bg, obj.x_ + (s * 6) + 1, obj.y_ + 1, tile16.tile3_); // Bottom-right + WriteTile8(bg, obj.x_ + (s * 6) + 2, obj.y_ + 1, tile16.tile2_); // Bottom-left (repeat) + WriteTile8(bg, obj.x_ + (s * 6) + 3, obj.y_ + 1, tile16.tile3_); // Bottom-right (repeat) } } } @@ -560,12 +645,14 @@ void ObjectDrawer::DrawRightwardsDecor2x2spaced12_1to16(const RoomObject& obj, g int size = obj.size_ & 0x0F; for (int s = 0; s < size; s++) { - if (tiles.size() >= 4) { - // Draw 2x2 decoration with 12-tile spacing - WriteTile16(bg, obj.x_ + (s * 14), obj.y_, tiles[0]); - WriteTile16(bg, obj.x_ + (s * 14) + 1, obj.y_, tiles[1]); - WriteTile16(bg, obj.x_ + (s * 14), obj.y_ + 1, tiles[2]); - WriteTile16(bg, obj.x_ + (s * 14) + 1, obj.y_ + 1, tiles[3]); + if (tiles.size() >= 1) { + // Use first tile16 for 2x2 decoration with large spacing + const auto& tile16 = tiles[0]; + // Draw 2x2 decoration with 12-tile spacing using 8x8 tiles + WriteTile8(bg, obj.x_ + (s * 14), obj.y_, tile16.tile0_); // Top-left + WriteTile8(bg, obj.x_ + (s * 14) + 1, obj.y_, tile16.tile1_); // Top-right + WriteTile8(bg, obj.x_ + (s * 14), obj.y_ + 1, tile16.tile2_); // Bottom-left + WriteTile8(bg, obj.x_ + (s * 14) + 1, obj.y_ + 1, tile16.tile3_); // Bottom-right } } } @@ -574,9 +661,9 @@ void ObjectDrawer::DrawRightwardsDecor2x2spaced12_1to16(const RoomObject& obj, g // Utility Methods // ============================================================================ -void ObjectDrawer::WriteTile16(gfx::BackgroundBuffer& bg, int tile_x, int tile_y, - const gfx::Tile16& tile) { - LOG_DEBUG("ObjectDrawer", "Writing Tile16 at tile pos (%d,%d) to bitmap", tile_x, tile_y); +void ObjectDrawer::WriteTile8(gfx::BackgroundBuffer& bg, int tile_x, int tile_y, + const gfx::TileInfo& tile_info) { + LOG_DEBUG("ObjectDrawer", "Writing 8x8 tile at tile pos (%d,%d) to bitmap", tile_x, tile_y); // Draw directly to bitmap instead of tile buffer to avoid being overwritten auto& bitmap = bg.bitmap(); @@ -587,21 +674,27 @@ void ObjectDrawer::WriteTile16(gfx::BackgroundBuffer& bg, int tile_x, int tile_y return; // Bitmap not ready } - // Get graphics data from ROM - if (!rom_ || !rom_->is_loaded()) { - return; + // Get graphics data - prefer room-specific buffer if available + const uint8_t* gfx_data = nullptr; + + if (room_gfx_buffer_) { + // Use room-specific graphics buffer (current_gfx16_) + gfx_data = room_gfx_buffer_; + } else if (rom_ && rom_->is_loaded()) { + // Fallback to ROM graphics buffer + auto rom_gfx = rom_->mutable_graphics_buffer(); + if (rom_gfx && !rom_gfx->empty()) { + gfx_data = rom_gfx->data(); + } } - auto gfx_data = rom_->mutable_graphics_buffer(); - if (!gfx_data || gfx_data->empty()) { + if (!gfx_data) { + LOG_DEBUG("ObjectDrawer", "ERROR: No graphics data available"); return; } - // Draw each 8x8 tile directly to bitmap - DrawTileToBitmap(bitmap, tile.tile0_, tile_x * 8, tile_y * 8, gfx_data->data()); - DrawTileToBitmap(bitmap, tile.tile1_, (tile_x + 1) * 8, tile_y * 8, gfx_data->data()); - DrawTileToBitmap(bitmap, tile.tile2_, tile_x * 8, (tile_y + 1) * 8, gfx_data->data()); - DrawTileToBitmap(bitmap, tile.tile3_, (tile_x + 1) * 8, (tile_y + 1) * 8, gfx_data->data()); + // Draw single 8x8 tile directly to bitmap + DrawTileToBitmap(bitmap, tile_info, tile_x * 8, tile_y * 8, gfx_data); } bool ObjectDrawer::IsValidTilePosition(int tile_x, int tile_y) const { diff --git a/src/app/zelda3/dungeon/object_drawer.h b/src/app/zelda3/dungeon/object_drawer.h index e3f57c7e..a74a15eb 100644 --- a/src/app/zelda3/dungeon/object_drawer.h +++ b/src/app/zelda3/dungeon/object_drawer.h @@ -31,7 +31,7 @@ namespace zelda3 { */ class ObjectDrawer { public: - explicit ObjectDrawer(Rom* rom); + explicit ObjectDrawer(Rom* rom, const uint8_t* room_gfx_buffer = nullptr); /** * @brief Draw a room object to background buffers @@ -139,8 +139,8 @@ class ObjectDrawer { const std::vector& tiles); // Utility methods - void WriteTile16(gfx::BackgroundBuffer& bg, int tile_x, int tile_y, - const gfx::Tile16& tile); + void WriteTile8(gfx::BackgroundBuffer& bg, int tile_x, int tile_y, + const gfx::TileInfo& tile_info); bool IsValidTilePosition(int tile_x, int tile_y) const; // Draw routine registry @@ -149,6 +149,7 @@ class ObjectDrawer { bool routines_initialized_ = false; Rom* rom_; + const uint8_t* room_gfx_buffer_; // Room-specific graphics buffer (current_gfx16_) // Canvas dimensions in tiles (64x64 = 512x512 pixels) static constexpr int kMaxTilesX = 64; diff --git a/src/app/zelda3/dungeon/room.cc b/src/app/zelda3/dungeon/room.cc index 5d0624cf..42329c94 100644 --- a/src/app/zelda3/dungeon/room.cc +++ b/src/app/zelda3/dungeon/room.cc @@ -292,12 +292,17 @@ void Room::RenderRoomGraphics() { // LoadGraphicsSheetsIntoArena() removed - using per-room graphics instead // Arena sheets are optional and not needed for room rendering + // STEP 1: Draw floor tiles to bitmaps (base layer) bg1_buffer_.DrawFloor(rom()->vector(), tile_address, tile_address_floor, floor1_graphics_); bg2_buffer_.DrawFloor(rom()->vector(), tile_address, tile_address_floor, floor2_graphics_); - // Draw background tiles (floor, walls, etc.) to buffers + // STEP 2: Load layout tiles into tile buffer before DrawBackground + // This populates the buffer with wall/structure tiles from the layout + LoadLayoutTilesToBuffer(); + + // STEP 3: Draw background tiles (walls from layout) to buffers bg1_buffer_.DrawBackground(std::span(current_gfx16_)); bg2_buffer_.DrawBackground(std::span(current_gfx16_)); @@ -372,7 +377,7 @@ void Room::RenderObjectsToBackground() { if (!palette_group_result.ok()) { // Fallback to empty palette group gfx::PaletteGroup empty_group; - ObjectDrawer drawer(rom_); + ObjectDrawer drawer(rom_, current_gfx16_.data()); drawer.DrawObjectList(tile_objects_, bg1_buffer_, bg2_buffer_, empty_group); return; } @@ -380,7 +385,8 @@ void Room::RenderObjectsToBackground() { // Use ObjectDrawer for pattern-based object rendering // This provides proper wall/object drawing patterns - ObjectDrawer drawer(rom_); + // Pass the room-specific graphics buffer (current_gfx16_) so objects use correct tiles + ObjectDrawer drawer(rom_, current_gfx16_.data()); auto status = drawer.DrawObjectList(tile_objects_, bg1_buffer_, bg2_buffer_, palette_group); // Log only failures, not successes @@ -858,6 +864,73 @@ void Room::LoadRoomLayout() { layout = static_cast(room_id_ & 0xFF); } +void Room::LoadLayoutTilesToBuffer() { + // Load layout tiles into the BackgroundBuffer tile buffers + // This populates the buffer with wall/structure tile IDs from the layout + + LOG_DEBUG("RenderRoomGraphics", "LoadLayoutTilesToBuffer START for room %d", room_id_); + + if (!rom_ || !rom_->is_loaded()) { + LOG_DEBUG("RenderRoomGraphics", "ROM not loaded, aborting"); + return; + } + + // Get layout data + auto& layout_objects = layout_.GetObjects(); + LOG_DEBUG("RenderRoomGraphics", "Layout has %zu objects", layout_objects.size()); + + if (layout_objects.empty()) { + LOG_DEBUG("RenderRoomGraphics", "No layout objects for room %d", room_id_); + return; + } + + int tiles_written_bg1 = 0; + int tiles_written_bg2 = 0; + int tiles_skipped = 0; + + // Write each layout object's tile to the appropriate buffer + for (const auto& layout_obj : layout_objects) { + uint8_t x = layout_obj.x(); + uint8_t y = layout_obj.y(); + + // Get the tile16 for this layout object, passing room graphics buffer + auto tile_result = layout_obj.GetTile(current_gfx16_.data()); + if (!tile_result.ok()) { + tiles_skipped++; + continue; // Skip objects that don't have valid tiles + } + + auto& tile16 = tile_result.value(); + + // Convert Tile16 to a 16-bit tile ID word (use first tile) + uint16_t tile_word = gfx::TileInfoToWord(tile16.tile0_); + + // Debug first few tiles to verify data + if (tiles_written_bg1 + tiles_written_bg2 < 5) { + LOG_DEBUG("RenderRoomGraphics", "Layout tile[%d] at (%d,%d): ID=0x%04X, palette=%d, type=%d, layer=%d", + tiles_written_bg1 + tiles_written_bg2, x, y, tile16.tile0_.id_, tile16.tile0_.palette_, + static_cast(layout_obj.type()), layout_obj.layer()); + } + + // Determine which buffer based on layer + auto* target_buffer = &bg1_buffer_; + if (layout_obj.layer() == 1) { + target_buffer = &bg2_buffer_; + tiles_written_bg2++; + } else { + tiles_written_bg1++; + } + + // Write tile ID to buffer at position (x, y) + if (x < 64 && y < 64) { // 64x64 tiles = 512x512 pixels + target_buffer->SetTileAt(x, y, tile_word); + } + } + + LOG_DEBUG("RenderRoomGraphics", "Wrote %d BG1 tiles, %d BG2 tiles, skipped %d", + tiles_written_bg1, tiles_written_bg2, tiles_skipped); +} + void Room::LoadDoors() { auto rom_data = rom()->vector(); diff --git a/src/app/zelda3/dungeon/room.h b/src/app/zelda3/dungeon/room.h index ef65cf0a..04a3f2ec 100644 --- a/src/app/zelda3/dungeon/room.h +++ b/src/app/zelda3/dungeon/room.h @@ -194,6 +194,7 @@ class Room { void LoadSprites(); void LoadChests(); void LoadRoomLayout(); + void LoadLayoutTilesToBuffer(); // NEW: Write layout tiles to BG tile buffers void LoadDoors(); void LoadTorches(); void LoadBlocks(); diff --git a/src/app/zelda3/dungeon/room_layout.cc b/src/app/zelda3/dungeon/room_layout.cc index 661e6136..b0bc7804 100644 --- a/src/app/zelda3/dungeon/room_layout.cc +++ b/src/app/zelda3/dungeon/room_layout.cc @@ -7,18 +7,48 @@ namespace yaze { namespace zelda3 { -absl::StatusOr RoomLayoutObject::GetTile() const { - // This would typically look up the actual tile data from the graphics sheets - // For now, we'll create a placeholder tile based on the object type - +absl::StatusOr RoomLayoutObject::GetTile(const uint8_t* room_gfx_buffer) const { + // Map layout code to actual VRAM tile ID + // Layout codes (id_) are indices into a layout tilemap + // The actual tile graphics are in the room's graphics buffer + + // For dungeon layouts, the tile ID from the layout data directly maps to + // a tile in the room's graphics sheets (current_gfx16_) + // Layout codes typically range from 0x00 to 0xFF + + // Use the layout code directly as tile ID + // The palette will be determined by the tile's position and room palette + uint16_t tile_id = static_cast(id_); + + // Determine palette based on object type + uint8_t palette = 0; + switch (type_) { + case Type::kWall: + palette = 2; // Walls typically use palette 2 + break; + case Type::kFloor: + palette = 0; // Floors use palette 0 + break; + case Type::kWater: + palette = 4; // Water uses palette 4 + break; + case Type::kDoor: + palette = 3; // Doors use palette 3 + break; + default: + palette = 0; + break; + } + gfx::TileInfo tile_info; - tile_info.id_ = static_cast(id_); - tile_info.palette_ = 0; // Default palette + tile_info.id_ = tile_id; + tile_info.palette_ = palette; tile_info.vertical_mirror_ = false; tile_info.horizontal_mirror_ = false; tile_info.over_ = false; - // Create a 16x16 tile with the same tile info for all 4 sub-tiles + // Create a Tile16 with the same 8x8 tile in all 4 positions + // This makes the layout tile appear as a single repeated pattern return gfx::Tile16(tile_info, tile_info, tile_info, tile_info); } diff --git a/src/app/zelda3/dungeon/room_layout.h b/src/app/zelda3/dungeon/room_layout.h index 7ddf9e5e..1f77ef0a 100644 --- a/src/app/zelda3/dungeon/room_layout.h +++ b/src/app/zelda3/dungeon/room_layout.h @@ -51,7 +51,9 @@ class RoomLayoutObject { void set_layer(uint8_t layer) { layer_ = layer; } // Get tile data for this layout object - absl::StatusOr GetTile() const; + // NOTE: Layout codes need to be mapped to actual VRAM tile IDs + // The room_gfx_buffer provides the assembled graphics for this specific room + absl::StatusOr GetTile(const uint8_t* room_gfx_buffer = nullptr) const; // Get the name/description of this layout object type std::string GetTypeName() const; diff --git a/src/app/zelda3/dungeon/room_object.cc b/src/app/zelda3/dungeon/room_object.cc index 31741660..4406e3c7 100644 --- a/src/app/zelda3/dungeon/room_object.cc +++ b/src/app/zelda3/dungeon/room_object.cc @@ -46,112 +46,8 @@ ObjectOption operator~(ObjectOption option) { return static_cast(~static_cast(option)); } -SubtypeInfo FetchSubtypeInfo(uint16_t object_id) { - SubtypeInfo info; - - // TODO: Determine the subtype based on object_id - uint8_t subtype = 1; - - switch (subtype) { - case 1: // Subtype 1 - info.subtype_ptr = kRoomObjectSubtype1 + (object_id & 0xFF) * 2; - info.routine_ptr = kRoomObjectSubtype1 + 0x200 + (object_id & 0xFF) * 2; - break; - case 2: // Subtype 2 - info.subtype_ptr = kRoomObjectSubtype2 + (object_id & 0x7F) * 2; - info.routine_ptr = kRoomObjectSubtype2 + 0x80 + (object_id & 0x7F) * 2; - break; - case 3: // Subtype 3 - info.subtype_ptr = kRoomObjectSubtype3 + (object_id & 0xFF) * 2; - info.routine_ptr = kRoomObjectSubtype3 + 0x100 + (object_id & 0xFF) * 2; - break; - default: - throw std::runtime_error("Invalid object subtype"); - } - - return info; -} - -void RoomObject::DrawTile(gfx::Tile16 t, int xx, int yy, - std::vector& current_gfx16, - std::vector& tiles_bg1_buffer, - std::vector& tiles_bg2_buffer, - uint16_t tileUnder) { - bool preview = false; - if (width_ < xx + 8) { - width_ = xx + 8; - } - if (height_ < yy + 8) { - height_ = yy + 8; - } - if (preview) { - if (xx < 0x39 && yy < 0x39 && xx >= 0 && yy >= 0) { - gfx::TileInfo ti = t.tile0_; // t.GetTileInfo(); - for (auto yl = 0; yl < 8; yl++) { - for (auto xl = 0; xl < 4; xl++) { - int mx = xl; - int my = yl; - uint8_t r = 0; - - if (ti.horizontal_mirror_) { - mx = 3 - xl; - r = 1; - } - if (ti.vertical_mirror_) { - my = 7 - yl; - } - - // Formula information to get tile index position in the array. - //((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) )) - int tx = ((ti.id_ / 0x10) * 0x200) + - ((ti.id_ - ((ti.id_ / 0x10) * 0x10)) * 4); - auto pixel = current_gfx16[tx + (yl * 0x40) + xl]; - // nx,ny = object position, xx,yy = tile position, xl,yl = pixel - // position - - int index = - ((xx / 8) * 8) + ((yy / 8) * 0x200) + ((mx * 2) + (my * 0x40)); - preview_object_data_[index + r ^ 1] = - (uint8_t)((pixel & 0x0F) + ti.palette_ * 0x10); - preview_object_data_[index + r] = - (uint8_t)(((pixel >> 4) & 0x0F) + ti.palette_ * 0x10); - } - } - } - } else { - if (((xx / 8) + nx_ + offset_x_) + ((ny_ + offset_y_ + (yy / 8)) * 0x40) < - 0x1000 && - ((xx / 8) + nx_ + offset_x_) + ((ny_ + offset_y_ + (yy / 8)) * 0x40) >= - 0) { - uint16_t td = 0; // gfx::GetTilesInfo(); - - // collisionPoint.Add( - // new Point(xx + ((nx + offsetX) * 8), yy + ((ny + +offsetY) * 8))); - - if (layer_ == 0 || (uint8_t)layer_ == 2 || all_bgs_) { - if (tileUnder == - tiles_bg1_buffer[((xx / 8) + offset_x_ + nx_) + - ((ny_ + offset_y_ + (yy / 8)) * 0x40)]) { - return; - } - - tiles_bg1_buffer[((xx / 8) + offset_x_ + nx_) + - ((ny_ + offset_y_ + (yy / 8)) * 0x40)] = td; - } - - if ((uint8_t)layer_ == 1 || all_bgs_) { - if (tileUnder == - tiles_bg2_buffer[((xx / 8) + nx_ + offset_x_) + - ((ny_ + offset_y_ + (yy / 8)) * 0x40)]) { - return; - } - - tiles_bg2_buffer[((xx / 8) + nx_ + offset_x_) + - ((ny_ + offset_y_ + (yy / 8)) * 0x40)] = td; - } - } - } -} +// NOTE: DrawTile was legacy ZScream code that is no longer used. +// Modern rendering uses ObjectDrawer which draws directly to BackgroundBuffer bitmaps. void RoomObject::EnsureTilesLoaded() { LOG_DEBUG("RoomObject", "Object ID=0x%02X, tiles_loaded=%d", id_, tiles_loaded_); diff --git a/src/app/zelda3/dungeon/room_object.h b/src/app/zelda3/dungeon/room_object.h index df11f82d..15139479 100644 --- a/src/app/zelda3/dungeon/room_object.h +++ b/src/app/zelda3/dungeon/room_object.h @@ -12,13 +12,6 @@ namespace yaze { namespace zelda3 { -struct SubtypeInfo { - uint32_t subtype_ptr; - uint32_t routine_ptr; -}; - -SubtypeInfo FetchSubtypeInfo(uint16_t object_id); - enum class SpecialObjectType { Chest, BigChest, InterroomStairs }; enum Sorting { @@ -132,27 +125,9 @@ class RoomObject { // ============================================================================ - void AddTiles(int nbr, int pos) { - // Reads nbr Tile16 entries from ROM object data starting at pos (8 bytes per Tile16) - for (int i = 0; i < nbr; i++) { - int tpos = pos + (i * 8); - auto rom_data = rom()->data(); - if (tpos + 7 >= (int)rom()->size()) break; - uint16_t w0 = (uint16_t)(rom_data[tpos] | (rom_data[tpos + 1] << 8)); - uint16_t w1 = (uint16_t)(rom_data[tpos + 2] | (rom_data[tpos + 3] << 8)); - uint16_t w2 = (uint16_t)(rom_data[tpos + 4] | (rom_data[tpos + 5] << 8)); - uint16_t w3 = (uint16_t)(rom_data[tpos + 6] | (rom_data[tpos + 7] << 8)); - gfx::Tile16 tile(gfx::WordToTileInfo(w0), gfx::WordToTileInfo(w1), - gfx::WordToTileInfo(w2), gfx::WordToTileInfo(w3)); - tiles_.push_back(tile); - } - } - - void DrawTile(gfx::Tile16 t, int xx, int yy, - std::vector& current_gfx16, - std::vector& tiles_bg1_buffer, - std::vector& tiles_bg2_buffer, - uint16_t tile_under = 0xFFFF); + // NOTE: Legacy ZScream methods removed. Modern rendering uses: + // - ObjectParser for loading tiles from ROM + // - ObjectDrawer for rendering tiles to BackgroundBuffer auto options() const { return options_; } void set_options(ObjectOption options) { options_ = options; } @@ -197,90 +172,9 @@ class RoomObject { Rom* rom_; }; -class Subtype1 : public RoomObject { - public: - bool all_bgs; - int tile_count_; - std::string name; - Sorting sort; - - Subtype1(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer, - int tile_count) - : RoomObject(id, x, y, size, layer), tile_count_(tile_count) { - auto rom_data = rom()->data(); - int pos = kRoomObjectTileAddress + - static_cast( - (rom_data[kRoomObjectSubtype1 + ((id & 0xFF) * 2) + 1] << 8) + - rom_data[kRoomObjectSubtype1 + ((id & 0xFF) * 2)]); - AddTiles(tile_count_, pos); - sort = (Sorting)(Sorting::Horizontal | Sorting::Wall); - } - - void Draw(std::vector& current_gfx16, - std::vector& tiles_bg1_buffer, - std::vector& tiles_bg2_buffer) { - for (int s = 0; s < size_ + (tile_count_ == 8 ? 1 : 0); s++) { - for (int i = 0; i < tile_count_; i++) { - DrawTile(tiles_[i], ((s * 2)) * 8, (i / 2) * 8, current_gfx16, - tiles_bg1_buffer, tiles_bg2_buffer); - } - } - } -}; - -class Subtype2 : public RoomObject { - public: - std::string name; - bool all_bgs; - Sorting sort; - - Subtype2(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer) - : RoomObject(id, x, y, size, layer) { - auto rom_data = rom()->data(); - int pos = kRoomObjectTileAddress + - static_cast( - (rom_data[kRoomObjectSubtype2 + ((id & 0x7F) * 2) + 1] << 8) + - rom_data[kRoomObjectSubtype2 + ((id & 0x7F) * 2)]); - AddTiles(8, pos); - sort = (Sorting)(Sorting::Horizontal | Sorting::Wall); - } - - void Draw(std::vector& current_gfx16, - std::vector& tiles_bg1_buffer, - std::vector& tiles_bg2_buffer) { - for (int i = 0; i < 8; i++) { - DrawTile(tiles_[i], x_ * 8, (y_ + i) * 8, current_gfx16, tiles_bg1_buffer, - tiles_bg2_buffer); - } - } -}; - -class Subtype3 : public RoomObject { - public: - bool all_bgs; - std::string name; - Sorting sort; - - Subtype3(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer) - : RoomObject(id, x, y, size, layer) { - auto rom_data = rom()->data(); - int pos = kRoomObjectTileAddress + - static_cast( - (rom_data[kRoomObjectSubtype3 + ((id & 0xFF) * 2) + 1] << 8) + - rom_data[kRoomObjectSubtype3 + ((id & 0xFF) * 2)]); - AddTiles(8, pos); - sort = (Sorting)(Sorting::Horizontal | Sorting::Wall); - } - - void Draw(std::vector& current_gfx16, - std::vector& tiles_bg1_buffer, - std::vector& tiles_bg2_buffer) { - for (int i = 0; i < 8; i++) { - DrawTile(tiles_[i], x_ * 8, (y_ + i) * 8, current_gfx16, tiles_bg1_buffer, - tiles_bg2_buffer); - } - } -}; +// NOTE: Legacy Subtype1, Subtype2, Subtype3 classes removed. +// These were ported from ZScream but are no longer used. +// Modern code uses: ObjectParser + ObjectDrawer + ObjectRenderer constexpr static inline const char* Type1RoomObjectNames[] = { "Ceiling ↔",