yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
rightwards_routines.cc
Go to the documentation of this file.
2
5
6namespace yaze {
7namespace zelda3 {
8namespace draw_routines {
9
11 // Pattern: Draws 2x2 tiles rightward (object 0x00)
12 // Size byte determines how many times to repeat (1-15 or 32)
13 // ROM tile order is COLUMN-MAJOR: [col0_row0, col0_row1, col1_row0, col1_row1]
14 int size = ctx.object.size_;
15 if (size == 0)
16 size = 32; // Special case for object 0x00
17
18 for (int s = 0; s < size; s++) {
19 if (ctx.tiles.size() >= 4) {
20 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
21 // tiles[0] → $BF → (col 0, row 0) = top-left
22 // tiles[1] → $CB → (col 0, row 1) = bottom-left
23 // tiles[2] → $C2 → (col 1, row 0) = top-right
24 // tiles[3] → $CE → (col 1, row 1) = bottom-right
26 ctx.object.y_, ctx.tiles[0]); // col 0, row 0
28 ctx.object.y_ + 1, ctx.tiles[1]); // col 0, row 1
29 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
30 ctx.object.y_, ctx.tiles[2]); // col 1, row 0
31 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
32 ctx.object.y_ + 1, ctx.tiles[3]); // col 1, row 1
33 }
34 }
35}
36
38 // Pattern: Draws 2x4 tiles rightward (objects 0x01-0x02)
39 // Uses RoomDraw_Nx4 with N=2, tiles are COLUMN-MAJOR:
40 // [col0_row0, col0_row1, col0_row2, col0_row3, col1_row0, col1_row1, col1_row2, col1_row3]
41 int size = ctx.object.size_;
42 if (size == 0)
43 size = 26; // Special case
44
45 for (int s = 0; s < size; s++) {
46 if (ctx.tiles.size() >= 8) {
47 // Draw 2x4 pattern in COLUMN-MAJOR order (matching RoomDraw_Nx4)
48 // Column 0 (tiles 0-3)
50 ctx.object.y_, ctx.tiles[0]); // col 0, row 0
52 ctx.object.y_ + 1, ctx.tiles[1]); // col 0, row 1
54 ctx.object.y_ + 2, ctx.tiles[2]); // col 0, row 2
56 ctx.object.y_ + 3, ctx.tiles[3]); // col 0, row 3
57 // Column 1 (tiles 4-7)
58 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
59 ctx.object.y_, ctx.tiles[4]); // col 1, row 0
60 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
61 ctx.object.y_ + 1, ctx.tiles[5]); // col 1, row 1
62 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
63 ctx.object.y_ + 2, ctx.tiles[6]); // col 1, row 2
64 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
65 ctx.object.y_ + 3, ctx.tiles[7]); // col 1, row 3
66 } else if (ctx.tiles.size() >= 4) {
67 // Fallback: with 4 tiles we can only draw 1 column (1x4 pattern)
69 ctx.object.y_, ctx.tiles[0]);
71 ctx.object.y_ + 1, ctx.tiles[1]);
73 ctx.object.y_ + 2, ctx.tiles[2]);
75 ctx.object.y_ + 3, ctx.tiles[3]);
76 }
77 }
78}
79
81 // Pattern: Draws 2x4 tiles rightward with adjacent spacing (objects 0x03-0x04)
82 // Uses RoomDraw_Nx4 with N=2, tiles are COLUMN-MAJOR
83 // ASM: GetSize_1to16 means count = size + 1
84 int size = ctx.object.size_ & 0x0F;
85 int count = size + 1;
86
87 for (int s = 0; s < count; s++) {
88 if (ctx.tiles.size() >= 8) {
89 // Draw 2x4 pattern in COLUMN-MAJOR order with adjacent spacing (s * 2)
90 // Column 0 (tiles 0-3)
92 ctx.object.y_, ctx.tiles[0]); // col 0, row 0
94 ctx.object.y_ + 1, ctx.tiles[1]); // col 0, row 1
96 ctx.object.y_ + 2, ctx.tiles[2]); // col 0, row 2
98 ctx.object.y_ + 3, ctx.tiles[3]); // col 0, row 3
99 // Column 1 (tiles 4-7)
100 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
101 ctx.object.y_, ctx.tiles[4]); // col 1, row 0
102 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
103 ctx.object.y_ + 1, ctx.tiles[5]); // col 1, row 1
104 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
105 ctx.object.y_ + 2, ctx.tiles[6]); // col 1, row 2
106 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
107 ctx.object.y_ + 3, ctx.tiles[7]); // col 1, row 3
108 } else if (ctx.tiles.size() >= 4) {
109 // Fallback: with 4 tiles we can only draw 1 column (1x4 pattern)
111 ctx.object.y_, ctx.tiles[0]);
113 ctx.object.y_ + 1, ctx.tiles[1]);
115 ctx.object.y_ + 2, ctx.tiles[2]);
117 ctx.object.y_ + 3, ctx.tiles[3]);
118 }
119 }
120}
121
123 // Pattern: Same as DrawRightwards2x4_1to16 but draws to both BG1 and BG2 (objects 0x05-0x06)
125 // Note: BothBG would require access to both buffers - simplified for now
126}
127
129 // Pattern: Draws 2x2 tiles rightward (objects 0x07-0x08)
130 // ROM tile order is COLUMN-MAJOR: [col0_row0, col0_row1, col1_row0, col1_row1]
131 int size = ctx.object.size_ & 0x0F;
132
133 // Assembly: JSR RoomDraw_GetSize_1to16
134 // GetSize_1to16: count = size + 1
135 int count = size + 1;
136
137 for (int s = 0; s < count; s++) {
138 if (ctx.tiles.size() >= 4) {
139 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
141 ctx.object.y_, ctx.tiles[0]); // col 0, row 0
143 ctx.object.y_ + 1, ctx.tiles[1]); // col 0, row 1
144 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
145 ctx.object.y_, ctx.tiles[2]); // col 1, row 0
146 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 2) + 1,
147 ctx.object.y_ + 1, ctx.tiles[3]); // col 1, row 1
148 }
149 }
150}
151
153 // Pattern: 1x2 tiles rightward with +2 offset (object 0x21)
154 int size = ctx.object.size_ & 0x0F;
155
156 // Assembly: (size << 1) + 1 = (size * 2) + 1
157 int count = (size * 2) + 1;
158
159 for (int s = 0; s < count; s++) {
160 if (ctx.tiles.size() >= 2) {
161 // Use first tile span for 1x2 pattern
163 ctx.object.y_, ctx.tiles[0]);
165 ctx.object.y_ + 1, ctx.tiles[1]);
166 }
167 }
168}
169
171 // Pattern: 1x1 tiles with edge detection +3 offset (object 0x22)
172 int size = ctx.object.size_ & 0x0F;
173
174 // Assembly: GetSize_1to16_timesA(2), so count = size + 2
175 int count = size + 2;
176
177 for (int s = 0; s < count; s++) {
178 if (ctx.tiles.size() >= 1) {
179 // Use first 8x8 tile from span
181 ctx.object.y_, ctx.tiles[0]);
182 }
183 }
184}
185
187 // Pattern: 1x1 tiles with edge detection +2 offset (objects 0x23-0x2E, 0x3F-0x46)
188 int size = ctx.object.size_ & 0x0F;
189
190 // Assembly: GetSize_1to16, so count = size + 1
191 int count = size + 1;
192
193 for (int s = 0; s < count; s++) {
194 if (ctx.tiles.size() >= 1) {
195 // Use first 8x8 tile from span
197 ctx.object.y_, ctx.tiles[0]);
198 }
199 }
200}
201
203 // Pattern: Top corner 1x2 tiles with +13 offset (object 0x2F)
204 int size = ctx.object.size_ & 0x0F;
205
206 // Assembly: GetSize_1to16_timesA(0x0A), so count = size + 10
207 int count = size + 10;
208
209 for (int s = 0; s < count; s++) {
210 if (ctx.tiles.size() >= 2) {
211 // Use first tile span for 1x2 pattern
213 ctx.object.y_, ctx.tiles[0]);
215 ctx.object.y_ + 1, ctx.tiles[1]);
216 }
217 }
218}
219
221 // Pattern: Bottom corner 1x2 tiles with +13 offset (object 0x30)
222 int size = ctx.object.size_ & 0x0F;
223
224 // Assembly: GetSize_1to16_timesA(0x0A), so count = size + 10
225 int count = size + 10;
226
227 for (int s = 0; s < count; s++) {
228 if (ctx.tiles.size() >= 2) {
229 // Use first tile span for 1x2 pattern
231 ctx.object.y_ + 1, ctx.tiles[0]);
233 ctx.object.y_ + 2, ctx.tiles[1]);
234 }
235 }
236}
237
239 // Pattern: 4x4 block rightward (object 0x33)
240 int size = ctx.object.size_ & 0x0F;
241
242 // Assembly: GetSize_1to16, so count = size + 1
243 int count = size + 1;
244
245 for (int s = 0; s < count; s++) {
246 if (ctx.tiles.size() >= 16) {
247 // Draw 4x4 pattern in COLUMN-MAJOR order (matching assembly)
248 // Iterate columns (x) first, then rows (y) within each column
249 for (int x = 0; x < 4; ++x) {
250 for (int y = 0; y < 4; ++y) {
251 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 4) + x,
252 ctx.object.y_ + y, ctx.tiles[x * 4 + y]);
253 }
254 }
255 }
256 }
257}
258
260 // Pattern: 1x1 solid tiles +3 offset (object 0x34)
261 int size = ctx.object.size_ & 0x0F;
262
263 // Assembly: GetSize_1to16_timesA(4), so count = size + 4
264 int count = size + 4;
265
266 for (int s = 0; s < count; s++) {
267 if (ctx.tiles.size() >= 1) {
268 // Use first 8x8 tile from span
270 ctx.object.y_, ctx.tiles[0]);
271 }
272 }
273}
274
276 // Pattern: 4x4 decoration with spacing (objects 0x36-0x37)
277 int size = ctx.object.size_ & 0x0F;
278
279 // Assembly: GetSize_1to16, so count = size + 1
280 int count = size + 1;
281
282 for (int s = 0; s < count; s++) {
283 if (ctx.tiles.size() >= 16) {
284 // Draw 4x4 pattern with spacing in COLUMN-MAJOR order (matching assembly)
285 for (int x = 0; x < 4; ++x) {
286 for (int y = 0; y < 4; ++y) {
287 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 6) + x,
288 ctx.object.y_ + y, ctx.tiles[x * 4 + y]);
289 }
290 }
291 }
292 }
293}
294
296 // Pattern: 2x3 statue with spacing (object 0x38)
297 // 2 columns × 3 rows = 6 tiles in COLUMN-MAJOR order
298 int size = ctx.object.size_ & 0x0F;
299
300 // Assembly: GetSize_1to16, so count = size + 1
301 int count = size + 1;
302
303 for (int s = 0; s < count; s++) {
304 if (ctx.tiles.size() >= 6) {
305 // Draw 2x3 pattern in COLUMN-MAJOR order (matching assembly)
306 for (int x = 0; x < 2; ++x) {
307 for (int y = 0; y < 3; ++y) {
308 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 4) + x,
309 ctx.object.y_ + y, ctx.tiles[x * 3 + y]);
310 }
311 }
312 }
313 }
314}
315
317 // Pattern: 2x4 pillar with spacing (objects 0x39, 0x3D)
318 // 2 columns × 4 rows = 8 tiles in COLUMN-MAJOR order
319 int size = ctx.object.size_ & 0x0F;
320
321 // Assembly: GetSize_1to16, so count = size + 1
322 int count = size + 1;
323
324 for (int s = 0; s < count; s++) {
325 if (ctx.tiles.size() >= 8) {
326 // Draw 2x4 pattern in COLUMN-MAJOR order (matching assembly)
327 for (int x = 0; x < 2; ++x) {
328 for (int y = 0; y < 4; ++y) {
329 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 6) + x,
330 ctx.object.y_ + y, ctx.tiles[x * 4 + y]);
331 }
332 }
333 }
334 }
335}
336
338 // Pattern: 4x3 decoration with spacing (objects 0x3A-0x3B)
339 // 4 columns × 3 rows = 12 tiles in COLUMN-MAJOR order
340 int size = ctx.object.size_ & 0x0F;
341
342 // Assembly: GetSize_1to16, so count = size + 1
343 int count = size + 1;
344
345 for (int s = 0; s < count; s++) {
346 if (ctx.tiles.size() >= 12) {
347 // Draw 4x3 pattern in COLUMN-MAJOR order (matching assembly)
348 for (int x = 0; x < 4; ++x) {
349 for (int y = 0; y < 3; ++y) {
350 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 6) + x,
351 ctx.object.y_ + y, ctx.tiles[x * 3 + y]);
352 }
353 }
354 }
355 }
356}
357
359 // Pattern: Doubled 2x2 with spacing (object 0x3C)
360 // 4 columns × 2 rows = 8 tiles in COLUMN-MAJOR order
361 int size = ctx.object.size_ & 0x0F;
362
363 // Assembly: GetSize_1to16, so count = size + 1
364 int count = size + 1;
365
366 for (int s = 0; s < count; s++) {
367 if (ctx.tiles.size() >= 8) {
368 // Draw doubled 2x2 pattern in COLUMN-MAJOR order (matching assembly)
369 for (int x = 0; x < 4; ++x) {
370 for (int y = 0; y < 2; ++y) {
371 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 6) + x,
372 ctx.object.y_ + y, ctx.tiles[x * 2 + y]);
373 }
374 }
375 }
376 }
377}
378
380 // Pattern: 2x2 decoration with large spacing (object 0x3E)
381 int size = ctx.object.size_ & 0x0F;
382
383 // Assembly: GetSize_1to16, so count = size + 1
384 int count = size + 1;
385
386 for (int s = 0; s < count; s++) {
387 if (ctx.tiles.size() >= 4) {
388 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
389 // tiles[0] → col 0, row 0 = top-left
390 // tiles[1] → col 0, row 1 = bottom-left
391 // tiles[2] → col 1, row 0 = top-right
392 // tiles[3] → col 1, row 1 = bottom-right
394 ctx.object.y_, ctx.tiles[0]); // col 0, row 0
396 ctx.object.y_ + 1, ctx.tiles[1]); // col 0, row 1
397 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 14) + 1,
398 ctx.object.y_, ctx.tiles[2]); // col 1, row 0
399 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + (s * 14) + 1,
400 ctx.object.y_ + 1, ctx.tiles[3]); // col 1, row 1
401 }
402 }
403}
404
405void RegisterRightwardsRoutines(std::vector<DrawRoutineInfo>& registry) {
406 // Note: Routine IDs are assigned based on the assembly routine table
407 // These rightwards routines are part of the core 40 draw routines
408 // Uses canonical IDs from DrawRoutineIds namespace
409
410 registry.push_back(DrawRoutineInfo{
412 .name = "Rightwards2x2_1to15or32",
413 .function = DrawRightwards2x2_1to15or32,
414 .draws_to_both_bgs = false,
415 .base_width = 2,
416 .base_height = 2,
418 });
419
420 registry.push_back(DrawRoutineInfo{
422 .name = "Rightwards2x4_1to15or26",
423 .function = DrawRightwards2x4_1to15or26,
424 .draws_to_both_bgs = false,
425 .base_width = 2,
426 .base_height = 4,
428 });
429
430 registry.push_back(DrawRoutineInfo{
432 .name = "Rightwards2x4_1to16",
433 .function = DrawRightwards2x4_1to16,
434 .draws_to_both_bgs = false,
435 .base_width = 2, // Adjacent spacing (s * 2)
436 .base_height = 4,
438 });
439
440 registry.push_back(DrawRoutineInfo{
442 .name = "Rightwards2x4_1to16_BothBG",
444 .draws_to_both_bgs = true,
445 .base_width = 2, // Adjacent spacing (s * 2)
446 .base_height = 4,
448 });
449
450 registry.push_back(DrawRoutineInfo{
452 .name = "Rightwards2x2_1to16",
453 .function = DrawRightwards2x2_1to16,
454 .draws_to_both_bgs = false,
455 .base_width = 2,
456 .base_height = 2,
458 });
459
460 registry.push_back(DrawRoutineInfo{
462 .name = "Rightwards1x2_1to16_plus2",
464 .draws_to_both_bgs = false,
465 .base_width = 1,
466 .base_height = 2,
468 });
469
470 registry.push_back(DrawRoutineInfo{
472 .name = "RightwardsHasEdge1x1_1to16_plus3",
474 .draws_to_both_bgs = false,
475 .base_width = 1,
476 .base_height = 1,
478 });
479
480 registry.push_back(DrawRoutineInfo{
482 .name = "RightwardsHasEdge1x1_1to16_plus2",
484 .draws_to_both_bgs = false,
485 .base_width = 1,
486 .base_height = 1,
488 });
489
490 registry.push_back(DrawRoutineInfo{
492 .name = "RightwardsTopCorners1x2_1to16_plus13",
494 .draws_to_both_bgs = false,
495 .base_width = 1,
496 .base_height = 2,
498 });
499
500 registry.push_back(DrawRoutineInfo{
502 .name = "RightwardsBottomCorners1x2_1to16_plus13",
504 .draws_to_both_bgs = false,
505 .base_width = 1,
506 .base_height = 2, // spans y+1 to y+2
508 });
509
510 registry.push_back(DrawRoutineInfo{
512 .name = "Rightwards4x4_1to16",
513 .function = DrawRightwards4x4_1to16,
514 .draws_to_both_bgs = false,
515 .base_width = 4,
516 .base_height = 4,
518 });
519
520 registry.push_back(DrawRoutineInfo{
522 .name = "Rightwards1x1Solid_1to16_plus3",
524 .draws_to_both_bgs = false,
525 .base_width = 1,
526 .base_height = 1,
528 });
529
530 registry.push_back(DrawRoutineInfo{
532 .name = "RightwardsDecor4x4spaced2_1to16",
534 .draws_to_both_bgs = false,
535 .base_width = 6, // 4 tiles + 2 spacing
536 .base_height = 4,
538 });
539
540 registry.push_back(DrawRoutineInfo{
542 .name = "RightwardsStatue2x3spaced2_1to16",
544 .draws_to_both_bgs = false,
545 .base_width = 4, // 2 tiles + 2 spacing
546 .base_height = 3,
548 });
549
550 registry.push_back(DrawRoutineInfo{
552 .name = "RightwardsPillar2x4spaced4_1to16",
554 .draws_to_both_bgs = false,
555 .base_width = 6, // 2 tiles + 4 spacing
556 .base_height = 4,
558 });
559
560 registry.push_back(DrawRoutineInfo{
562 .name = "RightwardsDecor4x3spaced4_1to16",
564 .draws_to_both_bgs = false,
565 .base_width = 6, // 4 tiles + 2 spacing (actually the calculation seems off, kept as is)
566 .base_height = 3,
568 });
569
570 registry.push_back(DrawRoutineInfo{
572 .name = "RightwardsDoubled2x2spaced2_1to16",
574 .draws_to_both_bgs = false,
575 .base_width = 6, // 4 tiles + 2 spacing
576 .base_height = 2,
578 });
579
580 registry.push_back(DrawRoutineInfo{
582 .name = "RightwardsDecor2x2spaced12_1to16",
584 .draws_to_both_bgs = false,
585 .base_width = 14, // 2 tiles + 12 spacing
586 .base_height = 2,
588 });
589}
590
591} // namespace draw_routines
592} // namespace zelda3
593} // namespace yaze
constexpr int kRightwardsBottomCorners1x2_1to16_plus13
constexpr int kRightwardsTopCorners1x2_1to16_plus13
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
Write an 8x8 tile to the background buffer.
void DrawRightwardsStatue2x3spaced2_1to16(const DrawContext &ctx)
Draw 2x3 statue with spacing.
void DrawRightwards2x4_1to15or26(const DrawContext &ctx)
Draw 2x4 tiles rightward (1-15 or 26 repetitions)
void DrawRightwards2x2_1to15or32(const DrawContext &ctx)
Draw 2x2 tiles rightward (1-15 or 32 repetitions)
void DrawRightwardsBottomCorners1x2_1to16_plus13(const DrawContext &ctx)
Draw bottom corner 1x2 tiles with +13 offset.
void DrawRightwardsTopCorners1x2_1to16_plus13(const DrawContext &ctx)
Draw top corner 1x2 tiles with +13 offset.
void DrawRightwardsHasEdge1x1_1to16_plus2(const DrawContext &ctx)
Draw 1x1 tiles with edge detection +2 offset.
void DrawRightwardsDecor2x2spaced12_1to16(const DrawContext &ctx)
Draw 2x2 decoration with large spacing.
void DrawRightwards1x1Solid_1to16_plus3(const DrawContext &ctx)
Draw 1x1 solid tiles +3 offset.
void DrawRightwards1x2_1to16_plus2(const DrawContext &ctx)
Draw 1x2 tiles rightward with +2 offset.
void DrawRightwards4x4_1to16(const DrawContext &ctx)
Draw 4x4 block rightward.
void DrawRightwardsHasEdge1x1_1to16_plus3(const DrawContext &ctx)
Draw 1x1 tiles with edge detection +3 offset.
void DrawRightwards2x2_1to16(const DrawContext &ctx)
Draw 2x2 tiles rightward (1-16 repetitions)
void DrawRightwardsDoubled2x2spaced2_1to16(const DrawContext &ctx)
Draw doubled 2x2 with spacing.
void DrawRightwards2x4_1to16(const DrawContext &ctx)
Draw 2x4 tiles rightward with adjacent spacing (1-16 repetitions)
void RegisterRightwardsRoutines(std::vector< DrawRoutineInfo > &registry)
Register all rightwards draw routines to the registry.
void DrawRightwardsDecor4x3spaced4_1to16(const DrawContext &ctx)
Draw 4x3 decoration with spacing.
void DrawRightwards2x4_1to16_BothBG(const DrawContext &ctx)
Draw 2x4 tiles rightward with adjacent spacing to both BG layers.
void DrawRightwardsPillar2x4spaced4_1to16(const DrawContext &ctx)
Draw 2x4 pillar with spacing.
void DrawRightwardsDecor4x4spaced2_1to16(const DrawContext &ctx)
Draw 4x4 decoration with spacing.
Context passed to draw routines containing all necessary state.
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
Metadata about a draw routine.