yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
corner_routines.cc
Go to the documentation of this file.
1#include "corner_routines.h"
2
6
7namespace yaze {
8namespace zelda3 {
9namespace draw_routines {
10
11namespace {
12
19
21 // USDASM parity:
22 // RoomDraw_DiagonalCeiling* uses GetSize_1to16_timesA with A=4.
23 // Effective side length is (size_nibble & 0x0F) + 4.
24 if (ctx.tiles.empty()) {
25 return;
26 }
27
28 const int side = (ctx.object.size_ & 0x0F) + 4;
29 const gfx::TileInfo& fill_tile = ctx.tiles[0];
30
31 const bool mirror_x = anchor == DiagonalCeilingAnchor::kTopRight ||
32 anchor == DiagonalCeilingAnchor::kBottomRight;
33 const bool mirror_y = anchor == DiagonalCeilingAnchor::kBottomLeft ||
34 anchor == DiagonalCeilingAnchor::kBottomRight;
35
36 const int base_x = ctx.object.x_ - (mirror_x ? (side - 1) : 0);
37 const int base_y = ctx.object.y_ - (mirror_y ? (side - 1) : 0);
38
39 // Fill a right-triangle in the local square and mirror as needed.
40 for (int row = 0; row < side; ++row) {
41 const int span = side - row;
42 for (int col = 0; col < span; ++col) {
43 const int x = mirror_x ? (side - 1 - col) : col;
44 const int y = mirror_y ? (side - 1 - row) : row;
45 DrawRoutineUtils::WriteTile8(ctx.target_bg, base_x + x, base_y + y,
46 fill_tile);
47 }
48 }
49}
50
51} // namespace
52
53// Note: DrawWaterFace is defined in special_routines.cc along with other
54// water face variants (Empty, Spitting, Drenching)
55
56void DrawCorner4x4(const DrawContext& ctx) {
57 // Pattern: 4x4 grid corner (Type 2 corners 0x40-0x4F, 0x108-0x10F)
58 // Type 2 objects only have 8 tiles, so we need to handle both 16 and 8 tile
59 // cases
60
61 if (ctx.tiles.size() >= 16) {
62 // Full 4x4 pattern - Column-major ordering per ZScream
63 int tid = 0;
64 for (int xx = 0; xx < 4; xx++) {
65 for (int yy = 0; yy < 4; yy++) {
67 ctx.object.y_ + yy, ctx.tiles[tid++]);
68 }
69 }
70 } else if (ctx.tiles.size() >= 8) {
71 // Type 2 objects: 8 tiles arranged in 2x4 column-major pattern
72 // This is the standard Type 2 tile layout
73 int tid = 0;
74 for (int xx = 0; xx < 2; xx++) {
75 for (int yy = 0; yy < 4; yy++) {
77 ctx.object.y_ + yy, ctx.tiles[tid++]);
78 }
79 }
80 } else if (ctx.tiles.size() >= 4) {
81 // Fallback: 2x2 pattern
82 int tid = 0;
83 for (int xx = 0; xx < 2; xx++) {
84 for (int yy = 0; yy < 2; yy++) {
86 ctx.object.y_ + yy, ctx.tiles[tid++]);
87 }
88 }
89 }
90}
91
93 // USDASM: RoomDraw_4x4Corner_BothBG ($01:9813)
94 // Canonical shape is 4 columns x 4 rows (column-major). We retain smaller
95 // fallback shapes for abbreviated hack-ROM payloads.
96 if (ctx.tiles.size() >= 16) {
97 DrawCorner4x4(ctx);
98 } else if (ctx.tiles.size() >= 8) {
99 // Fallback: 2x4 corner pattern (column-major)
100 int tid = 0;
101 for (int xx = 0; xx < 2; xx++) {
102 for (int yy = 0; yy < 4; yy++) {
104 ctx.object.y_ + yy, ctx.tiles[tid++]);
105 }
106 }
107 } else if (ctx.tiles.size() >= 4) {
108 // Fallback: 2x2 pattern
109 DrawWaterFace(ctx);
110 }
111}
112
114 // USDASM: RoomDraw_WeirdCornerBottom_BothBG ($01:9854)
115 // ASM sets count=3 and reuses RoomDraw_4x4Corner_BothBG_set_count:
116 // 3 columns x 4 rows, column-major (12 tiles).
117 if (ctx.tiles.size() >= 12) {
118 int tid = 0;
119 for (int xx = 0; xx < 3; xx++) {
120 for (int yy = 0; yy < 4; yy++) {
122 ctx.object.y_ + yy, ctx.tiles[tid++]);
123 }
124 }
125 } else if (ctx.tiles.size() >= 8) {
126 // Fallback for truncated payloads: 2x4 column-major.
127 int tid = 0;
128 for (int xx = 0; xx < 2; xx++) {
129 for (int yy = 0; yy < 4; yy++) {
131 ctx.object.y_ + yy, ctx.tiles[tid++]);
132 }
133 }
134 } else if (ctx.tiles.size() >= 4) {
135 DrawWaterFace(ctx);
136 }
137}
138
140 // USDASM: RoomDraw_WeirdCornerTop_BothBG ($01:985C)
141 // ASM writes 3 rows per column and advances source by 6 bytes each loop:
142 // 4 columns x 3 rows, column-major (12 tiles).
143 if (ctx.tiles.size() >= 12) {
144 int tid = 0;
145 for (int xx = 0; xx < 4; xx++) {
146 for (int yy = 0; yy < 3; yy++) {
148 ctx.object.y_ + yy, ctx.tiles[tid++]);
149 }
150 }
151 } else if (ctx.tiles.size() >= 8) {
152 // Fallback for truncated payloads: 2x4 column-major.
153 int tid = 0;
154 for (int xx = 0; xx < 2; xx++) {
155 for (int yy = 0; yy < 4; yy++) {
157 ctx.object.y_ + yy, ctx.tiles[tid++]);
158 }
159 }
160 } else if (ctx.tiles.size() >= 4) {
161 DrawWaterFace(ctx);
162 }
163}
164
166 DrawDiagonalCeiling(ctx, DiagonalCeilingAnchor::kTopLeft);
167}
168
170 DrawDiagonalCeiling(ctx, DiagonalCeilingAnchor::kBottomLeft);
171}
172
174 DrawDiagonalCeiling(ctx, DiagonalCeilingAnchor::kTopRight);
175}
176
178 DrawDiagonalCeiling(ctx, DiagonalCeilingAnchor::kBottomRight);
179}
180
181void RegisterCornerRoutines(std::vector<DrawRoutineInfo>& registry) {
182 // Note: Routine IDs are assigned based on the assembly routine table
183 // These corner routines are part of the core 40 draw routines
184
185 registry.push_back(DrawRoutineInfo{
186 .id = 19, // DrawCorner4x4
187 .name = "Corner4x4",
188 .function = DrawCorner4x4,
189 // Structural layout routine: writes to both BG1 and BG2 in the engine.
190 .draws_to_both_bgs = true,
191 .base_width = 4,
192 .base_height = 4,
193 .min_tiles = 4, // handles 4, 8, or 16 tile variants
195 });
196
197 registry.push_back(DrawRoutineInfo{
198 .id = 35, // Draw4x4Corner_BothBG
199 .name = "4x4Corner_BothBG",
200 .function = Draw4x4Corner_BothBG,
201 .draws_to_both_bgs = true,
202 .base_width = 4,
203 .base_height = 4,
204 .min_tiles = 4, // handles 4, 8, or 16 tile variants
206 });
207
208 registry.push_back(DrawRoutineInfo{
209 .id = 36, // DrawWeirdCornerBottom_BothBG
210 .name = "WeirdCornerBottom_BothBG",
212 .draws_to_both_bgs = true,
213 .base_width = 3,
214 .base_height = 4,
215 .min_tiles = 12, // Enforce canonical USDASM payload size.
217 });
218
219 registry.push_back(DrawRoutineInfo{
220 .id = 37, // DrawWeirdCornerTop_BothBG
221 .name = "WeirdCornerTop_BothBG",
222 .function = DrawWeirdCornerTop_BothBG,
223 .draws_to_both_bgs = true,
224 .base_width = 4,
225 .base_height = 3,
226 .min_tiles = 12, // Enforce canonical USDASM payload size.
228 });
229
230 registry.push_back(DrawRoutineInfo{
232 .name = "DiagonalCeilingTopLeft",
233 .function = DrawDiagonalCeilingTopLeft,
234 .draws_to_both_bgs = false,
235 .base_width = 4, // size_nibble + 4
236 .base_height = 4, // size_nibble + 4
237 .min_tiles = 1,
239 });
240
241 registry.push_back(DrawRoutineInfo{
243 .name = "DiagonalCeilingBottomLeft",
245 .draws_to_both_bgs = false,
246 .base_width = 4, // size_nibble + 4
247 .base_height = 4, // size_nibble + 4
248 .min_tiles = 1,
250 });
251
252 registry.push_back(DrawRoutineInfo{
254 .name = "DiagonalCeilingTopRight",
255 .function = DrawDiagonalCeilingTopRight,
256 .draws_to_both_bgs = false,
257 .base_width = 4, // size_nibble + 4
258 .base_height = 4, // size_nibble + 4
259 .min_tiles = 1,
261 });
262
263 registry.push_back(DrawRoutineInfo{
265 .name = "DiagonalCeilingBottomRight",
267 .draws_to_both_bgs = false,
268 .base_width = 4, // size_nibble + 4
269 .base_height = 4, // size_nibble + 4
270 .min_tiles = 1,
272 });
273}
274
275} // namespace draw_routines
276} // namespace zelda3
277} // namespace yaze
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
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 DrawDiagonalCeiling(const DrawContext &ctx, DiagonalCeilingAnchor anchor)
void DrawWeirdCornerTop_BothBG(const DrawContext &ctx)
Draw a weird corner top pattern for both BG layers.
void DrawDiagonalCeilingTopLeft(const DrawContext &ctx)
Draw diagonal ceiling triangle anchored at top-left.
void RegisterCornerRoutines(std::vector< DrawRoutineInfo > &registry)
Register all corner draw routines to the registry.
void DrawCorner4x4(const DrawContext &ctx)
Draw a 4x4 grid corner pattern.
void DrawWaterFace(const DrawContext &ctx)
Draw a generic 2x2 water-face helper pattern.
void DrawWeirdCornerBottom_BothBG(const DrawContext &ctx)
Draw a weird corner bottom pattern for both BG layers.
void DrawDiagonalCeilingBottomLeft(const DrawContext &ctx)
Draw diagonal ceiling triangle anchored at bottom-left.
void DrawDiagonalCeilingTopRight(const DrawContext &ctx)
Draw diagonal ceiling triangle anchored at top-right.
void Draw4x4Corner_BothBG(const DrawContext &ctx)
Draw a 4x4 corner for both BG layers.
void DrawDiagonalCeilingBottomRight(const DrawContext &ctx)
Draw diagonal ceiling triangle anchored at bottom-right.
Context passed to draw routines containing all necessary state.
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
Metadata about a draw routine.