yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
object_rendering_test.cc
Go to the documentation of this file.
1#include "gtest/gtest.h"
2
3#include "absl/status/status.h"
6#include "app/rom.h"
10
11namespace yaze {
12namespace zelda3 {
13
14class ObjectRenderingTest : public ::testing::Test {
15 protected:
16 void SetUp() override {
17 // Create a mock ROM for testing
18 rom_ = std::make_unique<Rom>();
19 // Initialize with minimal ROM data for testing
20 std::vector<uint8_t> mock_rom_data(1024 * 1024, 0); // 1MB mock ROM
21 rom_->LoadFromData(mock_rom_data);
22 }
23
24 void TearDown() override {
25 rom_.reset();
26 }
27
28 std::unique_ptr<Rom> rom_;
31
32 // Create a test palette
34 gfx::SnesPalette palette;
35 // Add some test colors
36 palette.AddColor(gfx::SnesColor(0, 0, 0)); // Transparent
37 palette.AddColor(gfx::SnesColor(255, 0, 0)); // Red
38 palette.AddColor(gfx::SnesColor(0, 255, 0)); // Green
39 palette.AddColor(gfx::SnesColor(0, 0, 255)); // Blue
40 palette.AddColor(gfx::SnesColor(255, 255, 0)); // Yellow
41 palette.AddColor(gfx::SnesColor(255, 0, 255)); // Magenta
42 palette.AddColor(gfx::SnesColor(0, 255, 255)); // Cyan
43 palette.AddColor(gfx::SnesColor(255, 255, 255)); // White
44 return palette;
45 }
46
52};
53
54// Test object drawer initialization
55TEST_F(ObjectRenderingTest, ObjectDrawerInitializesCorrectly) {
56 ObjectDrawer drawer(rom_.get());
57
58 // Test that drawer can be created without errors
59 EXPECT_NE(rom_.get(), nullptr);
60}
61
62// Test object parser draw routine detection
63TEST_F(ObjectRenderingTest, ObjectParserDetectsDrawRoutines) {
64 ObjectParser parser(rom_.get());
65
66 // Test common object IDs and their expected draw routines
67 auto info_00 = parser.GetObjectDrawInfo(0x00);
68 EXPECT_EQ(info_00.draw_routine_id, 0);
69 EXPECT_EQ(info_00.routine_name, "Rightwards2x2_1to15or32");
70 EXPECT_TRUE(info_00.is_horizontal);
71
72 auto info_01 = parser.GetObjectDrawInfo(0x01);
73 EXPECT_EQ(info_01.draw_routine_id, 1);
74 EXPECT_EQ(info_01.routine_name, "Rightwards2x4_1to15or26");
75 EXPECT_TRUE(info_01.is_horizontal);
76
77 auto info_09 = parser.GetObjectDrawInfo(0x09);
78 EXPECT_EQ(info_09.draw_routine_id, 5);
79 EXPECT_EQ(info_09.routine_name, "DiagonalAcute_1to16");
80 EXPECT_FALSE(info_09.is_horizontal);
81
82 auto info_34 = parser.GetObjectDrawInfo(0x34);
83 EXPECT_EQ(info_34.draw_routine_id, 16);
84 EXPECT_EQ(info_34.routine_name, "Rightwards1x1Solid_1to16_plus3");
85 EXPECT_TRUE(info_34.is_horizontal);
86
87 // Test unmapped object defaults to solid block routine
88 auto info_unknown = parser.GetObjectDrawInfo(0x999);
89 EXPECT_EQ(info_unknown.draw_routine_id, 16); // Default solid routine
90 EXPECT_EQ(info_unknown.routine_name, "DefaultSolid");
91}
92
93// Test object drawer with various object types
94TEST_F(ObjectRenderingTest, ObjectDrawerHandlesVariousObjectTypes) {
95 ObjectDrawer drawer(rom_.get());
96 auto palette_group = CreateTestPaletteGroup();
97
98 // Test object 0x00 (horizontal floor tile)
99 RoomObject floor_object(0x00, 10, 10, 3, 0); // ID, X, Y, size, layer
100
101 auto status = drawer.DrawObject(floor_object, bg1_, bg2_, palette_group);
102 // Should succeed even if tiles aren't loaded (graceful handling)
103 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
104
105 // Test object 0x09 (diagonal stairs)
106 RoomObject stair_object(0x09, 15, 15, 5, 0);
107 stair_object.set_rom(rom_.get());
108
109 status = drawer.DrawObject(stair_object, bg1_, bg2_, palette_group);
110 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
111
112 // Test object 0x34 (solid block)
113 RoomObject block_object(0x34, 20, 20, 1, 0);
114 block_object.set_rom(rom_.get());
115
116 status = drawer.DrawObject(block_object, bg1_, bg2_, palette_group);
117 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
118}
119
120// Test object drawer with different layers
121TEST_F(ObjectRenderingTest, ObjectDrawerHandlesDifferentLayers) {
122 ObjectDrawer drawer(rom_.get());
123 auto palette_group = CreateTestPaletteGroup();
124
125 // Test BG1 layer object
126 RoomObject bg1_object(0x00, 5, 5, 2, 0); // Layer 0 = BG1
127 bg1_object.set_rom(rom_.get());
128
129 auto status = drawer.DrawObject(bg1_object, bg1_, bg2_, palette_group);
130 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
131
132 // Test BG2 layer object
133 RoomObject bg2_object(0x01, 10, 10, 2, 1); // Layer 1 = BG2
134 bg2_object.set_rom(rom_.get());
135
136 status = drawer.DrawObject(bg2_object, bg1_, bg2_, palette_group);
137 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
138}
139
140// Test object drawer with size variations
141TEST_F(ObjectRenderingTest, ObjectDrawerHandlesSizeVariations) {
142 ObjectDrawer drawer(rom_.get());
143 auto palette_group = CreateTestPaletteGroup();
144
145 // Test small object
146 RoomObject small_object(0x00, 5, 5, 1, 0); // Size = 1
147 small_object.set_rom(rom_.get());
148
149 auto status = drawer.DrawObject(small_object, bg1_, bg2_, palette_group);
150 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
151
152 // Test large object
153 RoomObject large_object(0x00, 10, 10, 15, 0); // Size = 15
154 large_object.set_rom(rom_.get());
155
156 status = drawer.DrawObject(large_object, bg1_, bg2_, palette_group);
157 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
158
159 // Test maximum size object
160 RoomObject max_object(0x00, 15, 15, 31, 0); // Size = 31 (0x1F)
161 max_object.set_rom(rom_.get());
162
163 status = drawer.DrawObject(max_object, bg1_, bg2_, palette_group);
164 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
165}
166
167// Test object drawer with edge cases
168TEST_F(ObjectRenderingTest, ObjectDrawerHandlesEdgeCases) {
169 ObjectDrawer drawer(rom_.get());
170 auto palette_group = CreateTestPaletteGroup();
171
172 // Test object at origin
173 RoomObject origin_object(0x34, 0, 0, 1, 0);
174 origin_object.set_rom(rom_.get());
175
176 auto status = drawer.DrawObject(origin_object, bg1_, bg2_, palette_group);
177 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
178
179 // Test object with zero size
180 RoomObject zero_size_object(0x34, 10, 10, 0, 0);
181 zero_size_object.set_rom(rom_.get());
182
183 status = drawer.DrawObject(zero_size_object, bg1_, bg2_, palette_group);
184 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
185
186 // Test object with maximum coordinates
187 RoomObject max_coord_object(0x34, 63, 63, 1, 0); // Near buffer edge
188 max_coord_object.set_rom(rom_.get());
189
190 status = drawer.DrawObject(max_coord_object, bg1_, bg2_, palette_group);
191 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
192}
193
194// Test object drawer with multiple objects
195TEST_F(ObjectRenderingTest, ObjectDrawerHandlesMultipleObjects) {
196 ObjectDrawer drawer(rom_.get());
197 auto palette_group = CreateTestPaletteGroup();
198
199 std::vector<RoomObject> objects;
200
201 // Create various test objects
202 objects.emplace_back(0x00, 5, 5, 3, 0); // Horizontal floor
203 objects.emplace_back(0x01, 10, 10, 2, 0); // Vertical floor
204 objects.emplace_back(0x09, 15, 15, 4, 0); // Diagonal stairs
205 objects.emplace_back(0x34, 20, 20, 1, 1); // Solid block on BG2
206
207 // Set ROM for all objects
208 for (auto& obj : objects) {
209 obj.set_rom(rom_.get());
210 }
211
212 auto status = drawer.DrawObjectList(objects, bg1_, bg2_, palette_group);
213 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
214}
215
216// Test specific draw routines
217TEST_F(ObjectRenderingTest, DrawRoutinesWorkCorrectly) {
218 ObjectDrawer drawer(rom_.get());
219 auto palette_group = CreateTestPaletteGroup();
220
221 // Test rightward patterns
222 RoomObject rightward_obj(0x00, 5, 5, 5, 0);
223 rightward_obj.set_rom(rom_.get());
224
225 auto status = drawer.DrawObject(rightward_obj, bg1_, bg2_, palette_group);
226 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
227
228 // Test diagonal patterns
229 RoomObject diagonal_obj(0x09, 10, 10, 6, 0);
230 diagonal_obj.set_rom(rom_.get());
231
232 status = drawer.DrawObject(diagonal_obj, bg1_, bg2_, palette_group);
233 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
234
235 // Test solid block patterns
236 RoomObject solid_obj(0x34, 15, 15, 8, 0);
237 solid_obj.set_rom(rom_.get());
238
239 status = drawer.DrawObject(solid_obj, bg1_, bg2_, palette_group);
240 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
241}
242
243// Test object drawer error handling
244TEST_F(ObjectRenderingTest, ObjectDrawerHandlesErrorsGracefully) {
245 ObjectDrawer drawer(nullptr); // No ROM
246 auto palette_group = CreateTestPaletteGroup();
247
248 RoomObject test_object(0x00, 5, 5, 1, 0);
249
250 auto status = drawer.DrawObject(test_object, bg1_, bg2_, palette_group);
251 EXPECT_FALSE(status.ok());
252 EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
253}
254
255// Test object parser with various object IDs
256TEST_F(ObjectRenderingTest, ObjectParserHandlesVariousObjectIDs) {
257 ObjectParser parser(rom_.get());
258
259 // Test subtype 1 objects (0x00-0xFF)
260 for (int id = 0; id <= 0x40; id += 4) { // Test every 4th object
261 auto info = parser.GetObjectDrawInfo(id);
262 EXPECT_GE(info.draw_routine_id, 0);
263 EXPECT_LT(info.draw_routine_id, 25); // Should be within valid range
264 EXPECT_FALSE(info.routine_name.empty());
265 }
266
267 // Test some specific important objects
268 std::vector<int16_t> important_objects = {
269 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
270 0x0A, 0x0B, 0x15, 0x16, 0x21, 0x22, 0x2F, 0x30, 0x31, 0x32,
271 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
272 0x3D, 0x3E, 0x3F, 0x40
273 };
274
275 for (int16_t obj_id : important_objects) {
276 auto info = parser.GetObjectDrawInfo(obj_id);
277 EXPECT_GE(info.draw_routine_id, 0);
278 EXPECT_LT(info.draw_routine_id, 25);
279 EXPECT_FALSE(info.routine_name.empty());
280
281 // Verify tile count is reasonable
282 EXPECT_GT(info.tile_count, 0);
283 EXPECT_LE(info.tile_count, 64); // Reasonable upper bound
284 }
285}
286
287// Test object drawer performance with many objects
288TEST_F(ObjectRenderingTest, ObjectDrawerPerformanceTest) {
289 ObjectDrawer drawer(rom_.get());
290 auto palette_group = CreateTestPaletteGroup();
291
292 std::vector<RoomObject> objects;
293
294 // Create 100 test objects
295 for (int i = 0; i < 100; ++i) {
296 int id = i % 65; // Cycle through object IDs 0-64
297 int x = (i * 2) % 60; // Spread across buffer
298 int y = (i * 3) % 60;
299 int size = (i % 8) + 1; // Size 1-8
300 int layer = i % 2; // Alternate layers
301
302 objects.emplace_back(id, x, y, size, layer);
303 objects.back().set_rom(rom_.get());
304 }
305
306 // Time the drawing operation
307 auto start_time = std::chrono::high_resolution_clock::now();
308
309 auto status = drawer.DrawObjectList(objects, bg1_, bg2_, palette_group);
310
311 auto end_time = std::chrono::high_resolution_clock::now();
312 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
313 end_time - start_time);
314
315 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
316
317 // Should complete in reasonable time (less than 1 second for 100 objects)
318 EXPECT_LT(duration.count(), 1000);
319
320 std::cout << "Drew 100 objects in " << duration.count() << "ms" << std::endl;
321}
322
323} // namespace zelda3
324} // namespace yaze
SNES Color container.
Definition snes_color.h:38
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void AddColor(const SnesColor &color)
Draws dungeon objects to background buffers using game patterns.
absl::Status DrawObjectList(const std::vector< RoomObject > &objects, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group)
Draw all objects in a room.
absl::Status DrawObject(const RoomObject &object, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group)
Draw a room object to background buffers.
Direct ROM parser for dungeon objects.
ObjectDrawInfo GetObjectDrawInfo(int16_t object_id) const
Get draw routine information for an object.
void set_rom(Rom *rom)
Definition room_object.h:67
TEST_F(DungeonEditorSystemIntegrationTest, BasicInitialization)
Main namespace for the application.
Represents a group of palettes.
void AddPalette(SnesPalette pal)