refactor: Remove manual object renderer and dungeon renderer from the editor
- Deleted the ManualObjectRenderer and DungeonRenderer classes to streamline the codebase and reduce redundancy. - Updated DungeonCanvasViewer and DungeonEditorV2 to remove references to the deleted renderers, ensuring proper functionality without them. - Enhanced the rendering logic in DungeonCanvasViewer to directly handle object rendering and background layers, improving performance and maintainability. - Added debug logging to track rendering processes and ensure proper graphics loading.
This commit is contained in:
@@ -8,63 +8,56 @@
|
||||
namespace yaze {
|
||||
namespace zelda3 {
|
||||
|
||||
ObjectDrawer::ObjectDrawer(Rom* rom) : rom_(rom) {}
|
||||
ObjectDrawer::ObjectDrawer(Rom* rom) : rom_(rom) {
|
||||
InitializeDrawRoutines();
|
||||
}
|
||||
|
||||
absl::Status ObjectDrawer::DrawObject(const RoomObject& object,
|
||||
gfx::BackgroundBuffer& bg1,
|
||||
gfx::BackgroundBuffer& bg2) {
|
||||
gfx::BackgroundBuffer& bg2,
|
||||
const gfx::PaletteGroup& palette_group) {
|
||||
if (!rom_ || !rom_->is_loaded()) {
|
||||
return absl::FailedPreconditionError("ROM not loaded");
|
||||
}
|
||||
|
||||
if (!routines_initialized_) {
|
||||
return absl::FailedPreconditionError("Draw routines not initialized");
|
||||
}
|
||||
|
||||
// Ensure object has tiles loaded
|
||||
auto mutable_obj = const_cast<RoomObject&>(object);
|
||||
printf("[DrawObject] Setting ROM for object ID=0x%02X\n", object.id_);
|
||||
mutable_obj.set_rom(rom_);
|
||||
printf("[DrawObject] Calling EnsureTilesLoaded for object ID=0x%02X\n", object.id_);
|
||||
mutable_obj.EnsureTilesLoaded();
|
||||
|
||||
// Get tiles - silently skip objects that can't load tiles
|
||||
if (object.tiles().empty()) {
|
||||
// Many objects may not have tiles loaded yet - this is normal
|
||||
// Just skip them rather than failing the whole draw operation
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
const auto& tile = object.tiles()[0]; // Base tile for object
|
||||
|
||||
// Check if tiles were actually loaded on the mutable object
|
||||
printf("[DrawObject] After EnsureTilesLoaded: mutable object has %zu tiles\n",
|
||||
mutable_obj.tiles().size());
|
||||
|
||||
// Select buffer based on layer
|
||||
auto& target_bg = (object.layer_ == RoomObject::LayerType::BG2) ? bg2 : bg1;
|
||||
|
||||
// Dispatch to pattern-specific drawing based on object ID
|
||||
// This is reverse-engineered from the game's drawing routines
|
||||
// Skip objects that don't have tiles loaded - check mutable object
|
||||
if (mutable_obj.tiles().empty()) {
|
||||
printf("[DrawObject] Object ID=0x%02X has no tiles loaded, skipping\n", object.id_);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
printf("[DrawObject] Object ID=0x%02X has %zu tiles, proceeding with drawing\n",
|
||||
object.id_, mutable_obj.tiles().size());
|
||||
|
||||
// Look up draw routine for this object
|
||||
int routine_id = GetDrawRoutineId(object.id_);
|
||||
|
||||
if (object.id_ == 0x34) {
|
||||
// Object 0x34: 1x1 solid block (simplest)
|
||||
Draw1x1Solid(object, target_bg, tile);
|
||||
}
|
||||
else if (object.id_ >= 0x00 && object.id_ <= 0x08) {
|
||||
// Objects 0x00-0x08: Rightward 2x2 patterns
|
||||
DrawRightwards2x2(object, target_bg, tile);
|
||||
}
|
||||
else if (object.id_ >= 0x60 && object.id_ <= 0x68) {
|
||||
// Objects 0x60-0x68: Downward 2x2 patterns
|
||||
DrawDownwards2x2(object, target_bg, tile);
|
||||
}
|
||||
else if (object.id_ >= 0x09 && object.id_ <= 0x14) {
|
||||
// Objects 0x09-0x14: Diagonal acute patterns
|
||||
DrawDiagonalAcute(object, target_bg, tile);
|
||||
}
|
||||
else if (object.id_ >= 0x15 && object.id_ <= 0x20) {
|
||||
// Objects 0x15-0x20: Diagonal grave patterns
|
||||
DrawDiagonalGrave(object, target_bg, tile);
|
||||
}
|
||||
else if (object.id_ == 0x33 || (object.id_ >= 0x70 && object.id_ <= 0x71)) {
|
||||
// 4x4 block objects
|
||||
Draw4x4Block(object, target_bg, tile);
|
||||
}
|
||||
else {
|
||||
// Default: Draw as simple 1x1 at position
|
||||
Draw1x1Solid(object, target_bg, tile);
|
||||
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]);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Execute the appropriate draw routine
|
||||
draw_routines_[routine_id](this, object, target_bg, mutable_obj.tiles());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -72,13 +65,16 @@ absl::Status ObjectDrawer::DrawObject(const RoomObject& object,
|
||||
absl::Status ObjectDrawer::DrawObjectList(
|
||||
const std::vector<RoomObject>& objects,
|
||||
gfx::BackgroundBuffer& bg1,
|
||||
gfx::BackgroundBuffer& bg2) {
|
||||
gfx::BackgroundBuffer& bg2,
|
||||
const gfx::PaletteGroup& palette_group) {
|
||||
|
||||
printf("[DrawObjectList] Drawing %zu objects\n", objects.size());
|
||||
|
||||
int drawn_count = 0;
|
||||
int skipped_count = 0;
|
||||
|
||||
for (const auto& object : objects) {
|
||||
auto status = DrawObject(object, bg1, bg2);
|
||||
auto status = DrawObject(object, bg1, bg2, palette_group);
|
||||
if (status.ok()) {
|
||||
drawn_count++;
|
||||
} else {
|
||||
@@ -90,7 +86,8 @@ absl::Status ObjectDrawer::DrawObjectList(
|
||||
}
|
||||
}
|
||||
|
||||
if (drawn_count > 0 || skipped_count > 0) {
|
||||
// Only log if there are failures
|
||||
if (skipped_count > 0) {
|
||||
printf("[ObjectDrawer] Drew %d objects, skipped %d\n", drawn_count, skipped_count);
|
||||
}
|
||||
|
||||
@@ -98,85 +95,474 @@ absl::Status ObjectDrawer::DrawObjectList(
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pattern Drawing Implementations
|
||||
// Draw Routine Registry Initialization
|
||||
// ============================================================================
|
||||
|
||||
void ObjectDrawer::Draw1x1Solid(const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg,
|
||||
const gfx::Tile16& tile) {
|
||||
// Simple 1x1 tile placement
|
||||
WriteTile16(bg, obj.x_, obj.y_, tile);
|
||||
void ObjectDrawer::InitializeDrawRoutines() {
|
||||
// Initialize draw routine registry based on ZScream's subtype1_routines table
|
||||
// This maps object IDs to draw routine indices (0-24)
|
||||
|
||||
// Routine 0: RoomDraw_Rightwards2x2_1to15or32
|
||||
for (int id = 0x00; id <= 0x00; id++) {
|
||||
object_to_routine_map_[id] = 0;
|
||||
}
|
||||
|
||||
// Routine 1: RoomDraw_Rightwards2x4_1to15or26
|
||||
for (int id = 0x01; id <= 0x02; id++) {
|
||||
object_to_routine_map_[id] = 1;
|
||||
}
|
||||
|
||||
// Routine 2: RoomDraw_Rightwards2x4spaced4_1to16
|
||||
for (int id = 0x03; id <= 0x04; id++) {
|
||||
object_to_routine_map_[id] = 2;
|
||||
}
|
||||
|
||||
// Routine 3: RoomDraw_Rightwards2x4spaced4_1to16_BothBG
|
||||
for (int id = 0x05; id <= 0x06; id++) {
|
||||
object_to_routine_map_[id] = 3;
|
||||
}
|
||||
|
||||
// Routine 4: RoomDraw_Rightwards2x2_1to16
|
||||
for (int id = 0x07; id <= 0x08; id++) {
|
||||
object_to_routine_map_[id] = 4;
|
||||
}
|
||||
|
||||
// Routine 5: RoomDraw_DiagonalAcute_1to16
|
||||
for (int id = 0x09; id <= 0x09; id++) {
|
||||
object_to_routine_map_[id] = 5;
|
||||
}
|
||||
|
||||
// Routine 6: RoomDraw_DiagonalGrave_1to16
|
||||
for (int id = 0x0A; id <= 0x0B; id++) {
|
||||
object_to_routine_map_[id] = 6;
|
||||
}
|
||||
|
||||
// Continue mapping more object IDs...
|
||||
// (This is a simplified version - the full table has 248 entries)
|
||||
|
||||
// Initialize draw routine function array
|
||||
draw_routines_.clear();
|
||||
draw_routines_.reserve(25);
|
||||
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards2x2_1to15or32(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards2x4_1to15or26(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards2x4spaced4_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards2x4spaced4_1to16_BothBG(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards2x2_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawDiagonalAcute_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawDiagonalGrave_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawDiagonalAcute_1to16_BothBG(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawDiagonalGrave_1to16_BothBG(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards1x2_1to16_plus2(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsHasEdge1x1_1to16_plus3(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsHasEdge1x1_1to16_plus2(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsTopCorners1x2_1to16_plus13(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsBottomCorners1x2_1to16_plus13(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->CustomDraw(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards4x4_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwards1x1Solid_1to16_plus3(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawDoorSwitcherer(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsDecor4x4spaced2_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsStatue2x3spaced2_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsPillar2x4spaced4_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsDecor4x3spaced4_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsDoubled2x2spaced2_1to16(obj, bg, tiles);
|
||||
});
|
||||
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj, gfx::BackgroundBuffer& bg, const std::vector<gfx::Tile16>& tiles) {
|
||||
self->DrawRightwardsDecor2x2spaced12_1to16(obj, bg, tiles);
|
||||
});
|
||||
|
||||
routines_initialized_ = true;
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwards2x2(const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg,
|
||||
const gfx::Tile16& tile) {
|
||||
// Pattern: Draws 2x2 tiles rightward
|
||||
// Size byte determines how many times to repeat
|
||||
int repeat_count = (obj.size_ & 0x0F) + 1; // Low nibble = width
|
||||
int ObjectDrawer::GetDrawRoutineId(int16_t object_id) const {
|
||||
auto it = object_to_routine_map_.find(object_id);
|
||||
if (it != object_to_routine_map_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
for (int i = 0; i < repeat_count; i++) {
|
||||
// Each iteration draws a 2x2 tile16
|
||||
int tile_x = obj.x_ + (i * 2); // Each tile16 is 2x2 8x8 tiles
|
||||
int tile_y = obj.y_;
|
||||
|
||||
WriteTile16(bg, tile_x, tile_y, tile);
|
||||
// Default to simple 1x1 solid for unmapped objects
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Draw Routine Implementations (Based on ZScream patterns)
|
||||
// ============================================================================
|
||||
|
||||
void ObjectDrawer::DrawRightwards2x2_1to15or32(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Draws 2x2 tiles rightward (object 0x00)
|
||||
// Size byte determines how many times to repeat (1-15 or 32)
|
||||
int size = obj.size_;
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDownwards2x2(const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg,
|
||||
const gfx::Tile16& tile) {
|
||||
// Pattern: Draws 2x2 tiles downward
|
||||
// Size byte determines how many times to repeat
|
||||
int repeat_count = ((obj.size_ >> 4) & 0x0F) + 1; // High nibble = height
|
||||
void ObjectDrawer::DrawRightwards2x4_1to15or26(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Draws 2x4 tiles rightward (objects 0x01-0x02)
|
||||
int size = obj.size_;
|
||||
if (size == 0) size = 26; // Special case
|
||||
|
||||
for (int i = 0; i < repeat_count; i++) {
|
||||
int tile_x = obj.x_;
|
||||
int tile_y = obj.y_ + (i * 2);
|
||||
|
||||
WriteTile16(bg, tile_x, tile_y, tile);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDiagonalAcute(const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg,
|
||||
const gfx::Tile16& tile) {
|
||||
// Pattern: Diagonal line going down-right (/)
|
||||
int length = (obj.size_ & 0x0F) + 1;
|
||||
void ObjectDrawer::DrawRightwards2x4spaced4_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Draws 2x4 tiles rightward with spacing (objects 0x03-0x04)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
int tile_x = obj.x_ + i;
|
||||
int tile_y = obj.y_ + i;
|
||||
|
||||
WriteTile16(bg, tile_x, tile_y, tile);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDiagonalGrave(const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg,
|
||||
const gfx::Tile16& tile) {
|
||||
// Pattern: Diagonal line going down-left (\)
|
||||
int length = (obj.size_ & 0x0F) + 1;
|
||||
void ObjectDrawer::DrawRightwards2x4spaced4_1to16_BothBG(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Same as above but draws to both BG1 and BG2 (objects 0x05-0x06)
|
||||
DrawRightwards2x4spaced4_1to16(obj, bg, tiles);
|
||||
// Note: BothBG would require access to both buffers - simplified for now
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwards2x2_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Draws 2x2 tiles rightward (objects 0x07-0x08)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
int tile_x = obj.x_ - i;
|
||||
int tile_y = obj.y_ + i;
|
||||
|
||||
WriteTile16(bg, tile_x, tile_y, tile);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::Draw4x4Block(const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg,
|
||||
const gfx::Tile16& tile) {
|
||||
// Pattern: 4x4 tile16 block (8x8 8x8 tiles total)
|
||||
for (int yy = 0; yy < 4; yy++) {
|
||||
for (int xx = 0; xx < 4; xx++) {
|
||||
int tile_x = obj.x_ + (xx * 2);
|
||||
int tile_y = obj.y_ + (yy * 2);
|
||||
|
||||
WriteTile16(bg, tile_x, tile_y, tile);
|
||||
void ObjectDrawer::DrawDiagonalAcute_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Diagonal line going down-right (/) (object 0x09)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int s = 0; s < size + 6; s++) {
|
||||
if (tiles.size() >= 5) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
WriteTile16(bg, obj.x_ + s, obj.y_ + (i - s), tiles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDiagonalGrave_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Diagonal line going down-left (\) (objects 0x0A-0x0B)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int s = 0; s < size + 6; s++) {
|
||||
if (tiles.size() >= 5) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
WriteTile16(bg, obj.x_ + s, obj.y_ + (i + s), tiles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDiagonalAcute_1to16_BothBG(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Diagonal acute for both BG layers (objects 0x15-0x1F)
|
||||
DrawDiagonalAcute_1to16(obj, bg, tiles);
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDiagonalGrave_1to16_BothBG(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Diagonal grave for both BG layers (objects 0x16-0x20)
|
||||
DrawDiagonalGrave_1to16(obj, bg, tiles);
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwards1x2_1to16_plus2(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 1x2 tiles rightward with +2 offset (object 0x21)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsHasEdge1x1_1to16_plus3(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 1x1 tiles with edge detection +3 offset (object 0x22)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int s = 0; s < size; s++) {
|
||||
if (tiles.size() >= 1) {
|
||||
WriteTile16(bg, obj.x_ + s + 3, obj.y_, tiles[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsHasEdge1x1_1to16_plus2(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 1x1 tiles with edge detection +2 offset (objects 0x23-0x2E)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int s = 0; s < size; s++) {
|
||||
if (tiles.size() >= 1) {
|
||||
WriteTile16(bg, obj.x_ + s + 2, obj.y_, tiles[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsTopCorners1x2_1to16_plus13(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Top corner 1x2 tiles with +13 offset (object 0x2F)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsBottomCorners1x2_1to16_plus13(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Bottom corner 1x2 tiles with +13 offset (object 0x30)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::CustomDraw(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwards4x4_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 4x4 block rightward (object 0x33)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwards1x1Solid_1to16_plus3(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 1x1 solid tiles +3 offset (object 0x34)
|
||||
int size = obj.size_ & 0x0F;
|
||||
|
||||
for (int s = 0; s < size; s++) {
|
||||
if (tiles.size() >= 1) {
|
||||
WriteTile16(bg, obj.x_ + s + 3, obj.y_, tiles[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawDoorSwitcherer(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Door switcher (object 0x35)
|
||||
// Special door logic - simplified for now
|
||||
if (tiles.size() >= 1) {
|
||||
WriteTile16(bg, obj.x_, obj.y_, tiles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsDecor4x4spaced2_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 4x4 decoration with spacing (objects 0x36-0x37)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsStatue2x3spaced2_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 2x3 statue with spacing (object 0x38)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsPillar2x4spaced4_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 2x4 pillar with spacing (objects 0x39, 0x3D)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsDecor4x3spaced4_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 4x3 decoration with spacing (objects 0x3A-0x3B)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsDoubled2x2spaced2_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: Doubled 2x2 with spacing (object 0x3C)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawRightwardsDecor2x2spaced12_1to16(const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
const std::vector<gfx::Tile16>& tiles) {
|
||||
// Pattern: 2x2 decoration with large spacing (object 0x3E)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,27 +573,30 @@ void ObjectDrawer::Draw4x4Block(const RoomObject& obj,
|
||||
|
||||
void ObjectDrawer::WriteTile16(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
|
||||
const gfx::Tile16& tile) {
|
||||
// A Tile16 is 2x2 8x8 tiles, so we write 4 tile entries
|
||||
printf("[WriteTile16] Writing Tile16 at tile pos (%d,%d) to bitmap\n", tile_x, tile_y);
|
||||
|
||||
// Top-left (tile0)
|
||||
if (IsValidTilePosition(tile_x, tile_y)) {
|
||||
bg.SetTileAt(tile_x, tile_y, gfx::TileInfoToWord(tile.tile0_));
|
||||
// Draw directly to bitmap instead of tile buffer to avoid being overwritten
|
||||
auto& bitmap = bg.bitmap();
|
||||
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
|
||||
}
|
||||
|
||||
// Get graphics data from ROM
|
||||
if (!rom_ || !rom_->is_loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Top-right (tile1)
|
||||
if (IsValidTilePosition(tile_x + 1, tile_y)) {
|
||||
bg.SetTileAt(tile_x + 1, tile_y, gfx::TileInfoToWord(tile.tile1_));
|
||||
}
|
||||
|
||||
// Bottom-left (tile2)
|
||||
if (IsValidTilePosition(tile_x, tile_y + 1)) {
|
||||
bg.SetTileAt(tile_x, tile_y + 1, gfx::TileInfoToWord(tile.tile2_));
|
||||
}
|
||||
|
||||
// Bottom-right (tile3)
|
||||
if (IsValidTilePosition(tile_x + 1, tile_y + 1)) {
|
||||
bg.SetTileAt(tile_x + 1, tile_y + 1, gfx::TileInfoToWord(tile.tile3_));
|
||||
auto gfx_data = rom_->mutable_graphics_buffer();
|
||||
if (!gfx_data || gfx_data->empty()) {
|
||||
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());
|
||||
}
|
||||
|
||||
bool ObjectDrawer::IsValidTilePosition(int tile_x, int tile_y) const {
|
||||
@@ -215,6 +604,49 @@ bool ObjectDrawer::IsValidTilePosition(int tile_x, int tile_y) const {
|
||||
tile_y >= 0 && tile_y < kMaxTilesY;
|
||||
}
|
||||
|
||||
void ObjectDrawer::DrawTileToBitmap(gfx::Bitmap& bitmap, const gfx::TileInfo& tile_info,
|
||||
int pixel_x, int pixel_y, const uint8_t* tiledata) {
|
||||
// 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_);
|
||||
|
||||
// Calculate tile position in graphics sheet (128 pixels wide)
|
||||
int tile_sheet_x = (tile_info.id_ % 16) * 8; // 16 tiles per row
|
||||
int tile_sheet_y = (tile_info.id_ / 16) * 8; // Each row is 16 tiles
|
||||
|
||||
// Clamp palette to valid range
|
||||
uint8_t palette_id = tile_info.palette_ & 0x0F;
|
||||
if (palette_id > 10) palette_id = palette_id % 11;
|
||||
uint8_t palette_offset = palette_id * 8; // 3BPP: 8 colors per palette
|
||||
|
||||
// Draw 8x8 pixels
|
||||
for (int py = 0; py < 8; py++) {
|
||||
for (int px = 0; px < 8; px++) {
|
||||
// Apply mirroring
|
||||
int src_x = tile_info.horizontal_mirror_ ? (7 - px) : px;
|
||||
int src_y = tile_info.vertical_mirror_ ? (7 - py) : py;
|
||||
|
||||
// Read pixel from graphics sheet
|
||||
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;
|
||||
int dest_x = pixel_x + px;
|
||||
int dest_y = pixel_y + py;
|
||||
|
||||
if (dest_x >= 0 && dest_x < bitmap.width() && dest_y >= 0 && dest_y < bitmap.height()) {
|
||||
int dest_index = dest_y * bitmap.width() + dest_x;
|
||||
if (dest_index >= 0 && dest_index < static_cast<int>(bitmap.mutable_data().size())) {
|
||||
bitmap.mutable_data()[dest_index] = final_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace zelda3
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
Reference in New Issue
Block a user