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.
This commit is contained in:
@@ -393,8 +393,8 @@ std::pair<int, int> 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());
|
||||
}
|
||||
|
||||
@@ -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<int>(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 {
|
||||
|
||||
@@ -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<gfx::Tile16>& 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;
|
||||
|
||||
@@ -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<uint8_t>(current_gfx16_));
|
||||
bg2_buffer_.DrawBackground(std::span<uint8_t>(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<uint8_t>(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<int>(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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -7,18 +7,48 @@
|
||||
namespace yaze {
|
||||
namespace zelda3 {
|
||||
|
||||
absl::StatusOr<gfx::Tile16> 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<gfx::Tile16> 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<uint16_t>(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<uint16_t>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@ class RoomLayoutObject {
|
||||
void set_layer(uint8_t layer) { layer_ = layer; }
|
||||
|
||||
// Get tile data for this layout object
|
||||
absl::StatusOr<gfx::Tile16> 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<gfx::Tile16> GetTile(const uint8_t* room_gfx_buffer = nullptr) const;
|
||||
|
||||
// Get the name/description of this layout object type
|
||||
std::string GetTypeName() const;
|
||||
|
||||
@@ -46,112 +46,8 @@ ObjectOption operator~(ObjectOption option) {
|
||||
return static_cast<ObjectOption>(~static_cast<int>(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<uint8_t>& current_gfx16,
|
||||
std::vector<uint8_t>& tiles_bg1_buffer,
|
||||
std::vector<uint8_t>& 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_);
|
||||
|
||||
@@ -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<uint8_t>& current_gfx16,
|
||||
std::vector<uint8_t>& tiles_bg1_buffer,
|
||||
std::vector<uint8_t>& 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<int16_t>(
|
||||
(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<uint8_t>& current_gfx16,
|
||||
std::vector<uint8_t>& tiles_bg1_buffer,
|
||||
std::vector<uint8_t>& 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<int16_t>(
|
||||
(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<uint8_t>& current_gfx16,
|
||||
std::vector<uint8_t>& tiles_bg1_buffer,
|
||||
std::vector<uint8_t>& 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<int16_t>(
|
||||
(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<uint8_t>& current_gfx16,
|
||||
std::vector<uint8_t>& tiles_bg1_buffer,
|
||||
std::vector<uint8_t>& 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 ↔",
|
||||
|
||||
Reference in New Issue
Block a user