16 for (
int q = 0; q < 4; ++q) {
25bool ContainsTile(
const std::vector<Tile16Commit>& edits,
int tile_id) {
26 return std::any_of(edits.begin(), edits.end(), [tile_id](
const auto& edit) {
27 return edit.tile_id == tile_id;
33 using Apply = std::function<absl::Status(
const std::vector<Tile16Commit>&)>;
35 std::vector<Tile16Commit> after,
Apply apply,
36 std::string description = {},
37 const void* owner =
nullptr,
38 uint64_t edit_group = 0)
39 : before_(std::move(before)),
40 after_(std::move(after)),
41 apply_(std::move(apply)),
42 description_(std::move(description)),
44 edit_group_(edit_group) {}
45 absl::Status
Undo()
override {
return apply_(before_); }
46 absl::Status
Redo()
override {
return apply_(after_); }
48 if (!description_.empty())
50 return before_.size() == 1 ?
"Edit Tile16 definition" :
"Edit Tile16 stamp";
53 return (before_.size() + after_.size()) *
sizeof(
Tile16Commit);
56 const auto* previous =
58 return edit_group_ != 0 && previous !=
nullptr &&
59 previous->
owner_ == owner_ && previous->edit_group_ == edit_group_;
64 std::vector<Tile16Commit> before = std::move(previous.before_);
65 for (
auto& edit : before_) {
67 before.push_back(std::move(edit));
69 for (
auto& edit : previous.after_) {
71 after_.push_back(std::move(edit));
73 before_ = std::move(before);
77 std::vector<Tile16Commit> before_,
after_;
80 const void* owner_ =
nullptr;
81 uint64_t edit_group_ = 0;
88 return absl::OutOfRangeError(
"Tile16 is outside the document");
96 return absl::FailedPreconditionError(
"No Tile16 document");
101 const std::vector<Tile16Commit>& definitions) {
104 std::vector<gfx::Bitmap> bitmaps(definitions.size());
105 for (
size_t i = 0; i < definitions.size(); ++i) {
106 const auto& edit = definitions[i];
110 return absl::OutOfRangeError(
"Tile16 edit is outside the document");
115 for (
size_t i = 0; i < definitions.size(); ++i) {
116 const auto& edit = definitions[i];
120 (*document_definitions_)[edit.tile_id] = edit.tile_data;
139 return absl::OkStatus();
143 const std::vector<Tile16Commit>& definitions)
const {
144 if (definitions.empty())
145 return absl::OkStatus();
147 return absl::FailedPreconditionError(
148 "Tile16 blockset or ROM not initialized");
150 std::set<int> destinations;
151 for (
const auto& edit : definitions) {
155 return absl::OutOfRangeError(
"Tile16 import is outside the document");
157 if (!destinations.insert(edit.tile_id).second) {
158 return absl::InvalidArgumentError(
159 "Tile16 import contains a duplicate destination");
162 for (
int q = 0; q < 4; ++q) {
164 if (info.id_ >= 1024 ||
167 return absl::OutOfRangeError(
168 "Tile16 import has invalid Tile8 metadata");
183absl::StatusOr<std::unique_ptr<UndoAction>>
185 const std::vector<Tile16Commit>& definitions, std::string description) {
187 std::vector<Tile16Commit> before, after;
188 for (
const auto& edit : definitions) {
190 auto normalized = edit.tile_data;
192 if (!SameDefinition(original, normalized)) {
193 before.push_back({edit.tile_id, std::move(original)});
194 after.push_back({edit.tile_id, std::move(normalized)});
198 return std::unique_ptr<UndoAction>{};
199 return std::unique_ptr<UndoAction>(
200 std::make_unique<Tile16DefinitionEditAction>(
201 std::move(before), std::move(after),
202 [
this](
const std::vector<Tile16Commit>& edits) {
206 std::move(description)));
210 const std::vector<Tile16Commit>& definitions, std::string description) {
212 definitions, std::move(description)));
214 return absl::OkStatus();
221 return absl::OkStatus();
225 const std::function<absl::Status()>& operation, uint64_t edit_group) {
231 const auto result = operation();
236 std::vector<Tile16Commit> before, after;
237 for (
const auto& [
id, data] : proposed) {
239 if (!original.ok()) {
241 return original.status();
243 if (!SameDefinition(*original, data)) {
244 before.push_back({id, *original});
245 after.push_back({id, data});
250 for (
const auto& edit : before) {
267 history_->
Push(std::make_unique<Tile16DefinitionEditAction>(
268 std::move(before), std::move(after),
269 [
this](
const std::vector<Tile16Commit>& edits) {
272 std::string{},
this, edit_group));
273 return absl::OkStatus();
277 uint64_t edit_group) {
284 return absl::OkStatus();
absl::StatusOr< gfx::Tile16 > ReadTile16(uint32_t tile16_id, uint32_t tile16_ptr)
void set_dirty(bool dirty)
gfx::Tile16 current_tile16_data_
absl::Status SetCurrentTile(int id)
absl::Status ApplyDefinitions(const std::vector< Tile16Commit > &definitions)
absl::Status RegenerateTile16BitmapFromROM()
absl::Status RunEdit(const std::function< absl::Status()> &operation, uint64_t edit_group=0)
absl::StatusOr< gfx::Tile16 > ReadDocumentTile(int id) const
std::function< void()> before_edit_
void CopyTileBitmapToBlockset(int tile_id, const gfx::Bitmap &tile_bitmap)
std::map< int, gfx::Bitmap > edited_tile_bitmaps_
absl::Status ValidateDefinitionImport(const std::vector< Tile16Commit > &definitions) const
gfx::Bitmap * tile16_blockset_bmp_
gfx::Tilemap * tile16_blockset_
absl::Status ReplaceCurrentTile(const gfx::Tile16 &data, uint64_t edit_group=0)
std::map< int, gfx::Tile16 > document_edits_
absl::Status ImportDefinitions(const std::vector< Tile16Commit > &definitions, std::string description="Import Tile16 definitions")
absl::Status BuildTile16BitmapFromData(const gfx::Tile16 &tile_data, gfx::Bitmap *output_bitmap) const
gfx::Bitmap current_tile16_bmp_
bool HasTile16BlocksetBitmap() const
void MarkCurrentTileModified()
bool tile8_usage_cache_dirty_
std::function< void(const std::vector< Tile16Commit > &) on_document_changed_)
absl::StatusOr< std::unique_ptr< UndoAction > > PrepareDefinitionImport(const std::vector< Tile16Commit > &definitions, std::string description="Import Tile16 definitions")
std::vector< gfx::Tile16 > * document_definitions_
std::vector< zelda3::Tile8PixelData > current_gfx_individual_
Abstract base for all undoable actions (Command pattern)
void Push(std::unique_ptr< UndoAction > action)
std::vector< Tile16Commit > after_
void MergeWith(UndoAction &prev) override
absl::Status Redo() override
absl::Status Undo() override
Tile16DefinitionEditAction(std::vector< Tile16Commit > before, std::vector< Tile16Commit > after, Apply apply, std::string description={}, const void *owner=nullptr, uint64_t edit_group=0)
bool CanMergeWith(const UndoAction &prev) const override
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
std::function< absl::Status(const std::vector< Tile16Commit > &)> Apply
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Represents a bitmap image optimized for SNES ROM hacking.
const SnesPalette & palette() const
Tile composition of four 8x8 tiles.
#define ASSIGN_OR_RETURN(type_variable_name, expression)
bool ContainsTile(const std::vector< Tile16Commit > &edits, int tile_id)
Editors are the view controllers for the application.
uint16_t TileInfoToShort(TileInfo tile_info)
void SyncTile16TilesInfo(gfx::Tile16 *tile)
constexpr int kNumTile16Individual
constexpr uint32_t kTile16Ptr
const gfx::TileInfo & Tile16QuadrantInfo(const gfx::Tile16 &tile, int quadrant)
#define RETURN_IF_ERROR(expr)
Bitmap atlas
Master bitmap containing all tiles.