yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
object_tile_editor.h
Go to the documentation of this file.
1#ifndef YAZE_ZELDA3_DUNGEON_OBJECT_TILE_EDITOR_H_
2#define YAZE_ZELDA3_DUNGEON_OBJECT_TILE_EDITOR_H_
3
4#include <cstddef>
5#include <cstdint>
6#include <filesystem>
7#include <optional>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include "absl/status/status.h"
13#include "absl/status/statusor.h"
14#include "app/gfx/core/bitmap.h"
17#include "rom/rom.h"
20#include "zelda3/dungeon/room.h"
21
22namespace yaze {
23namespace zelda3 {
24
29 uint32_t pc_address = 0;
30 std::vector<uint16_t> expected_words;
31};
32
40 int16_t object_id = -1;
43 std::vector<ObjectTileSourceSpan> spans;
44};
45
50 size_t span_index = 0;
51 size_t word_index = 0;
52};
53
59 int16_t object_id = -1;
60 std::vector<ObjectTileReadRange> overlapping_ranges;
61};
62
64 // Synthesized room object 0x150 reads the unlit/lit torch blocks directly
65 // during initial room drawing; it is not representable in the persisted
66 // dungeon object stream.
68 // Underworld light/extinguish updates read the same literal blocks again
69 // when replacing the torch tiles at runtime.
71};
72
77
87 std::vector<ObjectTileSourceImpactEntry> affected_objects;
88 std::vector<ObjectTileRuntimeConsumerImpactEntry> runtime_consumers;
89
90 size_t consumer_count() const {
91 return affected_objects.size() + runtime_consumers.size();
92 }
93};
94
102 int16_t object_id = 0;
105
106 struct Cell {
107 int rel_x = 0; // 0-based tile X within bounding box
108 int rel_y = 0; // 0-based tile Y within bounding box
109 gfx::TileInfo tile_info; // Decomposed SNES tilemap word
110 uint16_t original_word = 0;
111 // Legacy name retained for preview/test compatibility. This is draw-trace
112 // order only and never authorizes a ROM write; draw order is not generally
113 // source order.
114 int write_index = -1;
115 std::optional<ObjectTileSourceRef> source_ref;
116 bool modified = false;
117 };
118
119 std::vector<Cell> cells;
120 int bounds_width = 0; // Bounding box width in 8px tiles
121 int bounds_height = 0; // Bounding box height in 8px tiles
122
123 // Legacy display/shared-data metadata. Standard writes are authorized only
124 // by source_provenance + per-cell source_ref, never by this base address.
126 std::optional<ObjectTileSourceProvenance> source_provenance;
127 bool is_custom = false;
129 std::string custom_filename;
130 std::filesystem::path custom_resolved_path;
131 std::vector<uint8_t> custom_source_bytes;
132
134 const std::vector<ObjectDrawer::TileTrace>& traces);
135
136 Cell* FindCell(int rel_x, int rel_y);
137 const Cell* FindCell(int rel_x, int rel_y) const;
138
139 bool HasModifications() const;
140 void RevertAll();
141};
142
150 public:
151 struct Write {
152 int address = -1;
153 uint16_t expected_word = 0;
154 uint16_t word = 0;
155 };
156
158 int address = -1;
159 uint16_t expected_word = 0;
160 };
161
164 ObjectTileWritePlan& operator=(const ObjectTileWritePlan&) = default;
165 ObjectTileWritePlan& operator=(ObjectTileWritePlan&&) noexcept = default;
166
167 const std::vector<Write>& writes() const { return writes_; }
168 const std::vector<WordPrecondition>& preconditions() const {
169 return preconditions_;
170 }
171 const std::vector<std::pair<uint32_t, uint32_t>>& write_ranges() const {
172 return write_ranges_;
173 }
174
175 private:
176 friend class ObjectTileEditor;
177
179
180 std::vector<Write> writes_;
181 // Includes the pointer descriptor and every captured source word. Apply
182 // rechecks these immediately before opening the transaction.
183 std::vector<WordPrecondition> preconditions_;
184 std::vector<std::pair<uint32_t, uint32_t>> write_ranges_;
185};
186
195 public:
196 static constexpr int kAtlasTilesPerRow = 16;
197 static constexpr int kAtlasTileRows = 64;
199 static constexpr int kAtlasWidthPx = kAtlasTilesPerRow * 8;
200 static constexpr int kAtlasHeightPx = kAtlasTileRows * 8;
201
202 explicit ObjectTileEditor(Rom* rom);
203
204 // Capture: run object draw in trace_only mode, build editable layout
205 absl::StatusOr<ObjectTileLayout> CaptureObjectLayout(
206 int16_t object_id, const Room& room, const gfx::PaletteGroup& palette);
207 absl::StatusOr<ObjectTileLayout> CaptureObjectLayout(
208 int16_t object_id, const Room& room, const gfx::PaletteGroup& palette,
209 uint8_t object_size);
210
211 // Capture a standard object with exact ROM source provenance. The initial
212 // fail-closed allowlist is intentionally limited to the two audited fixed
213 // 2x2 subtype-2 objects (0x11F and 0x120).
214 absl::StatusOr<ObjectTileLayout> CaptureEditableObjectLayout(
215 int16_t object_id, const Room& room, const gfx::PaletteGroup& palette);
216
217 // Load one existing fixed runtime custom-object asset directly from its
218 // binary source, including no-op words and exact bytes for stale-write CAS.
219 absl::StatusOr<ObjectTileLayout> LoadCustomObjectLayout(int16_t object_id,
220 int subtype);
221
222 static bool IsEditableStandardObject(int16_t object_id);
223
224 // Render: draw layout to preview bitmap using room's gfx buffer
225 absl::Status RenderLayoutToBitmap(const ObjectTileLayout& layout,
226 gfx::Bitmap& bitmap,
227 const uint8_t* room_gfx_buffer,
228 const gfx::PaletteGroup& palette);
229
230 // Build a source-ID atlas from room graphics. Custom objects show the
231 // runtime-effective tile at each raw source ID without changing saved words.
232 // Retained H/V/priority attributes affect zero-word detection only; atlas
233 // images remain unflipped so their orientation is consistent when browsing.
234 absl::Status BuildTile8Atlas(
235 gfx::Bitmap& atlas, const uint8_t* room_gfx_buffer,
236 const gfx::PaletteGroup& palette, int display_palette = 2,
237 std::optional<int16_t> custom_object_id = std::nullopt,
238 uint16_t retained_attributes = 0);
239
240 // Write-back: standard objects patch ROM, custom objects write .bin
241 absl::Status WriteBack(ObjectTileLayout& layout);
242
243 // Resolve and validate all standard-object writes before any ROM mutation.
244 absl::StatusOr<ObjectTileWritePlan> BuildStandardWritePlan(
245 const ObjectTileLayout& layout) const;
246
247 // Atomically apply a previously validated standard-object write plan.
248 absl::Status ApplyStandardWritePlan(const ObjectTileWritePlan& plan);
249
250 // Enumerate every representable standard object whose parser-visible source
251 // ranges overlap this editable layout, plus the explicit runtime consumers
252 // modeled by this backend. Resolution errors are returned to the caller and
253 // must block writes rather than being interpreted as no sharing. Other
254 // runtime-only behavior remains a separate parity-audit concern.
255 absl::StatusOr<ObjectTileSourceImpact> AnalyzeStandardTileSourceImpact(
256 const ObjectTileLayout& layout) const;
257
258 private:
260};
261
262} // namespace zelda3
263} // namespace yaze
264
265#endif // YAZE_ZELDA3_DUNGEON_OBJECT_TILE_EDITOR_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:28
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:69
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
Captures and edits the tile8 composition of dungeon objects.
absl::StatusOr< ObjectTileSourceImpact > AnalyzeStandardTileSourceImpact(const ObjectTileLayout &layout) const
absl::Status ApplyStandardWritePlan(const ObjectTileWritePlan &plan)
static constexpr int kAtlasTilesPerRow
absl::Status RenderLayoutToBitmap(const ObjectTileLayout &layout, gfx::Bitmap &bitmap, const uint8_t *room_gfx_buffer, const gfx::PaletteGroup &palette)
static bool IsEditableStandardObject(int16_t object_id)
absl::Status BuildTile8Atlas(gfx::Bitmap &atlas, const uint8_t *room_gfx_buffer, const gfx::PaletteGroup &palette, int display_palette=2, std::optional< int16_t > custom_object_id=std::nullopt, uint16_t retained_attributes=0)
absl::StatusOr< ObjectTileLayout > CaptureObjectLayout(int16_t object_id, const Room &room, const gfx::PaletteGroup &palette)
absl::Status WriteBack(ObjectTileLayout &layout)
absl::StatusOr< ObjectTileLayout > CaptureEditableObjectLayout(int16_t object_id, const Room &room, const gfx::PaletteGroup &palette)
absl::StatusOr< ObjectTileWritePlan > BuildStandardWritePlan(const ObjectTileLayout &layout) const
absl::StatusOr< ObjectTileLayout > LoadCustomObjectLayout(int16_t object_id, int subtype)
Fully resolved standard-object ROM writes.
std::vector< std::pair< uint32_t, uint32_t > > write_ranges_
const std::vector< Write > & writes() const
const std::vector< WordPrecondition > & preconditions() const
std::vector< WordPrecondition > preconditions_
ObjectTileWritePlan(const ObjectTileWritePlan &)=default
const std::vector< std::pair< uint32_t, uint32_t > > & write_ranges() const
ObjectTileWritePlan(ObjectTileWritePlan &&) noexcept=default
Represents a group of palettes.
std::optional< ObjectTileSourceRef > source_ref
Editable tile8 layout captured from an object's draw trace.
std::vector< uint8_t > custom_source_bytes
std::optional< ObjectTileSourceProvenance > source_provenance
std::filesystem::path custom_resolved_path
Cell * FindCell(int rel_x, int rel_y)
static ObjectTileLayout FromTraces(const std::vector< ObjectDrawer::TileTrace > &traces)
std::vector< ObjectTileReadRange > overlapping_ranges
One standard object whose parser-visible tile sources overlap an editable layout's authorized source ...
std::vector< ObjectTileReadRange > overlapping_ranges
Fail-closed impact inventory within ObjectParser's source model plus explicitly modeled runtime consu...
std::vector< ObjectTileRuntimeConsumerImpactEntry > runtime_consumers
std::vector< ObjectTileSourceImpactEntry > affected_objects
ROM descriptor and source snapshot authorizing an editable capture.
std::vector< ObjectTileSourceSpan > spans
A cell's exact word within an authorized source span.
One contiguous ROM-backed source span for an object's tile words.
std::vector< uint16_t > expected_words