yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
downwards_routines.cc
Go to the documentation of this file.
2
5
6namespace yaze {
7namespace zelda3 {
8namespace draw_routines {
9
10namespace {
11
12void DrawDownwardsCorners2x1(const DrawContext& ctx, bool edge_is_left) {
13 if (ctx.tiles.size() < 6) {
14 return;
15 }
16
17 // USDASM caches tile 0 as the solid column. Tiles 1-2 form the opening
18 // cap, tile 3 repeats for size+10 rows, and tiles 4-5 form the closing cap.
19 // The routine name's "+12" is the minimum extent, not an X offset.
20 const int body_count = (ctx.object.size_ & 0x0F) + 10;
21 const int edge_x = ctx.object.x_ + (edge_is_left ? 0 : 1);
22 const int fill_x = ctx.object.x_ + (edge_is_left ? 1 : 0);
23 int y = ctx.object.y_;
24
25 if (!DrawRoutineUtils::ExistingTileMatchesAny(ctx, edge_x, y, {0x00E3})) {
26 DrawRoutineUtils::WriteTile8(ctx.target_bg, edge_x, y, ctx.tiles[1]);
27 DrawRoutineUtils::WriteTile8(ctx.target_bg, edge_x, y + 1, ctx.tiles[2]);
28 DrawRoutineUtils::WriteTile8(ctx.target_bg, fill_x, y, ctx.tiles[0]);
29 DrawRoutineUtils::WriteTile8(ctx.target_bg, fill_x, y + 1, ctx.tiles[0]);
30 y += 2;
31 }
32
33 for (int i = 0; i < body_count; ++i, ++y) {
34 DrawRoutineUtils::WriteTile8(ctx.target_bg, edge_x, y, ctx.tiles[3]);
35 DrawRoutineUtils::WriteTile8(ctx.target_bg, fill_x, y, ctx.tiles[0]);
36 }
37
38 DrawRoutineUtils::WriteTile8(ctx.target_bg, edge_x, y, ctx.tiles[4]);
39 DrawRoutineUtils::WriteTile8(ctx.target_bg, edge_x, y + 1, ctx.tiles[5]);
40 DrawRoutineUtils::WriteTile8(ctx.target_bg, fill_x, y, ctx.tiles[0]);
41 DrawRoutineUtils::WriteTile8(ctx.target_bg, fill_x, y + 1, ctx.tiles[0]);
42}
43
44} // namespace
45
47 // Pattern: Draws 2x2 tiles downward (object 0x60)
48 // Size byte determines how many times to repeat (1-15 or 32)
49 int size = ctx.object.size_;
50 if (size == 0)
51 size = 32; // Special case for object 0x60
52
53 for (int s = 0; s < size; s++) {
54 if (ctx.tiles.size() >= 4) {
55 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
56 // Assembly uses indirect pointers: $BF, $CB, $C2, $CE
57 // tiles[0] → $BF → (col 0, row 0) = top-left
58 // tiles[1] → $CB → (col 0, row 1) = bottom-left
59 // tiles[2] → $C2 → (col 1, row 0) = top-right
60 // tiles[3] → $CE → (col 1, row 1) = bottom-right
62 ctx.object.y_ + (s * 2),
63 ctx.tiles[0]); // col 0, row 0
65 ctx.object.y_ + (s * 2) + 1,
66 ctx.tiles[1]); // col 0, row 1
68 ctx.object.y_ + (s * 2),
69 ctx.tiles[2]); // col 1, row 0
71 ctx.object.y_ + (s * 2) + 1,
72 ctx.tiles[3]); // col 1, row 1
73 }
74 }
75}
76
78 // Pattern: Draws 4x2 tiles downward (objects 0x61-0x62)
79 // This is 4 columns × 2 rows = 8 tiles in ROW-MAJOR order (per ZScream)
80 int size = ctx.object.size_;
81 if (size == 0)
82 size = 26; // Special case
83
84 for (int s = 0; s < size; s++) {
85 if (ctx.tiles.size() >= 8) {
86 // Draw 4x2 pattern in ROW-MAJOR order (matching ZScream)
87 // Row 0: tiles 0, 1, 2, 3 at x+0, x+1, x+2, x+3
89 ctx.object.y_ + (s * 2), ctx.tiles[0]);
91 ctx.object.y_ + (s * 2), ctx.tiles[1]);
93 ctx.object.y_ + (s * 2), ctx.tiles[2]);
95 ctx.object.y_ + (s * 2), ctx.tiles[3]);
96 // Row 1: tiles 4, 5, 6, 7 at x+0, x+1, x+2, x+3
98 ctx.object.y_ + (s * 2) + 1, ctx.tiles[4]);
100 ctx.object.y_ + (s * 2) + 1, ctx.tiles[5]);
102 ctx.object.y_ + (s * 2) + 1, ctx.tiles[6]);
104 ctx.object.y_ + (s * 2) + 1, ctx.tiles[7]);
105 } else if (ctx.tiles.size() >= 4) {
106 // Fallback: with 4 tiles draw 4x1 row pattern
108 ctx.object.y_ + (s * 2), ctx.tiles[0]);
110 ctx.object.y_ + (s * 2), ctx.tiles[1]);
112 ctx.object.y_ + (s * 2), ctx.tiles[2]);
114 ctx.object.y_ + (s * 2), ctx.tiles[3]);
115 }
116 }
117}
118
120 // USDASM $01:8AA4 calls RoomDraw_GetSize_1to16, so the encoded size nibble
121 // is the zero-based repeat count. ObjectDrawer dispatches this routine once
122 // per background because the registry marks it as a BothBG writer.
123 const int count = (ctx.object.size_ & 0x0F) + 1;
124 if (ctx.tiles.size() < 8) {
125 return;
126 }
127
128 for (int s = 0; s < count; ++s) {
129 const int y = ctx.object.y_ + (s * 2);
132 ctx.tiles[1]);
134 ctx.tiles[2]);
136 ctx.tiles[3]);
138 ctx.tiles[4]);
140 ctx.tiles[5]);
142 ctx.tiles[6]);
144 ctx.tiles[7]);
145 }
146}
147
149 // Pattern: Draws 4x2 decoration downward with spacing (objects 0x65-0x66)
150 // This is 4 columns × 2 rows = 8 tiles in ROW-MAJOR order with 6-tile Y
151 // spacing.
152 int size = ctx.object.size_ & 0x0F;
153
154 // Assembly: GetSize_1to16, so count = size + 1
155 int count = size + 1;
156
157 for (int s = 0; s < count; s++) {
158 if (ctx.tiles.size() >= 8) {
159 // Draw 4x2 pattern in ROW-MAJOR order:
160 // Row 0: tiles[0..3], Row 1: tiles[4..7].
161 const int base_y = ctx.object.y_ + (s * 6);
163 ctx.tiles[0]);
164 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y,
165 ctx.tiles[1]);
166 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 2, base_y,
167 ctx.tiles[2]);
168 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 3, base_y,
169 ctx.tiles[3]);
170 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_, base_y + 1,
171 ctx.tiles[4]);
172 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 1,
173 ctx.tiles[5]);
174 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 2, base_y + 1,
175 ctx.tiles[6]);
176 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 3, base_y + 1,
177 ctx.tiles[7]);
178 }
179 }
180}
181
183 // Pattern: Draws 2x2 tiles downward (objects 0x67-0x68)
184 int size = ctx.object.size_ & 0x0F;
185
186 // Assembly: GetSize_1to16, so count = size + 1
187 int count = size + 1;
188
189 for (int s = 0; s < count; s++) {
190 if (ctx.tiles.size() >= 4) {
191 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
192 // tiles[0] → col 0, row 0 = top-left
193 // tiles[1] → col 0, row 1 = bottom-left
194 // tiles[2] → col 1, row 0 = top-right
195 // tiles[3] → col 1, row 1 = bottom-right
197 ctx.object.y_ + (s * 2),
198 ctx.tiles[0]); // col 0, row 0
200 ctx.object.y_ + (s * 2) + 1,
201 ctx.tiles[1]); // col 0, row 1
203 ctx.object.y_ + (s * 2),
204 ctx.tiles[2]); // col 1, row 0
206 ctx.object.y_ + (s * 2) + 1,
207 ctx.tiles[3]); // col 1, row 1
208 }
209 }
210}
211
213 // Pattern: Vertical rail with corner/middle/end (object 0x69).
214 // ASM: RoomDraw_DownwardsHasEdge1x1_1to16_plus3 ($01:8EC3) loads A=2 then
215 // falls into RoomDraw_DownwardsHasEdge1x1_1to16, which calls
216 // RoomDraw_GetSize_1to16_timesA ($01:B0AF) to set $B2 = composite_size + A.
217 // For the _plus3 variant that yields count = size + 2 middle tiles, matching
218 // the horizontal counterpart RoomDraw_RightwardsHasEdge1x1_1to16_plus3
219 // ($01:8EF0) which uses the same A=2. Total span = 1 corner + (size+2)
220 // middles + 1 end = size + 4 tiles.
221 int size = ctx.object.size_ & 0x0F;
222 int count = size + 2;
223
224 if (ctx.tiles.size() < 3)
225 return;
226
227 int y = ctx.object.y_;
228 // USDASM $01:8EC9-$01:8ED4 suppresses the leading corner when the existing
229 // tile already contains the small vertical rail corner.
231 {0x00E3})) {
233 }
234 y++;
235 for (int s = 0; s < count; s++) {
237 y++;
238 }
240}
241
243 // Pattern: 1x1 edge tiles downward (objects 0x6A-0x6B)
244 int size = ctx.object.size_ & 0x0F;
245
246 // Assembly: GetSize_1to16, so count = size + 1
247 int count = size + 1;
248
249 for (int s = 0; s < count; s++) {
250 if (ctx.tiles.size() >= 1) {
251 // Use first 8x8 tile from span
253 ctx.object.y_ + s, ctx.tiles[0]);
254 }
255 }
256}
257
259 DrawDownwardsCorners2x1(ctx, /*edge_is_left=*/true);
260}
261
263 DrawDownwardsCorners2x1(ctx, /*edge_is_left=*/false);
264}
265
267 const int size = ctx.object.size_ & 0x0F;
268 const int count = size + 1;
269 if (ctx.tiles.size() < 16) {
270 return;
271 }
272
273 for (int s = 0; s < count; ++s) {
274 const int base_y = ctx.object.y_ + (s * 4);
275 for (int x = 0; x < 4; ++x) {
276 for (int y = 0; y < 4; ++y) {
278 base_y + y, ctx.tiles[x * 4 + y]);
279 }
280 }
281 }
282}
283
285 const int size = ctx.object.size_ & 0x0F;
286 const int count = size + 4;
287 if (ctx.tiles.empty()) {
288 return;
289 }
290
291 for (int s = 0; s < count; ++s) {
293 ctx.object.y_ + s, ctx.tiles[0]);
294 }
295}
296
298 const int size = ctx.object.size_ & 0x0F;
299 const int count = size + 1;
300 if (ctx.tiles.size() < 16) {
301 return;
302 }
303
304 for (int s = 0; s < count; ++s) {
305 const int base_y = ctx.object.y_ + (s * 6);
306 for (int x = 0; x < 4; ++x) {
307 for (int y = 0; y < 4; ++y) {
309 base_y + y, ctx.tiles[x * 4 + y]);
310 }
311 }
312 }
313}
314
316 const int size = ctx.object.size_ & 0x0F;
317 const int count = size + 1;
318 if (ctx.tiles.size() < 8) {
319 return;
320 }
321
322 for (int s = 0; s < count; ++s) {
323 const int base_y = ctx.object.y_ + (s * 6);
324 for (int x = 0; x < 2; ++x) {
325 for (int y = 0; y < 4; ++y) {
327 base_y + y, ctx.tiles[x * 4 + y]);
328 }
329 }
330 }
331}
332
334 const int size = ctx.object.size_ & 0x0F;
335 const int count = size + 1;
336 if (ctx.tiles.size() < 12) {
337 return;
338 }
339
340 for (int s = 0; s < count; ++s) {
341 const int base_y = ctx.object.y_ + (s * 8);
342 for (int x = 0; x < 3; ++x) {
343 for (int y = 0; y < 4; ++y) {
345 base_y + y, ctx.tiles[x * 4 + y]);
346 }
347 }
348 }
349}
350
352 const int size = ctx.object.size_ & 0x0F;
353 const int count = size + 1;
354 if (ctx.tiles.size() < 4) {
355 return;
356 }
357
358 for (int s = 0; s < count; ++s) {
359 const int base_y = ctx.object.y_ + (s * 14);
360 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 0,
361 ctx.tiles[0]);
362 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 1,
363 ctx.tiles[1]);
364 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 0,
365 ctx.tiles[2]);
366 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 1,
367 ctx.tiles[3]);
368 }
369}
370
372 const int size = ctx.object.size_ & 0x0F;
373 const int count = size + 2;
374 if (ctx.tiles.empty()) {
375 return;
376 }
377
378 for (int s = 0; s < count; ++s) {
380 ctx.object.y_ + s, ctx.tiles[0]);
381 }
382}
383
385 const int size = ctx.object.size_ & 0x0F;
386 const int count = size + 1;
387 if (ctx.tiles.size() < 8) {
388 return;
389 }
390
391 for (int s = 0; s < count; ++s) {
392 const int base_y = ctx.object.y_ + (s * 12);
393 for (int x = 0; x < 2; ++x) {
394 for (int y = 0; y < 4; ++y) {
396 base_y + y, ctx.tiles[x * 4 + y]);
397 }
398 }
399 }
400}
401
403 const int size = ctx.object.size_ & 0x0F;
404 const int count = size + 1;
405 if (ctx.tiles.size() < 12) {
406 return;
407 }
408
409 for (int s = 0; s < count; ++s) {
410 const int base_y = ctx.object.y_ + (s * 6);
411 for (int x = 0; x < 3; ++x) {
412 for (int y = 0; y < 4; ++y) {
414 base_y + y, ctx.tiles[x * 4 + y]);
415 }
416 }
417 }
418}
419
421 const int size = ctx.object.size_ & 0x0F;
422 const int middle_rows = size + 1;
423 const int total_rows = size + 6; // 2 top + (size+1) middle + 3 bottom.
424
425 if (ctx.tiles.size() >= 12) {
426 // USDASM $01:8F0C:
427 // - Top cap: 2x2 (tiles 0..3, column-major)
428 // - Middle: repeated 2x1 rows (tiles 4..5)
429 // - Bottom cap: 2 columns x 3 rows (tiles 6..11)
431 ctx.object.y_ + 0, ctx.tiles[0]);
433 ctx.object.y_ + 1, ctx.tiles[1]);
435 ctx.object.y_ + 0, ctx.tiles[2]);
437 ctx.object.y_ + 1, ctx.tiles[3]);
438
439 int base_y = ctx.object.y_ + 2;
440 for (int row = 0; row < middle_rows; ++row) {
442 base_y + row, ctx.tiles[4]);
444 base_y + row, ctx.tiles[5]);
445 }
446
447 const int cap_y = base_y + middle_rows;
448 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, cap_y + 0,
449 ctx.tiles[6]);
450 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, cap_y + 1,
451 ctx.tiles[7]);
452 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, cap_y + 2,
453 ctx.tiles[8]);
454 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, cap_y + 0,
455 ctx.tiles[9]);
456 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, cap_y + 1,
457 ctx.tiles[10]);
458 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, cap_y + 2,
459 ctx.tiles[11]);
460 return;
461 }
462
463 if (ctx.tiles.empty() || total_rows <= 0) {
464 return;
465 }
466 const gfx::TileInfo& left = ctx.tiles[0];
467 const gfx::TileInfo& right =
468 ctx.tiles.size() > 1 ? ctx.tiles[1] : ctx.tiles[0];
469 for (int row = 0; row < total_rows; ++row) {
471 ctx.object.y_ + row, left);
473 ctx.object.y_ + row, right);
474 }
475}
476
478 const int size = ctx.object.size_ & 0x0F;
479 const int count = size + 1;
480 if (ctx.tiles.size() < 4) {
481 return;
482 }
483
484 for (int s = 0; s < count; ++s) {
485 const int base_y = ctx.object.y_ + (s * 4);
486 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 0,
487 ctx.tiles[0]);
488 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 1,
489 ctx.tiles[1]);
490 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 0,
491 ctx.tiles[2]);
492 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 1,
493 ctx.tiles[3]);
494 }
495}
496
498 const int size = ctx.object.size_ & 0x0F;
499 const int repeat_count = size + 1;
500 if (ctx.tiles.size() < 12) {
501 return;
502 }
503
504 auto draw_segment = [&](int base_y, int tile_base) {
505 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 0,
506 ctx.tiles[tile_base + 0]);
507 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 0,
508 ctx.tiles[tile_base + 1]);
509 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 2, base_y + 0,
510 ctx.tiles[tile_base + 2]);
511 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 1,
512 ctx.tiles[tile_base + 3]);
513 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 1,
514 ctx.tiles[tile_base + 4]);
515 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 2, base_y + 1,
516 ctx.tiles[tile_base + 5]);
517 };
518
519 // USDASM $01:9CEB:
520 // - Repeat the left 3x2 segment (tiles 0..5) size+1 times
521 // - Append one 3x2 edge segment (tiles 6..11)
522 for (int s = 0; s < repeat_count; ++s) {
523 draw_segment(ctx.object.y_ + (s * 2), /*tile_base=*/0);
524 }
525 draw_segment(ctx.object.y_ + (repeat_count * 2), /*tile_base=*/6);
526}
527
529 const int size = ctx.object.size_ & 0x0F;
530 const int middle_rows = (size + 2) * 2;
531 if (ctx.tiles.size() < 4) {
532 return;
533 }
534
535 // USDASM $01:97B5:
536 // - top row uses tiles 0..1
537 // - remaining rows use tiles 2..3, repeated 2*(size+2) times
539 ctx.object.y_ + 0, ctx.tiles[0]);
541 ctx.object.y_ + 0, ctx.tiles[1]);
542 for (int row = 0; row < middle_rows; ++row) {
544 ctx.object.y_ + 1 + row, ctx.tiles[2]);
546 ctx.object.y_ + 1 + row, ctx.tiles[3]);
547 }
548}
549
551 const int size = ctx.object.size_ & 0x0F;
552 const int count = size + 1;
553 if (ctx.tiles.size() < 4) {
554 return;
555 }
556
557 for (int s = 0; s < count; ++s) {
558 const int base_y = ctx.object.y_ + (s * 2);
559 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 0,
560 ctx.tiles[0]);
561 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 0, base_y + 1,
562 ctx.tiles[1]);
563 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 0,
564 ctx.tiles[2]);
565 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y + 1,
566 ctx.tiles[3]);
567 }
568}
569
573
575 const int count = (ctx.object.size_ & 0x0F) + 8;
576 if (ctx.tiles.empty()) {
577 return;
578 }
579
580 for (int row = 0; row < count; ++row) {
582 ctx.object.y_ + row, ctx.tiles[0]);
583 }
584}
585
586void RegisterDownwardsRoutines(std::vector<DrawRoutineInfo>& registry) {
587 using Category = DrawRoutineInfo::Category;
588
589 registry.push_back(
590 DrawRoutineInfo{.id = 7, // RoomDraw_Downwards2x2_1to15or32
591 .name = "Downwards2x2_1to15or32",
592 .function = DrawDownwards2x2_1to15or32,
593 .draws_to_both_bgs = false,
594 .base_width = 2,
595 .base_height = 2,
596 .min_tiles = 4, // 2x2 block
597 .category = Category::Downwards});
598
599 registry.push_back(DrawRoutineInfo{
600 .id = 8, // RoomDraw_Downwards4x2_1to15or26
601 .name = "Downwards4x2_1to15or26",
602 .function = DrawDownwards4x2_1to15or26,
603 // USDASM: RoomDraw_Downwards4x2_1to15or26 ($01:8A89) jumps to
604 // RoomDraw_Downwards4x2VariableSpacing ($01:B220) which writes through
605 // the current tilemap pointers (single-layer).
606 .draws_to_both_bgs = false,
607 .base_width = 4,
608 .base_height = 2,
609 .min_tiles = 8, // 4x2 block
610 .category = Category::Downwards});
611
612 registry.push_back(
613 DrawRoutineInfo{.id = 9, // RoomDraw_Downwards4x2_1to16_BothBG
614 .name = "Downwards4x2_1to16_BothBG",
616 .draws_to_both_bgs = true,
617 .base_width = 4,
618 .base_height = 2,
619 .min_tiles = 8, // 4x2 block
620 .category = Category::Downwards});
621
622 registry.push_back(
623 DrawRoutineInfo{.id = 10, // RoomDraw_DownwardsDecor4x2spaced4_1to16
624 .name = "DownwardsDecor4x2spaced4_1to16",
626 .draws_to_both_bgs = false,
627 .base_width = 4,
628 .base_height = 2,
629 .min_tiles = 8, // 4x2 block
630 .category = Category::Downwards});
631
632 registry.push_back(DrawRoutineInfo{.id = 11, // RoomDraw_Downwards2x2_1to16
633 .name = "Downwards2x2_1to16",
634 .function = DrawDownwards2x2_1to16,
635 .draws_to_both_bgs = false,
636 .base_width = 2,
637 .base_height = 2,
638 .min_tiles = 4, // 2x2 block
639 .category = Category::Downwards});
640
641 registry.push_back(
642 DrawRoutineInfo{.id = 12, // RoomDraw_DownwardsHasEdge1x1_1to16_plus3
643 .name = "DownwardsHasEdge1x1_1to16_plus3",
645 .draws_to_both_bgs = false,
646 .base_width = 1,
647 // size=0 footprint = corner + 2 middles + end = 4 rows
648 // (mirrors horizontal kRightwardsHasEdge1x1_1to16_plus3
649 // base_width=4; both share ASM A=2 path).
650 .base_height = 4,
651 .min_tiles = 3, // top edge + middle + bottom edge
652 .category = Category::Downwards});
653
654 registry.push_back(
655 DrawRoutineInfo{.id = 13, // RoomDraw_DownwardsEdge1x1_1to16
656 .name = "DownwardsEdge1x1_1to16",
657 .function = DrawDownwardsEdge1x1_1to16,
658 .draws_to_both_bgs = false,
659 .base_width = 1,
660 .base_height = 1,
661 .min_tiles = 1, // single repeated tile
662 .category = Category::Downwards});
663
664 registry.push_back(DrawRoutineInfo{
665 .id = 14, // RoomDraw_DownwardsLeftCorners2x1_1to16_plus12
666 .name = "DownwardsLeftCorners2x1_1to16_plus12",
668 .draws_to_both_bgs = false,
669 .base_width = 2,
670 .base_height = 14,
671 .min_tiles = 6, // cap + body + endpoint tile spans from subtype-1 table
672 .category = Category::Downwards});
673
674 registry.push_back(DrawRoutineInfo{
675 .id = 15, // RoomDraw_DownwardsRightCorners2x1_1to16_plus12
676 .name = "DownwardsRightCorners2x1_1to16_plus12",
678 .draws_to_both_bgs = false,
679 .base_width = 2,
680 .base_height = 14,
681 .min_tiles = 6, // cap + body + endpoint tile spans from subtype-1 table
682 .category = Category::Downwards});
683
684 registry.push_back(
686 .name = "DownwardsFloor4x4_1to16",
687 .function = DrawDownwardsFloor4x4_1to16,
688 .draws_to_both_bgs = false,
689 .base_width = 4,
690 .base_height = 4,
691 .min_tiles = 16,
692 .category = Category::Downwards});
693
694 registry.push_back(
696 .name = "Downwards1x1Solid_1to16_plus3",
698 .draws_to_both_bgs = false,
699 .base_width = 1,
700 .base_height = 1,
701 .min_tiles = 1,
702 .category = Category::Downwards});
703
704 registry.push_back(
706 .name = "DownwardsDecor4x4spaced2_1to16",
708 .draws_to_both_bgs = false,
709 .base_width = 4,
710 .base_height = 4,
711 .min_tiles = 16,
712 .category = Category::Downwards});
713
714 registry.push_back(
716 .name = "DownwardsPillar2x4spaced2_1to16",
718 .draws_to_both_bgs = false,
719 .base_width = 2,
720 .base_height = 4,
721 .min_tiles = 8,
722 .category = Category::Downwards});
723
724 registry.push_back(
726 .name = "DownwardsDecor3x4spaced4_1to16",
728 .draws_to_both_bgs = false,
729 .base_width = 3,
730 .base_height = 4,
731 .min_tiles = 12,
732 .category = Category::Downwards});
733
734 registry.push_back(
736 .name = "DownwardsDecor2x2spaced12_1to16",
738 .draws_to_both_bgs = false,
739 .base_width = 2,
740 .base_height = 2,
741 .min_tiles = 4,
742 .category = Category::Downwards});
743
744 registry.push_back(
746 .name = "DownwardsLine1x1_1to16plus1",
748 .draws_to_both_bgs = false,
749 .base_width = 1,
750 .base_height = 1,
751 .min_tiles = 1,
752 .category = Category::Downwards});
753
754 registry.push_back(
756 .name = "DownwardsDecor2x4spaced8_1to16",
758 .draws_to_both_bgs = false,
759 .base_width = 2,
760 .base_height = 4,
761 .min_tiles = 8,
762 .category = Category::Downwards});
763
764 registry.push_back(
766 .name = "DownwardsDecor3x4spaced2_1to16",
768 .draws_to_both_bgs = false,
769 .base_width = 3,
770 .base_height = 4,
771 .min_tiles = 12,
772 .category = Category::Downwards});
773
774 registry.push_back(
776 .name = "DownwardsBigRail3x1_1to16plus5",
778 .draws_to_both_bgs = false,
779 .base_width = 2,
780 .base_height = 6,
781 .min_tiles = 12,
782 .category = Category::Downwards});
783
784 registry.push_back(
786 .name = "DownwardsBlock2x2spaced2_1to16",
788 .draws_to_both_bgs = false,
789 .base_width = 2,
790 .base_height = 2,
791 .min_tiles = 4,
792 .category = Category::Downwards});
793
794 registry.push_back(
796 .name = "DownwardsCannonHole3x4_1to16",
798 .draws_to_both_bgs = false,
799 .base_width = 3,
800 .base_height = 4,
801 .min_tiles = 12,
802 .category = Category::Downwards});
803
804 registry.push_back(
806 .name = "DownwardsBar2x5_1to16",
807 .function = DrawDownwardsBar2x5_1to16,
808 .draws_to_both_bgs = false,
809 .base_width = 2,
810 .base_height = 5,
811 .min_tiles = 4,
812 .category = Category::Downwards});
813
814 registry.push_back(
816 .name = "DownwardsPots2x2_1to16",
817 .function = DrawDownwardsPots2x2_1to16,
818 .draws_to_both_bgs = false,
819 .base_width = 2,
820 .base_height = 2,
821 .min_tiles = 4,
822 .category = Category::Downwards});
823
824 registry.push_back(
826 .name = "DownwardsHammerPegs2x2_1to16",
828 .draws_to_both_bgs = false,
829 .base_width = 2,
830 .base_height = 2,
831 .min_tiles = 4,
832 .category = Category::Downwards});
833
834 registry.push_back(
836 .name = "DownwardsEdge1x1_1to16plus7",
838 .draws_to_both_bgs = false,
839 .base_width = 1,
840 .base_height = 8,
841 .min_tiles = 1,
842 .category = Category::Downwards});
843}
844
845} // namespace draw_routines
846} // namespace zelda3
847} // namespace yaze
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
bool ExistingTileMatchesAny(const gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::initializer_list< uint16_t > tile_ids)
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 DrawDownwardsCorners2x1(const DrawContext &ctx, bool edge_is_left)
void DrawDownwards1x1Solid_1to16_plus3(const DrawContext &ctx)
Draw downwards 1x1 solid line with +3 extension.
void DrawDownwardsDecor2x4spaced8_1to16(const DrawContext &ctx)
Draw downwards 2x4 decoration with 8-tile spacing.
void DrawDownwards4x2_1to15or26(const DrawContext &ctx)
Draw 4x2 tiles downward pattern (1-15 or 26 iterations)
void DrawDownwardsEdge1x1_1to16(const DrawContext &ctx)
Draw 1x1 edge tiles downward (1-16 iterations)
void DrawDownwardsBar2x5_1to16(const DrawContext &ctx)
Draw downwards 2x5 bar pattern.
void DrawDownwardsDecor2x2spaced12_1to16(const DrawContext &ctx)
Draw downwards 2x2 decoration with 12-tile spacing.
void DrawDownwards2x2_1to15or32(const DrawContext &ctx)
Draw 2x2 tiles downward pattern (1-15 or 32 iterations)
void DrawDownwards2x2_1to16(const DrawContext &ctx)
Draw 2x2 tiles downward pattern (1-16 iterations)
void RegisterDownwardsRoutines(std::vector< DrawRoutineInfo > &registry)
Register all downwards draw routines to the registry.
void DrawDownwardsDecor4x4spaced2_1to16(const DrawContext &ctx)
Draw downwards 4x4 decoration with 2-tile spacing.
void DrawDownwardsEdge1x1_1to16plus7(const DrawContext &ctx)
Draw a single tile downward for size + 8 rows.
void DrawDownwardsHasEdge1x1_1to16_plus3(const DrawContext &ctx)
Draw 1x1 tiles with edge detection +3 downward.
void DrawDownwardsLine1x1_1to16plus1(const DrawContext &ctx)
Draw downwards 1x1 line with +1 extension.
void DrawDownwardsCannonHole3x4_1to16(const DrawContext &ctx)
Draw downwards cannon-hole 3x4 pattern.
void DrawDownwardsLeftCorners2x1_1to16_plus12(const DrawContext &ctx)
Draw left corner 2x1 tiles with opening and closing caps.
void DrawDownwardsPots2x2_1to16(const DrawContext &ctx)
Draw downwards 2x2 pots pattern.
void DrawDownwardsBlock2x2spaced2_1to16(const DrawContext &ctx)
Draw downwards 2x2 block pattern with 2-tile spacing.
void DrawDownwardsBigRail3x1_1to16plus5(const DrawContext &ctx)
Draw downwards big rail pattern (3x1 family, +5 extension)
void DrawDownwardsFloor4x4_1to16(const DrawContext &ctx)
Draw downwards 4x4 floor blocks.
void DrawDownwardsRightCorners2x1_1to16_plus12(const DrawContext &ctx)
Draw right corner 2x1 tiles with opening and closing caps.
void DrawDownwardsHammerPegs2x2_1to16(const DrawContext &ctx)
Draw downwards 2x2 hammer pegs pattern.
void DrawDownwardsDecor4x2spaced4_1to16(const DrawContext &ctx)
Draw 4x2 decoration downward with spacing (1-16 iterations)
void DrawDownwardsPillar2x4spaced2_1to16(const DrawContext &ctx)
Draw downwards 2x4 pillar with 2-tile spacing.
void DrawDownwardsDecor3x4spaced2_1to16(const DrawContext &ctx)
Draw downwards 3x4 decoration with 2-tile spacing.
void DrawDownwardsDecor3x4spaced4_1to16(const DrawContext &ctx)
Draw downwards 3x4 decoration with 4-tile spacing.
void DrawDownwards4x2_1to16_BothBG(const DrawContext &ctx)
Draw 4x2 tiles downward pattern for both BG layers.
Context passed to draw routines containing all necessary state.
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
Metadata about a draw routine.