yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
draw_routine_types.h
Go to the documentation of this file.
1#ifndef YAZE_ZELDA3_DUNGEON_DRAW_ROUTINES_DRAW_ROUTINE_TYPES_H
2#define YAZE_ZELDA3_DUNGEON_DRAW_ROUTINES_DRAW_ROUTINE_TYPES_H
3
4#include <cstdint>
5#include <functional>
6#include <initializer_list>
7#include <span>
8#include <string>
9
12#include "rom/rom.h"
13
14namespace yaze {
15namespace zelda3 {
16
17// Forward declarations
18class CustomObjectRenderSnapshot;
19class DungeonState;
20struct RoomObject;
21
29 gfx::BackgroundBuffer& target_bg; // Primary buffer to draw to
30 const RoomObject& object; // Object being drawn
31 std::span<const gfx::TileInfo> tiles; // Tile data for the object
32 const DungeonState* state; // Dungeon state (chest states, etc.)
33 Rom* rom; // ROM for additional data lookup
34 int room_id; // Current room ID
35 const uint8_t* room_gfx_buffer; // Room-specific graphics buffer
37 secondary_bg; // Secondary BG for dual-layer routines (nullable)
39 nullptr; // Matching layout owner for logical tilemap reads
40 int room_tag2 = -1; // Room header tag2 ($AF); -1 when not drawing a room
41
43
44 // Canvas dimensions
45 static constexpr int kMaxTilesX = 64;
46 static constexpr int kMaxTilesY = 64;
47
48 // Helper to check if dual-BG drawing is available
49 bool HasSecondaryBG() const { return secondary_bg != nullptr; }
50};
51
58using DrawRoutineFn = std::function<void(const DrawContext& ctx)>;
59
64 int id; // Routine ID (0-39)
65 std::string name; // Human-readable name
66 DrawRoutineFn function; // The actual draw function
67 bool draws_to_both_bgs; // If true, draws to BG1 and BG2
68 int base_width; // Base width in tiles (0 = variable)
69 int base_height; // Base height in tiles (0 = variable)
70
71 // Minimum number of tiles required for this routine to render correctly.
72 // When > 0, ObjectDrawer::DrawObject will skip the routine if the object's
73 // tile payload is smaller, preventing out-of-bounds access in fixed-size
74 // draw patterns. Routines with variable tile counts should leave this at 0.
75 int min_tiles = 0;
76
77 // Category for organization
78 enum class Category {
79 Special, // Chest, Nothing, Custom, DoorSwitcher
80 Rightwards, // Horizontal extension patterns
81 Downwards, // Vertical extension patterns
82 Diagonal, // Diagonal patterns
83 Corner // Corner and special shape patterns
84 };
86};
87
91namespace DrawRoutineUtils {
92
93using TraceHookFn = void (*)(gfx::BackgroundBuffer* bg, int tile_x, int tile_y,
94 const gfx::TileInfo& tile_info, void* user_data);
95
96// Optional trace hook for validation/testing (used by ObjectDrawer).
97void SetTraceHook(TraceHookFn hook, void* user_data, bool trace_only);
98void ClearTraceHook();
99
100inline uint16_t TileIdAt(const gfx::BackgroundBuffer& bg, int tile_x,
101 int tile_y) {
102 return bg.GetTileAt(tile_x, tile_y) & 0x03FF;
103}
104
105inline bool ExistingTileMatchesAny(const gfx::BackgroundBuffer& bg, int tile_x,
106 int tile_y,
107 std::initializer_list<uint16_t> tile_ids) {
108 const uint16_t existing_tile_id = TileIdAt(bg, tile_x, tile_y);
109 for (const uint16_t tile_id : tile_ids) {
110 if (existing_tile_id == tile_id) {
111 return true;
112 }
113 }
114 return false;
115}
116
117inline bool TileHasObjectCoverage(const gfx::BackgroundBuffer& bg, int tile_x,
118 int tile_y) {
119 const auto& coverage = bg.coverage_data();
120 const auto& bitmap = bg.bitmap();
121 if (coverage.empty() || bitmap.width() <= 0 || bitmap.height() <= 0) {
122 return false;
123 }
124
125 const int start_x = tile_x * 8;
126 const int start_y = tile_y * 8;
127 if (start_x < 0 || start_y < 0 || start_x >= bitmap.width() ||
128 start_y >= bitmap.height()) {
129 return false;
130 }
131
132 // ObjectDrawer marks the full 8x8 footprint even when a tile is visually
133 // transparent. Checking one pixel is therefore enough to establish which
134 // split buffer owns the effective SNES tilemap entry.
135 const size_t index = static_cast<size_t>(start_y * bitmap.width() + start_x);
136 return index < coverage.size() && coverage[index] != 0;
137}
138
139inline bool ExistingTileMatchesAny(const DrawContext& ctx, int tile_x,
140 int tile_y,
141 std::initializer_list<uint16_t> tile_ids) {
142 const gfx::BackgroundBuffer* effective_owner = &ctx.target_bg;
143 if (!TileHasObjectCoverage(ctx.target_bg, tile_x, tile_y) &&
144 ctx.target_layout_bg != nullptr) {
145 effective_owner = ctx.target_layout_bg;
146 }
147 return ExistingTileMatchesAny(*effective_owner, tile_x, tile_y, tile_ids);
148}
149
153inline bool IsValidTilePosition(int tile_x, int tile_y) {
154 return tile_x >= 0 && tile_x < DrawContext::kMaxTilesX && tile_y >= 0 &&
156}
157
166void WriteTile8(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
167 const gfx::TileInfo& tile_info);
168
172void DrawBlock2x2(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
173 std::span<const gfx::TileInfo> tiles, int offset = 0);
174
178void DrawBlock2x4(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
179 std::span<const gfx::TileInfo> tiles, int offset = 0);
180
184void DrawBlock4x2(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
185 std::span<const gfx::TileInfo> tiles, int offset = 0);
186
190void DrawBlock4x4(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
191 std::span<const gfx::TileInfo> tiles, int offset = 0);
192
193} // namespace DrawRoutineUtils
194
195} // namespace zelda3
196} // namespace yaze
197
198#endif // YAZE_ZELDA3_DUNGEON_DRAW_ROUTINES_DRAW_ROUTINE_TYPES_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
const std::vector< uint8_t > & coverage_data() const
uint16_t GetTileAt(int x, int y) const
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
Interface for accessing dungeon game state.
void DrawBlock2x2(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::span< const gfx::TileInfo > tiles, int offset)
Draw a 2x2 block of tiles (16x16 pixels)
bool TileHasObjectCoverage(const gfx::BackgroundBuffer &bg, int tile_x, int tile_y)
void DrawBlock2x4(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::span< const gfx::TileInfo > tiles, int offset)
Draw a 2x4 block of tiles (16x32 pixels)
void SetTraceHook(TraceHookFn hook, void *user_data, bool trace_only)
void DrawBlock4x2(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::span< const gfx::TileInfo > tiles, int offset)
Draw a 4x2 block of tiles (32x16 pixels)
uint16_t TileIdAt(const gfx::BackgroundBuffer &bg, int tile_x, int tile_y)
bool ExistingTileMatchesAny(const gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::initializer_list< uint16_t > tile_ids)
bool IsValidTilePosition(int tile_x, int tile_y)
Check if tile position is within canvas bounds.
void(*)(gfx::BackgroundBuffer *bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info, void *user_data) TraceHookFn
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 DrawBlock4x4(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::span< const gfx::TileInfo > tiles, int offset)
Draw a 4x4 block of tiles (32x32 pixels)
std::function< void(const DrawContext &ctx)> DrawRoutineFn
Function signature for a draw routine.
Context passed to draw routines containing all necessary state.
static constexpr int kMaxTilesY
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
const CustomObjectRenderSnapshot * custom_objects
const gfx::BackgroundBuffer * target_layout_bg
static constexpr int kMaxTilesX
gfx::BackgroundBuffer * secondary_bg
const DungeonState * state
Metadata about a draw routine.