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:
356
test/integration/zelda3/dungeon_rendering_test.cc
Normal file
356
test/integration/zelda3/dungeon_rendering_test.cc
Normal file
@@ -0,0 +1,356 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/gfx/background_buffer.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/dungeon/object_drawer.h"
|
||||
#include "app/zelda3/dungeon/object_parser.h"
|
||||
#include "app/zelda3/dungeon/room.h"
|
||||
#include "app/zelda3/dungeon/room_object.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace zelda3 {
|
||||
|
||||
class DungeonRenderingIntegrationTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Create a mock ROM for testing
|
||||
rom_ = std::make_unique<Rom>();
|
||||
// Initialize with minimal ROM data for testing
|
||||
std::vector<uint8_t> mock_rom_data(1024 * 1024, 0); // 1MB mock ROM
|
||||
rom_->LoadFromData(mock_rom_data);
|
||||
|
||||
// Create test rooms
|
||||
room_0x00_ = CreateTestRoom(0x00); // Link's House
|
||||
room_0x01_ = CreateTestRoom(0x01); // Another test room
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
rom_.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<Rom> rom_;
|
||||
|
||||
// Create a test room with various objects
|
||||
Room CreateTestRoom(int room_id) {
|
||||
Room room(room_id, rom_.get());
|
||||
|
||||
// Add some test objects to the room
|
||||
std::vector<RoomObject> objects;
|
||||
|
||||
// Add floor objects (object 0x00)
|
||||
objects.emplace_back(0x00, 5, 5, 3, 0); // Horizontal floor
|
||||
objects.emplace_back(0x00, 10, 10, 5, 0); // Another floor section
|
||||
|
||||
// Add wall objects (object 0x01)
|
||||
objects.emplace_back(0x01, 15, 15, 2, 0); // Vertical wall
|
||||
objects.emplace_back(0x01, 20, 20, 4, 1); // Horizontal wall on BG2
|
||||
|
||||
// Add diagonal stairs (object 0x09)
|
||||
objects.emplace_back(0x09, 25, 25, 6, 0); // Diagonal stairs
|
||||
|
||||
// Add solid blocks (object 0x34)
|
||||
objects.emplace_back(0x34, 30, 30, 1, 0); // Solid block
|
||||
objects.emplace_back(0x34, 35, 35, 2, 1); // Another solid block on BG2
|
||||
|
||||
// Set ROM for all objects
|
||||
for (auto& obj : objects) {
|
||||
obj.set_rom(rom_.get());
|
||||
}
|
||||
|
||||
// Add objects to room (this would normally be done by LoadObjects)
|
||||
for (const auto& obj : objects) {
|
||||
room.AddObject(obj);
|
||||
}
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
// Create a test palette
|
||||
gfx::SnesPalette CreateTestPalette() {
|
||||
gfx::SnesPalette palette;
|
||||
// Add some test colors
|
||||
palette.AddColor(gfx::SnesColor(0, 0, 0)); // Transparent
|
||||
palette.AddColor(gfx::SnesColor(255, 0, 0)); // Red
|
||||
palette.AddColor(gfx::SnesColor(0, 255, 0)); // Green
|
||||
palette.AddColor(gfx::SnesColor(0, 0, 255)); // Blue
|
||||
palette.AddColor(gfx::SnesColor(255, 255, 0)); // Yellow
|
||||
palette.AddColor(gfx::SnesColor(255, 0, 255)); // Magenta
|
||||
palette.AddColor(gfx::SnesColor(0, 255, 255)); // Cyan
|
||||
palette.AddColor(gfx::SnesColor(255, 255, 255)); // White
|
||||
return palette;
|
||||
}
|
||||
|
||||
gfx::PaletteGroup CreateTestPaletteGroup() {
|
||||
gfx::PaletteGroup group;
|
||||
group.AddPalette(CreateTestPalette());
|
||||
return group;
|
||||
}
|
||||
|
||||
private:
|
||||
Room room_0x00_;
|
||||
Room room_0x01_;
|
||||
};
|
||||
|
||||
// Test full room rendering with ObjectDrawer
|
||||
TEST_F(DungeonRenderingIntegrationTest, FullRoomRenderingWorks) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
|
||||
// Test that room has objects
|
||||
EXPECT_GT(test_room.GetTileObjects().size(), 0);
|
||||
|
||||
// Test ObjectDrawer can render the room
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
auto status = drawer.DrawObjectList(test_room.GetTileObjects(),
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test room rendering with different palette configurations
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithDifferentPalettes) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
|
||||
// Test with different palette configurations
|
||||
std::vector<gfx::PaletteGroup> palette_groups;
|
||||
|
||||
// Create multiple palette groups
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
palette_groups.push_back(CreateTestPaletteGroup());
|
||||
}
|
||||
|
||||
for (const auto& palette_group : palette_groups) {
|
||||
auto status = drawer.DrawObjectList(test_room.GetTileObjects(),
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
}
|
||||
|
||||
// Test room rendering with objects on different layers
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithMultipleLayers) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Separate objects by layer
|
||||
std::vector<RoomObject> bg1_objects;
|
||||
std::vector<RoomObject> bg2_objects;
|
||||
|
||||
for (const auto& obj : test_room.GetTileObjects()) {
|
||||
if (obj.GetLayerValue() == 0) {
|
||||
bg1_objects.push_back(obj);
|
||||
} else if (obj.GetLayerValue() == 1) {
|
||||
bg2_objects.push_back(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Render BG1 objects
|
||||
if (!bg1_objects.empty()) {
|
||||
auto status = drawer.DrawObjectList(bg1_objects,
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Render BG2 objects
|
||||
if (!bg2_objects.empty()) {
|
||||
auto status = drawer.DrawObjectList(bg2_objects,
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
}
|
||||
|
||||
// Test room rendering with various object sizes
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithVariousObjectSizes) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Group objects by size
|
||||
std::map<int, std::vector<RoomObject>> objects_by_size;
|
||||
|
||||
for (const auto& obj : test_room.GetTileObjects()) {
|
||||
objects_by_size[obj.size_].push_back(obj);
|
||||
}
|
||||
|
||||
// Render objects of each size
|
||||
for (const auto& [size, objects] : objects_by_size) {
|
||||
auto status = drawer.DrawObjectList(objects,
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
}
|
||||
|
||||
// Test room rendering performance
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingPerformance) {
|
||||
// Create a room with many objects
|
||||
Room large_room(0x00, rom_.get());
|
||||
|
||||
// Add many test objects
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
int id = i % 65; // Cycle through object IDs 0-64
|
||||
int x = (i * 2) % 60; // Spread across buffer
|
||||
int y = (i * 3) % 60;
|
||||
int size = (i % 8) + 1; // Size 1-8
|
||||
int layer = i % 2; // Alternate layers
|
||||
|
||||
RoomObject obj(id, x, y, size, layer);
|
||||
obj.set_rom(rom_.get());
|
||||
large_room.AddObject(obj);
|
||||
}
|
||||
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Time the rendering operation
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto status = drawer.DrawObjectList(large_room.GetTileObjects(),
|
||||
large_room.bg1_buffer(),
|
||||
large_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
end_time - start_time);
|
||||
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Should complete in reasonable time (less than 2 seconds for 200 objects)
|
||||
EXPECT_LT(duration.count(), 2000);
|
||||
|
||||
std::cout << "Rendered room with 200 objects in " << duration.count() << "ms" << std::endl;
|
||||
}
|
||||
|
||||
// Test room rendering with edge case coordinates
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithEdgeCaseCoordinates) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Add objects at edge coordinates
|
||||
std::vector<RoomObject> edge_objects;
|
||||
|
||||
edge_objects.emplace_back(0x34, 0, 0, 1, 0); // Origin
|
||||
edge_objects.emplace_back(0x34, 63, 63, 1, 0); // Near buffer edge
|
||||
edge_objects.emplace_back(0x34, 32, 32, 1, 0); // Center
|
||||
edge_objects.emplace_back(0x34, 1, 1, 1, 0); // Near origin
|
||||
edge_objects.emplace_back(0x34, 62, 62, 1, 0); // Near edge
|
||||
|
||||
// Set ROM for all objects
|
||||
for (auto& obj : edge_objects) {
|
||||
obj.set_rom(rom_.get());
|
||||
}
|
||||
|
||||
auto status = drawer.DrawObjectList(edge_objects,
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test room rendering with mixed object types
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithMixedObjectTypes) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Add various object types
|
||||
std::vector<RoomObject> mixed_objects;
|
||||
|
||||
// Floor objects
|
||||
mixed_objects.emplace_back(0x00, 5, 5, 3, 0);
|
||||
mixed_objects.emplace_back(0x01, 10, 10, 2, 0);
|
||||
|
||||
// Wall objects
|
||||
mixed_objects.emplace_back(0x02, 15, 15, 4, 0);
|
||||
mixed_objects.emplace_back(0x03, 20, 20, 1, 1);
|
||||
|
||||
// Diagonal objects
|
||||
mixed_objects.emplace_back(0x09, 25, 25, 5, 0);
|
||||
mixed_objects.emplace_back(0x0A, 30, 30, 3, 0);
|
||||
|
||||
// Solid objects
|
||||
mixed_objects.emplace_back(0x34, 35, 35, 1, 0);
|
||||
mixed_objects.emplace_back(0x33, 40, 40, 2, 1);
|
||||
|
||||
// Decorative objects
|
||||
mixed_objects.emplace_back(0x36, 45, 45, 3, 0);
|
||||
mixed_objects.emplace_back(0x38, 50, 50, 1, 0);
|
||||
|
||||
// Set ROM for all objects
|
||||
for (auto& obj : mixed_objects) {
|
||||
obj.set_rom(rom_.get());
|
||||
}
|
||||
|
||||
auto status = drawer.DrawObjectList(mixed_objects,
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test room rendering error handling
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingErrorHandling) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
|
||||
// Test with null ROM
|
||||
ObjectDrawer null_drawer(nullptr);
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
auto status = null_drawer.DrawObjectList(test_room.GetTileObjects(),
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
|
||||
}
|
||||
|
||||
// Test room rendering with invalid object data
|
||||
TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithInvalidObjectData) {
|
||||
Room test_room = CreateTestRoom(0x00);
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Create objects with invalid data
|
||||
std::vector<RoomObject> invalid_objects;
|
||||
|
||||
invalid_objects.emplace_back(0x999, 5, 5, 1, 0); // Invalid object ID
|
||||
invalid_objects.emplace_back(0x00, -1, -1, 1, 0); // Negative coordinates
|
||||
invalid_objects.emplace_back(0x00, 100, 100, 1, 0); // Out of bounds coordinates
|
||||
invalid_objects.emplace_back(0x00, 5, 5, 255, 0); // Maximum size
|
||||
|
||||
// Set ROM for all objects
|
||||
for (auto& obj : invalid_objects) {
|
||||
obj.set_rom(rom_.get());
|
||||
}
|
||||
|
||||
// Should handle gracefully
|
||||
auto status = drawer.DrawObjectList(invalid_objects,
|
||||
test_room.bg1_buffer(),
|
||||
test_room.bg2_buffer(),
|
||||
palette_group);
|
||||
|
||||
// Should succeed or fail gracefully
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
} // namespace zelda3
|
||||
} // namespace yaze
|
||||
324
test/unit/zelda3/dungeon/object_rendering_test.cc
Normal file
324
test/unit/zelda3/dungeon/object_rendering_test.cc
Normal file
@@ -0,0 +1,324 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/gfx/background_buffer.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/dungeon/object_drawer.h"
|
||||
#include "app/zelda3/dungeon/object_parser.h"
|
||||
#include "app/zelda3/dungeon/room_object.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace zelda3 {
|
||||
|
||||
class ObjectRenderingTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Create a mock ROM for testing
|
||||
rom_ = std::make_unique<Rom>();
|
||||
// Initialize with minimal ROM data for testing
|
||||
std::vector<uint8_t> mock_rom_data(1024 * 1024, 0); // 1MB mock ROM
|
||||
rom_->LoadFromData(mock_rom_data);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
rom_.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<Rom> rom_;
|
||||
gfx::BackgroundBuffer bg1_;
|
||||
gfx::BackgroundBuffer bg2_;
|
||||
|
||||
// Create a test palette
|
||||
gfx::SnesPalette CreateTestPalette() {
|
||||
gfx::SnesPalette palette;
|
||||
// Add some test colors
|
||||
palette.AddColor(gfx::SnesColor(0, 0, 0)); // Transparent
|
||||
palette.AddColor(gfx::SnesColor(255, 0, 0)); // Red
|
||||
palette.AddColor(gfx::SnesColor(0, 255, 0)); // Green
|
||||
palette.AddColor(gfx::SnesColor(0, 0, 255)); // Blue
|
||||
palette.AddColor(gfx::SnesColor(255, 255, 0)); // Yellow
|
||||
palette.AddColor(gfx::SnesColor(255, 0, 255)); // Magenta
|
||||
palette.AddColor(gfx::SnesColor(0, 255, 255)); // Cyan
|
||||
palette.AddColor(gfx::SnesColor(255, 255, 255)); // White
|
||||
return palette;
|
||||
}
|
||||
|
||||
gfx::PaletteGroup CreateTestPaletteGroup() {
|
||||
gfx::PaletteGroup group;
|
||||
group.AddPalette(CreateTestPalette());
|
||||
return group;
|
||||
}
|
||||
};
|
||||
|
||||
// Test object drawer initialization
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerInitializesCorrectly) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
|
||||
// Test that drawer can be created without errors
|
||||
EXPECT_NE(rom_.get(), nullptr);
|
||||
}
|
||||
|
||||
// Test object parser draw routine detection
|
||||
TEST_F(ObjectRenderingTest, ObjectParserDetectsDrawRoutines) {
|
||||
ObjectParser parser(rom_.get());
|
||||
|
||||
// Test common object IDs and their expected draw routines
|
||||
auto info_00 = parser.GetObjectDrawInfo(0x00);
|
||||
EXPECT_EQ(info_00.draw_routine_id, 0);
|
||||
EXPECT_EQ(info_00.routine_name, "Rightwards2x2_1to15or32");
|
||||
EXPECT_TRUE(info_00.is_horizontal);
|
||||
|
||||
auto info_01 = parser.GetObjectDrawInfo(0x01);
|
||||
EXPECT_EQ(info_01.draw_routine_id, 1);
|
||||
EXPECT_EQ(info_01.routine_name, "Rightwards2x4_1to15or26");
|
||||
EXPECT_TRUE(info_01.is_horizontal);
|
||||
|
||||
auto info_09 = parser.GetObjectDrawInfo(0x09);
|
||||
EXPECT_EQ(info_09.draw_routine_id, 5);
|
||||
EXPECT_EQ(info_09.routine_name, "DiagonalAcute_1to16");
|
||||
EXPECT_FALSE(info_09.is_horizontal);
|
||||
|
||||
auto info_34 = parser.GetObjectDrawInfo(0x34);
|
||||
EXPECT_EQ(info_34.draw_routine_id, 16);
|
||||
EXPECT_EQ(info_34.routine_name, "Rightwards1x1Solid_1to16_plus3");
|
||||
EXPECT_TRUE(info_34.is_horizontal);
|
||||
|
||||
// Test unmapped object defaults to solid block routine
|
||||
auto info_unknown = parser.GetObjectDrawInfo(0x999);
|
||||
EXPECT_EQ(info_unknown.draw_routine_id, 16); // Default solid routine
|
||||
EXPECT_EQ(info_unknown.routine_name, "DefaultSolid");
|
||||
}
|
||||
|
||||
// Test object drawer with various object types
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerHandlesVariousObjectTypes) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Test object 0x00 (horizontal floor tile)
|
||||
RoomObject floor_object(0x00, 10, 10, 3, 0); // ID, X, Y, size, layer
|
||||
|
||||
auto status = drawer.DrawObject(floor_object, bg1_, bg2_, palette_group);
|
||||
// Should succeed even if tiles aren't loaded (graceful handling)
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test object 0x09 (diagonal stairs)
|
||||
RoomObject stair_object(0x09, 15, 15, 5, 0);
|
||||
stair_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(stair_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test object 0x34 (solid block)
|
||||
RoomObject block_object(0x34, 20, 20, 1, 0);
|
||||
block_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(block_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test object drawer with different layers
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerHandlesDifferentLayers) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Test BG1 layer object
|
||||
RoomObject bg1_object(0x00, 5, 5, 2, 0); // Layer 0 = BG1
|
||||
bg1_object.set_rom(rom_.get());
|
||||
|
||||
auto status = drawer.DrawObject(bg1_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test BG2 layer object
|
||||
RoomObject bg2_object(0x01, 10, 10, 2, 1); // Layer 1 = BG2
|
||||
bg2_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(bg2_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test object drawer with size variations
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerHandlesSizeVariations) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Test small object
|
||||
RoomObject small_object(0x00, 5, 5, 1, 0); // Size = 1
|
||||
small_object.set_rom(rom_.get());
|
||||
|
||||
auto status = drawer.DrawObject(small_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test large object
|
||||
RoomObject large_object(0x00, 10, 10, 15, 0); // Size = 15
|
||||
large_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(large_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test maximum size object
|
||||
RoomObject max_object(0x00, 15, 15, 31, 0); // Size = 31 (0x1F)
|
||||
max_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(max_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test object drawer with edge cases
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerHandlesEdgeCases) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Test object at origin
|
||||
RoomObject origin_object(0x34, 0, 0, 1, 0);
|
||||
origin_object.set_rom(rom_.get());
|
||||
|
||||
auto status = drawer.DrawObject(origin_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test object with zero size
|
||||
RoomObject zero_size_object(0x34, 10, 10, 0, 0);
|
||||
zero_size_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(zero_size_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test object with maximum coordinates
|
||||
RoomObject max_coord_object(0x34, 63, 63, 1, 0); // Near buffer edge
|
||||
max_coord_object.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(max_coord_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test object drawer with multiple objects
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerHandlesMultipleObjects) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
std::vector<RoomObject> objects;
|
||||
|
||||
// Create various test objects
|
||||
objects.emplace_back(0x00, 5, 5, 3, 0); // Horizontal floor
|
||||
objects.emplace_back(0x01, 10, 10, 2, 0); // Vertical floor
|
||||
objects.emplace_back(0x09, 15, 15, 4, 0); // Diagonal stairs
|
||||
objects.emplace_back(0x34, 20, 20, 1, 1); // Solid block on BG2
|
||||
|
||||
// Set ROM for all objects
|
||||
for (auto& obj : objects) {
|
||||
obj.set_rom(rom_.get());
|
||||
}
|
||||
|
||||
auto status = drawer.DrawObjectList(objects, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test specific draw routines
|
||||
TEST_F(ObjectRenderingTest, DrawRoutinesWorkCorrectly) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
// Test rightward patterns
|
||||
RoomObject rightward_obj(0x00, 5, 5, 5, 0);
|
||||
rightward_obj.set_rom(rom_.get());
|
||||
|
||||
auto status = drawer.DrawObject(rightward_obj, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test diagonal patterns
|
||||
RoomObject diagonal_obj(0x09, 10, 10, 6, 0);
|
||||
diagonal_obj.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(diagonal_obj, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Test solid block patterns
|
||||
RoomObject solid_obj(0x34, 15, 15, 8, 0);
|
||||
solid_obj.set_rom(rom_.get());
|
||||
|
||||
status = drawer.DrawObject(solid_obj, bg1_, bg2_, palette_group);
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
// Test object drawer error handling
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerHandlesErrorsGracefully) {
|
||||
ObjectDrawer drawer(nullptr); // No ROM
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
RoomObject test_object(0x00, 5, 5, 1, 0);
|
||||
|
||||
auto status = drawer.DrawObject(test_object, bg1_, bg2_, palette_group);
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
|
||||
}
|
||||
|
||||
// Test object parser with various object IDs
|
||||
TEST_F(ObjectRenderingTest, ObjectParserHandlesVariousObjectIDs) {
|
||||
ObjectParser parser(rom_.get());
|
||||
|
||||
// Test subtype 1 objects (0x00-0xFF)
|
||||
for (int id = 0; id <= 0x40; id += 4) { // Test every 4th object
|
||||
auto info = parser.GetObjectDrawInfo(id);
|
||||
EXPECT_GE(info.draw_routine_id, 0);
|
||||
EXPECT_LT(info.draw_routine_id, 25); // Should be within valid range
|
||||
EXPECT_FALSE(info.routine_name.empty());
|
||||
}
|
||||
|
||||
// Test some specific important objects
|
||||
std::vector<int16_t> important_objects = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
0x0A, 0x0B, 0x15, 0x16, 0x21, 0x22, 0x2F, 0x30, 0x31, 0x32,
|
||||
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
|
||||
0x3D, 0x3E, 0x3F, 0x40
|
||||
};
|
||||
|
||||
for (int16_t obj_id : important_objects) {
|
||||
auto info = parser.GetObjectDrawInfo(obj_id);
|
||||
EXPECT_GE(info.draw_routine_id, 0);
|
||||
EXPECT_LT(info.draw_routine_id, 25);
|
||||
EXPECT_FALSE(info.routine_name.empty());
|
||||
|
||||
// Verify tile count is reasonable
|
||||
EXPECT_GT(info.tile_count, 0);
|
||||
EXPECT_LE(info.tile_count, 64); // Reasonable upper bound
|
||||
}
|
||||
}
|
||||
|
||||
// Test object drawer performance with many objects
|
||||
TEST_F(ObjectRenderingTest, ObjectDrawerPerformanceTest) {
|
||||
ObjectDrawer drawer(rom_.get());
|
||||
auto palette_group = CreateTestPaletteGroup();
|
||||
|
||||
std::vector<RoomObject> objects;
|
||||
|
||||
// Create 100 test objects
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
int id = i % 65; // Cycle through object IDs 0-64
|
||||
int x = (i * 2) % 60; // Spread across buffer
|
||||
int y = (i * 3) % 60;
|
||||
int size = (i % 8) + 1; // Size 1-8
|
||||
int layer = i % 2; // Alternate layers
|
||||
|
||||
objects.emplace_back(id, x, y, size, layer);
|
||||
objects.back().set_rom(rom_.get());
|
||||
}
|
||||
|
||||
// Time the drawing operation
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto status = drawer.DrawObjectList(objects, bg1_, bg2_, palette_group);
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
end_time - start_time);
|
||||
|
||||
EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
|
||||
|
||||
// Should complete in reasonable time (less than 1 second for 100 objects)
|
||||
EXPECT_LT(duration.count(), 1000);
|
||||
|
||||
std::cout << "Drew 100 objects in " << duration.count() << "ms" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace zelda3
|
||||
} // namespace yaze
|
||||
Reference in New Issue
Block a user