yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
object_drawer.h
Go to the documentation of this file.
1#ifndef YAZE_APP_ZELDA3_DUNGEON_OBJECT_DRAWER_H
2#define YAZE_APP_ZELDA3_DUNGEON_OBJECT_DRAWER_H
3
4#include <functional>
5#include <unordered_map>
6#include <vector>
7
8#include "absl/status/status.h"
12#include "rom/rom.h"
18
19namespace yaze {
20namespace zelda3 {
21
37 public:
38 explicit ObjectDrawer(
39 Rom* rom, int room_id, const uint8_t* room_gfx_buffer = nullptr,
40 const CustomObjectRenderSnapshot* custom_objects = nullptr);
41
52 absl::Status DrawObject(const RoomObject& object, gfx::BackgroundBuffer& bg1,
54 const gfx::PaletteGroup& palette_group,
55 const DungeonState* state = nullptr,
56 gfx::BackgroundBuffer* layout_bg1 = nullptr,
57 gfx::BackgroundBuffer* layout_bg2 = nullptr);
58
59 // USDASM RoomDraw_BG2MaskFull (type-3 0xFF3): fills the object's whole
60 // layer with the tilemap erase word $01EC.
61 absl::Status DrawLayerMaskFull(const RoomObject& object,
62 gfx::BackgroundBuffer& target_bg,
64 // USDASM RoomDraw_LampCones (type-3 0xFAA): four fixed 12x12 blocks on BG2,
65 // independent of the object's position, size and list.
66 absl::Status DrawLampCones(const RoomObject& object,
68
69 // USDASM RoomDraw_AgahnimsWindows (type-3 0xFAE): fixed stores relative to
70 // the object's tilemap offset, then a priority-only pass.
71 absl::Status DrawAgahnimsWindows(const RoomObject& object,
74 gfx::BackgroundBuffer* layout_bg1,
75 gfx::BackgroundBuffer* layout_bg2);
76
77 // USDASM RoomDraw_SomeBigDecors (Kholdstare 0xF95, Trinexx 0xFF2 shells):
78 // a 10x8 row-major block on the object's layer from ROM offset data_pc.
79 absl::Status DrawBigDecor10x8(const RoomObject& object,
80 gfx::BackgroundBuffer& target_bg,
81 RoomObject::LayerType layer, int data_pc);
82 // USDASM RoomDraw_VitreousGooGraphics (0xFE2): 22x11 column-major on BG2
83 // plus a 3x2 block.
84 absl::Status DrawVitreousGoo(const RoomObject& object,
86
87 // USDASM RoomTag_ChestHoles0 (tag 0x22) / RoomTag_ChestHoles8 (tag 0x3B):
88 // once chest 0 is open, Underworld_ApplyRoomOverlay draws that overlay's
89 // pits onto BG1 ($7E2000). Draws nothing for other tags or a closed chest.
90 void DrawChestHoleOverlay(int tag1, int tag2, const DungeonState* state,
92
93 struct DoorDef {
96 uint8_t position;
97
98 // Helper to get visible render coordinates using DoorPositionManager.
99 std::pair<int, int> GetTileCoords() const {
101 direction);
102 }
103
104 // Helper to get door dimensions
108 };
109
110 // Reset the chest-only and shared chest/big-key-lock room-event indexes.
118 // Room objects 0xC4/0xDB copy the active Floor 1/Floor 2 pattern rather than
119 // reading a normal object tile payload.
120 // Room header tag2 ($AF), read by state-dependent routines such as
121 // RoomDraw_EmptyWaterFace. -1 (default) means no room context.
122 void SetRoomTag2(int tag2) { room_tag2_ = tag2; }
123
124 void SetRoomFloorGraphics(uint8_t floor1, uint8_t floor2) {
125 floor1_graphics_ = floor1 & 0x0F;
126 floor2_graphics_ = floor2 & 0x0F;
128 }
129
140 void DrawDoor(const DoorDef& door, int door_index, gfx::BackgroundBuffer& bg1,
141 gfx::BackgroundBuffer& bg2, const DungeonState* state = nullptr,
142 gfx::BackgroundBuffer* layout_bg1 = nullptr,
143 gfx::BackgroundBuffer* layout_bg2 = nullptr);
144
152 void DrawPotItem(uint8_t item_id, int x, int y, gfx::BackgroundBuffer& bg);
153
169 absl::Status DrawObjectList(const std::vector<RoomObject>& objects,
172 const gfx::PaletteGroup& palette_group,
173 const DungeonState* state = nullptr,
174 gfx::BackgroundBuffer* layout_bg1 = nullptr,
175 bool reset_room_event_indices = true,
176 gfx::BackgroundBuffer* layout_bg2 = nullptr);
177
183 int GetDrawRoutineId(int16_t object_id) const;
184
189 return static_cast<int>(draw_routines_.size());
190 }
191
197
206 void DrawTileToBitmap(gfx::Bitmap& bitmap, const gfx::TileInfo& tile_info,
207 int pixel_x, int pixel_y, const uint8_t* tiledata);
208
223 absl::Status DrawRoomDrawObjectData2x2(uint16_t object_id, int tile_x,
224 int tile_y,
226 uint16_t room_draw_object_data_offset,
229
235 std::pair<int, int> CalculateObjectDimensions(const RoomObject& object);
236
237 struct TileTrace {
238 uint16_t object_id = 0;
239 uint8_t size = 0;
240 uint8_t layer = 0;
241 int16_t x_tile = 0;
242 int16_t y_tile = 0;
243 uint16_t tile_id = 0;
244 uint8_t flags = 0;
245 };
246
247 void SetTraceCollector(std::vector<TileTrace>* collector,
248 bool trace_only = false);
249 void ClearTraceCollector();
250 bool TraceOnly() const { return trace_only_; }
251
252 protected:
253 // Draw routine function type
254 using DrawRoutine = std::function<void(
256 std::span<const gfx::TileInfo>, const DungeonState*)>;
257
258 // Core draw routines (based on ZScream's subtype1_routines table)
259 void DrawChest(const RoomObject& obj, gfx::BackgroundBuffer& bg,
260 std::span<const gfx::TileInfo> tiles,
261 const DungeonState* state = nullptr);
262 void DrawBigChest(const RoomObject& obj, gfx::BackgroundBuffer& bg,
263 std::span<const gfx::TileInfo> tiles,
264 const DungeonState* state = nullptr);
266 std::span<const gfx::TileInfo> tiles,
267 const DungeonState* state = nullptr);
268
269 void DrawNothing(const RoomObject& obj, gfx::BackgroundBuffer& bg,
270 std::span<const gfx::TileInfo> tiles,
271 const DungeonState* state = nullptr);
272 void CustomDraw(const RoomObject& obj, gfx::BackgroundBuffer& bg,
273 std::span<const gfx::TileInfo> tiles,
274 const DungeonState* state = nullptr);
276 std::span<const gfx::TileInfo> tiles,
277 const DungeonState* state = nullptr);
280 std::span<const gfx::TileInfo> tiles,
281 const DungeonState* state = nullptr);
282
283 // Type 3 / Special Routines
285 std::span<const gfx::TileInfo> tiles, int width,
286 int height);
287
288 // Custom Object Routine
290 std::span<const gfx::TileInfo> tiles,
291 const DungeonState* state = nullptr);
293 int tile_y);
294
295 // Utility methods
296 // Execute a DrawRoutineRegistry routine (pure DrawContext function) but render
297 // via ObjectDrawer::WriteTile8 so output hits the bitmap-backed buffers used
298 // by RoomLayerManager compositing.
299 void DrawUsingRegistryRoutine(int routine_id, const RoomObject& obj,
301 std::span<const gfx::TileInfo> tiles,
302 const DungeonState* state);
303 void WriteTile8(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
304 const gfx::TileInfo& tile_info);
305 bool IsValidTilePosition(int tile_x, int tile_y) const;
306
307 // Check if a draw routine should render to both BG1 and BG2
308 // Uses metadata instead of hardcoded routine IDs
309 static bool RoutineDrawsToBothBGs(int routine_id);
310
311 // Record a deferred BG1 reveal instead of mutating the raw BG1 pixels.
312 void MarkBg1RectRevealed(gfx::BackgroundBuffer& bg1, int start_px,
313 int start_py, int pixel_width, int pixel_height);
315 const gfx::TileInfo& tile_info,
316 int pixel_x, int pixel_y,
317 const uint8_t* tiledata);
318 static bool RequiresRectangularBg1Mask(const RoomObject& object);
319
320 // Door indicator fallback when graphics unavailable
321 void DrawDoorIndicator(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
322 int width, int height, DoorType type,
323 DoorDirection direction);
324
325 // Draw routine function array (indexed by routine ID from DrawRoutineRegistry)
326 std::vector<DrawRoutine> draw_routines_;
328
330 uint16_t object_id = 0;
331 uint8_t size = 0;
332 uint8_t layer = 0;
333 };
334
335 void SetTraceContext(const RoomObject& object, RoomObject::LayerType layer);
336 void PushTrace(int tile_x, int tile_y, const gfx::TileInfo& tile_info);
337 static void TraceHookThunk(gfx::BackgroundBuffer* bg, int tile_x, int tile_y,
338 const gfx::TileInfo& tile_info, void* user_data);
339
341 std::vector<TileTrace>* trace_collector_ = nullptr;
342 bool trace_only_ = false;
343
344 // Optional job-owned snapshot; caller keeps it alive through drawing.
348 mutable int current_chest_index_ = 0;
351 int room_tag2_ = -1;
352 uint8_t floor1_graphics_ = 0;
353 uint8_t floor2_graphics_ = 0;
355 // Object BG2 buffer: receives upper-tilemap writes past row 63.
365 const uint8_t*
366 room_gfx_buffer_; // Room-specific graphics buffer (current_gfx16_)
367
368 // Canvas dimensions in tiles (64x64 = 512x512 pixels)
369 static constexpr int kMaxTilesX = 64;
370 static constexpr int kMaxTilesY = 64;
371};
372
373} // namespace zelda3
374} // namespace yaze
375
376#endif // YAZE_APP_ZELDA3_DUNGEON_OBJECT_DRAWER_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
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:70
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
static std::pair< int, int > PositionToRenderTileCoords(uint8_t position, DoorDirection direction)
Convert encoded position to the top-left tile of the visible door.
Interface for accessing dungeon game state.
Draws dungeon objects to background buffers using game patterns.
int GetDrawRoutineId(int16_t object_id) const
Get draw routine ID for an object.
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
absl::Status DrawVitreousGoo(const RoomObject &object, gfx::BackgroundBuffer &bg2)
void DrawTileToBitmap(gfx::Bitmap &bitmap, const gfx::TileInfo &tile_info, int pixel_x, int pixel_y, const uint8_t *tiledata)
Draw a single tile directly to bitmap.
void InitializeDrawRoutines()
Initialize draw routine registry Must be called before drawing objects.
void DrawRightwards4x4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
int GetDrawRoutineCount() const
Get the total number of registered draw routines.
gfx::BackgroundBuffer * active_mask_source_bg_
void DrawBigChest(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
std::vector< TileTrace > * trace_collector_
gfx::BackgroundBuffer * active_layout_bg1_mask_
std::vector< DrawRoutine > draw_routines_
void DrawUsingRegistryRoutine(int routine_id, const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state)
gfx::BackgroundBuffer * registry_secondary_bg_
static bool RequiresRectangularBg1Mask(const RoomObject &object)
static void TraceHookThunk(gfx::BackgroundBuffer *bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info, void *user_data)
void SetRoomFloorGraphics(uint8_t floor1, uint8_t floor2)
absl::Status DrawBigDecor10x8(const RoomObject &object, gfx::BackgroundBuffer &target_bg, RoomObject::LayerType layer, int data_pc)
void MarkBg1OpaqueTilePixelsRevealed(gfx::BackgroundBuffer &bg1, const gfx::TileInfo &tile_info, int pixel_x, int pixel_y, const uint8_t *tiledata)
void SetBG1RevealMaskSource(gfx::BG1RevealMaskSource source)
std::pair< int, int > CalculateObjectDimensions(const RoomObject &object)
Calculate the dimensions (width, height) of an object in pixels.
void SetTraceContext(const RoomObject &object, RoomObject::LayerType layer)
void MarkBg1RectRevealed(gfx::BackgroundBuffer &bg1, int start_px, int start_py, int pixel_width, int pixel_height)
gfx::BackgroundBuffer * active_object_bg1_mask_
const uint8_t * room_gfx_buffer_
static bool RoutineDrawsToBothBGs(int routine_id)
void DrawNothing(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDoor(const DoorDef &door, int door_index, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const DungeonState *state=nullptr, gfx::BackgroundBuffer *layout_bg1=nullptr, gfx::BackgroundBuffer *layout_bg2=nullptr)
Draw a door to background buffers.
void DrawChestHoleOverlay(int tag1, int tag2, const DungeonState *state, gfx::BackgroundBuffer &bg1)
std::function< void( ObjectDrawer *, const RoomObject &, gfx::BackgroundBuffer &, std::span< const gfx::TileInfo >, const DungeonState *)> DrawRoutine
void DrawBigKeyLock(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
RoomObject::LayerType registry_primary_layer_
void DrawPotItem(uint8_t item_id, int x, int y, gfx::BackgroundBuffer &bg)
Draw a pot item visualization.
void DrawDoorIndicator(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, int width, int height, DoorType type, DoorDirection direction)
void DrawLargeCanvasObject(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, int width, int height)
void PushTrace(int tile_x, int tile_y, const gfx::TileInfo &tile_info)
absl::Status DrawObjectList(const std::vector< RoomObject > &objects, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group, const DungeonState *state=nullptr, gfx::BackgroundBuffer *layout_bg1=nullptr, bool reset_room_event_indices=true, gfx::BackgroundBuffer *layout_bg2=nullptr)
Draw all objects in a room.
void DrawCustomObject(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
const CustomObjectRenderSnapshot * custom_objects_
void DrawRightwardsDecor4x3spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
static constexpr int kMaxTilesX
absl::Status DrawLayerMaskFull(const RoomObject &object, gfx::BackgroundBuffer &target_bg, RoomObject::LayerType layer)
gfx::BackgroundBuffer * registry_bg2_
absl::Status DrawAgahnimsWindows(const RoomObject &object, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, gfx::BackgroundBuffer *layout_bg1, gfx::BackgroundBuffer *layout_bg2)
void DrawChest(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void CustomDraw(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawMissingCustomObjectPlaceholder(gfx::BackgroundBuffer &bg, int tile_x, int tile_y)
absl::Status DrawObject(const RoomObject &object, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group, const DungeonState *state=nullptr, gfx::BackgroundBuffer *layout_bg1=nullptr, gfx::BackgroundBuffer *layout_bg2=nullptr)
Draw a room object to background buffers.
ObjectDrawer(Rom *rom, int room_id, const uint8_t *room_gfx_buffer=nullptr, const CustomObjectRenderSnapshot *custom_objects=nullptr)
static constexpr int kMaxTilesY
absl::Status DrawRoomDrawObjectData2x2(uint16_t object_id, int tile_x, int tile_y, RoomObject::LayerType layer, uint16_t room_draw_object_data_offset, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2)
Draw a fixed 2x2 (16x16) tile pattern from RoomDrawObjectData.
void SetTraceCollector(std::vector< TileTrace > *collector, bool trace_only=false)
bool IsValidTilePosition(int tile_x, int tile_y) const
gfx::BG1RevealMaskSource bg1_reveal_mask_source_
const gfx::BackgroundBuffer * registry_primary_layout_bg_
absl::Status DrawLampCones(const RoomObject &object, gfx::BackgroundBuffer &bg2)
RoomObject::LayerType registry_secondary_layer_
constexpr DoorDimensions GetDoorDimensions(DoorDirection dir)
Get door dimensions based on direction.
Definition door_types.h:253
DoorType
Door types from ALTTP.
Definition door_types.h:33
DoorDirection
Door direction on room walls.
Definition door_types.h:18
Represents a group of palettes.
Door dimensions in tiles (8x8 pixel tiles)
Definition door_types.h:221
std::pair< int, int > GetTileCoords() const
DoorDimensions GetDimensions() const