yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_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"
11
12namespace yaze {
13namespace zelda3 {
14
15class DungeonRenderingIntegrationTest : public ::testing::Test {
16 protected:
17 void SetUp() override {
18 // Create a mock ROM for testing
19 rom_ = std::make_unique<Rom>();
20 // Initialize with minimal ROM data for testing
21 std::vector<uint8_t> mock_rom_data(1024 * 1024, 0); // 1MB mock ROM
22 rom_->LoadFromData(mock_rom_data);
23
24 // Create test rooms
25 room_0x00_ = CreateTestRoom(0x00); // Link's House
26 room_0x01_ = CreateTestRoom(0x01); // Another test room
27 }
28
29 void TearDown() override {
30 rom_.reset();
31 }
32
33 std::unique_ptr<Rom> rom_;
34
35 // Create a test room with various objects
36 Room CreateTestRoom(int room_id) {
37 Room room(room_id, rom_.get());
38
39 // Add some test objects to the room
40 std::vector<RoomObject> objects;
41
42 // Add floor objects (object 0x00)
43 objects.emplace_back(0x00, 5, 5, 3, 0); // Horizontal floor
44 objects.emplace_back(0x00, 10, 10, 5, 0); // Another floor section
45
46 // Add wall objects (object 0x01)
47 objects.emplace_back(0x01, 15, 15, 2, 0); // Vertical wall
48 objects.emplace_back(0x01, 20, 20, 4, 1); // Horizontal wall on BG2
49
50 // Add diagonal stairs (object 0x09)
51 objects.emplace_back(0x09, 25, 25, 6, 0); // Diagonal stairs
52
53 // Add solid blocks (object 0x34)
54 objects.emplace_back(0x34, 30, 30, 1, 0); // Solid block
55 objects.emplace_back(0x34, 35, 35, 2, 1); // Another solid block on BG2
56
57 // Set ROM for all objects
58 for (auto& obj : objects) {
59 obj.set_rom(rom_.get());
60 }
61
62 // Add objects to room (this would normally be done by LoadObjects)
63 for (const auto& obj : objects) {
64 room.AddObject(obj);
65 }
66
67 return room;
68 }
69
70 // Create a test palette
72 gfx::SnesPalette palette;
73 // Add some test colors
74 palette.AddColor(gfx::SnesColor(0, 0, 0)); // Transparent
75 palette.AddColor(gfx::SnesColor(255, 0, 0)); // Red
76 palette.AddColor(gfx::SnesColor(0, 255, 0)); // Green
77 palette.AddColor(gfx::SnesColor(0, 0, 255)); // Blue
78 palette.AddColor(gfx::SnesColor(255, 255, 0)); // Yellow
79 palette.AddColor(gfx::SnesColor(255, 0, 255)); // Magenta
80 palette.AddColor(gfx::SnesColor(0, 255, 255)); // Cyan
81 palette.AddColor(gfx::SnesColor(255, 255, 255)); // White
82 return palette;
83 }
84
90
91 private:
94};
95
96// Test full room rendering with ObjectDrawer
97TEST_F(DungeonRenderingIntegrationTest, FullRoomRenderingWorks) {
98 Room test_room = CreateTestRoom(0x00);
99
100 // Test that room has objects
101 EXPECT_GT(test_room.GetTileObjects().size(), 0);
102
103 // Test ObjectDrawer can render the room
104 ObjectDrawer drawer(rom_.get());
105 auto palette_group = CreateTestPaletteGroup();
106
107 auto status = drawer.DrawObjectList(test_room.GetTileObjects(),
108 test_room.bg1_buffer(),
109 test_room.bg2_buffer(),
110 palette_group);
111
112 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
113}
114
115// Test room rendering with different palette configurations
116TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithDifferentPalettes) {
117 Room test_room = CreateTestRoom(0x00);
118 ObjectDrawer drawer(rom_.get());
119
120 // Test with different palette configurations
121 std::vector<gfx::PaletteGroup> palette_groups;
122
123 // Create multiple palette groups
124 for (int i = 0; i < 3; ++i) {
125 palette_groups.push_back(CreateTestPaletteGroup());
126 }
127
128 for (const auto& palette_group : palette_groups) {
129 auto status = drawer.DrawObjectList(test_room.GetTileObjects(),
130 test_room.bg1_buffer(),
131 test_room.bg2_buffer(),
132 palette_group);
133
134 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
135 }
136}
137
138// Test room rendering with objects on different layers
139TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithMultipleLayers) {
140 Room test_room = CreateTestRoom(0x00);
141 ObjectDrawer drawer(rom_.get());
142 auto palette_group = CreateTestPaletteGroup();
143
144 // Separate objects by layer
145 std::vector<RoomObject> bg1_objects;
146 std::vector<RoomObject> bg2_objects;
147
148 for (const auto& obj : test_room.GetTileObjects()) {
149 if (obj.GetLayerValue() == 0) {
150 bg1_objects.push_back(obj);
151 } else if (obj.GetLayerValue() == 1) {
152 bg2_objects.push_back(obj);
153 }
154 }
155
156 // Render BG1 objects
157 if (!bg1_objects.empty()) {
158 auto status = drawer.DrawObjectList(bg1_objects,
159 test_room.bg1_buffer(),
160 test_room.bg2_buffer(),
161 palette_group);
162 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
163 }
164
165 // Render BG2 objects
166 if (!bg2_objects.empty()) {
167 auto status = drawer.DrawObjectList(bg2_objects,
168 test_room.bg1_buffer(),
169 test_room.bg2_buffer(),
170 palette_group);
171 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
172 }
173}
174
175// Test room rendering with various object sizes
176TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithVariousObjectSizes) {
177 Room test_room = CreateTestRoom(0x00);
178 ObjectDrawer drawer(rom_.get());
179 auto palette_group = CreateTestPaletteGroup();
180
181 // Group objects by size
182 std::map<int, std::vector<RoomObject>> objects_by_size;
183
184 for (const auto& obj : test_room.GetTileObjects()) {
185 objects_by_size[obj.size_].push_back(obj);
186 }
187
188 // Render objects of each size
189 for (const auto& [size, objects] : objects_by_size) {
190 auto status = drawer.DrawObjectList(objects,
191 test_room.bg1_buffer(),
192 test_room.bg2_buffer(),
193 palette_group);
194 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
195 }
196}
197
198// Test room rendering performance
199TEST_F(DungeonRenderingIntegrationTest, RoomRenderingPerformance) {
200 // Create a room with many objects
201 Room large_room(0x00, rom_.get());
202
203 // Add many test objects
204 for (int i = 0; i < 200; ++i) {
205 int id = i % 65; // Cycle through object IDs 0-64
206 int x = (i * 2) % 60; // Spread across buffer
207 int y = (i * 3) % 60;
208 int size = (i % 8) + 1; // Size 1-8
209 int layer = i % 2; // Alternate layers
210
211 RoomObject obj(id, x, y, size, layer);
212 obj.set_rom(rom_.get());
213 large_room.AddObject(obj);
214 }
215
216 ObjectDrawer drawer(rom_.get());
217 auto palette_group = CreateTestPaletteGroup();
218
219 // Time the rendering operation
220 auto start_time = std::chrono::high_resolution_clock::now();
221
222 auto status = drawer.DrawObjectList(large_room.GetTileObjects(),
223 large_room.bg1_buffer(),
224 large_room.bg2_buffer(),
225 palette_group);
226
227 auto end_time = std::chrono::high_resolution_clock::now();
228 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
229 end_time - start_time);
230
231 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
232
233 // Should complete in reasonable time (less than 2 seconds for 200 objects)
234 EXPECT_LT(duration.count(), 2000);
235
236 std::cout << "Rendered room with 200 objects in " << duration.count() << "ms" << std::endl;
237}
238
239// Test room rendering with edge case coordinates
240TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithEdgeCaseCoordinates) {
241 Room test_room = CreateTestRoom(0x00);
242 ObjectDrawer drawer(rom_.get());
243 auto palette_group = CreateTestPaletteGroup();
244
245 // Add objects at edge coordinates
246 std::vector<RoomObject> edge_objects;
247
248 edge_objects.emplace_back(0x34, 0, 0, 1, 0); // Origin
249 edge_objects.emplace_back(0x34, 63, 63, 1, 0); // Near buffer edge
250 edge_objects.emplace_back(0x34, 32, 32, 1, 0); // Center
251 edge_objects.emplace_back(0x34, 1, 1, 1, 0); // Near origin
252 edge_objects.emplace_back(0x34, 62, 62, 1, 0); // Near edge
253
254 // Set ROM for all objects
255 for (auto& obj : edge_objects) {
256 obj.set_rom(rom_.get());
257 }
258
259 auto status = drawer.DrawObjectList(edge_objects,
260 test_room.bg1_buffer(),
261 test_room.bg2_buffer(),
262 palette_group);
263
264 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
265}
266
267// Test room rendering with mixed object types
268TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithMixedObjectTypes) {
269 Room test_room = CreateTestRoom(0x00);
270 ObjectDrawer drawer(rom_.get());
271 auto palette_group = CreateTestPaletteGroup();
272
273 // Add various object types
274 std::vector<RoomObject> mixed_objects;
275
276 // Floor objects
277 mixed_objects.emplace_back(0x00, 5, 5, 3, 0);
278 mixed_objects.emplace_back(0x01, 10, 10, 2, 0);
279
280 // Wall objects
281 mixed_objects.emplace_back(0x02, 15, 15, 4, 0);
282 mixed_objects.emplace_back(0x03, 20, 20, 1, 1);
283
284 // Diagonal objects
285 mixed_objects.emplace_back(0x09, 25, 25, 5, 0);
286 mixed_objects.emplace_back(0x0A, 30, 30, 3, 0);
287
288 // Solid objects
289 mixed_objects.emplace_back(0x34, 35, 35, 1, 0);
290 mixed_objects.emplace_back(0x33, 40, 40, 2, 1);
291
292 // Decorative objects
293 mixed_objects.emplace_back(0x36, 45, 45, 3, 0);
294 mixed_objects.emplace_back(0x38, 50, 50, 1, 0);
295
296 // Set ROM for all objects
297 for (auto& obj : mixed_objects) {
298 obj.set_rom(rom_.get());
299 }
300
301 auto status = drawer.DrawObjectList(mixed_objects,
302 test_room.bg1_buffer(),
303 test_room.bg2_buffer(),
304 palette_group);
305
306 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
307}
308
309// Test room rendering error handling
310TEST_F(DungeonRenderingIntegrationTest, RoomRenderingErrorHandling) {
311 Room test_room = CreateTestRoom(0x00);
312
313 // Test with null ROM
314 ObjectDrawer null_drawer(nullptr);
315 auto palette_group = CreateTestPaletteGroup();
316
317 auto status = null_drawer.DrawObjectList(test_room.GetTileObjects(),
318 test_room.bg1_buffer(),
319 test_room.bg2_buffer(),
320 palette_group);
321
322 EXPECT_FALSE(status.ok());
323 EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
324}
325
326// Test room rendering with invalid object data
327TEST_F(DungeonRenderingIntegrationTest, RoomRenderingWithInvalidObjectData) {
328 Room test_room = CreateTestRoom(0x00);
329 ObjectDrawer drawer(rom_.get());
330 auto palette_group = CreateTestPaletteGroup();
331
332 // Create objects with invalid data
333 std::vector<RoomObject> invalid_objects;
334
335 invalid_objects.emplace_back(0x999, 5, 5, 1, 0); // Invalid object ID
336 invalid_objects.emplace_back(0x00, -1, -1, 1, 0); // Negative coordinates
337 invalid_objects.emplace_back(0x00, 100, 100, 1, 0); // Out of bounds coordinates
338 invalid_objects.emplace_back(0x00, 5, 5, 255, 0); // Maximum size
339
340 // Set ROM for all objects
341 for (auto& obj : invalid_objects) {
342 obj.set_rom(rom_.get());
343 }
344
345 // Should handle gracefully
346 auto status = drawer.DrawObjectList(invalid_objects,
347 test_room.bg1_buffer(),
348 test_room.bg2_buffer(),
349 palette_group);
350
351 // Should succeed or fail gracefully
352 EXPECT_TRUE(status.ok() || status.code() == absl::StatusCode::kOk);
353}
354
355} // namespace zelda3
356} // 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.
void set_rom(Rom *rom)
Definition room_object.h:67
auto & bg1_buffer()
Definition room.h:389
const std::vector< RoomObject > & GetTileObjects() const
Definition room.h:220
absl::Status AddObject(const RoomObject &object)
Definition room.cc:829
auto & bg2_buffer()
Definition room.h:390
TEST_F(DungeonEditorSystemIntegrationTest, BasicInitialization)
Main namespace for the application.
Represents a group of palettes.
void AddPalette(SnesPalette pal)