4#include "absl/status/status.h"
72 if (!is_current_map && !is_current_world) {
93 bool needs_graphics_rebuild = (*
ctx_.
maps_bmp)[map_index].modified();
95 if (needs_graphics_rebuild) {
97 map->LoadAreaGraphics();
100 auto status = map->BuildTileset();
103 "Failed to build tileset for map %d: %s", map_index,
104 status.message().data());
113 "Failed to build tiles16 graphics for map %d: %s", map_index,
114 status.message().data());
122 "Failed to build bitmap for map %d: %s", map_index,
123 status.message().data());
128 (*
ctx_.
maps_bmp)[map_index].set_data(map->bitmap_data());
132 if (!(*
ctx_.
maps_bmp)[map_index].ValidateDataSurfaceSync()) {
134 "Warning: Surface synchronization issue detected for map %d",
151 bool use_v3_area_sizes =
154 if (use_v3_area_sizes) {
159 if (map->is_large_map()) {
184 if (area_size == AreaSizeEnum::SmallArea) {
189 int parent_id = map->
parent();
195 "RefreshMultiAreaMapsSafely: Could not get parent map %d for "
197 parent_id, map_index);
202 "RefreshMultiAreaMapsSafely: Processing %s area from parent %d "
204 (area_size == AreaSizeEnum::LargeArea) ?
"large"
205 : (area_size == AreaSizeEnum::WideArea) ?
"wide"
207 parent_id, map_index);
211 std::vector<int> sibling_maps;
214 case AreaSizeEnum::LargeArea:
216 sibling_maps = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
219 case AreaSizeEnum::WideArea:
221 sibling_maps = {parent_id, parent_id + 1};
224 case AreaSizeEnum::TallArea:
226 sibling_maps = {parent_id, parent_id + 8};
231 "RefreshMultiAreaMapsSafely: Unknown area size %d for map %d",
232 static_cast<int>(area_size), map_index);
239 for (
int sibling : sibling_maps) {
242 if (sibling == map_index) {
258 if (is_current_map || is_current_world) {
260 "RefreshMultiAreaMapsSafely: Refreshing sibling map %d",
268 sibling_map->LoadAreaGraphics();
270 auto status = sibling_map->BuildTileset();
273 "Failed to build tileset for sibling %d: %s", sibling,
274 status.message().data());
282 "Failed to build tiles16 for sibling %d: %s", sibling,
283 status.message().data());
287 status = sibling_map->LoadPalette();
290 "Failed to load palette for sibling %d: %s", sibling,
291 status.message().data());
295 status = sibling_map->BuildBitmap(
299 "Failed to build bitmap for sibling %d: %s", sibling,
300 status.message().data());
305 (*
ctx_.
maps_bmp)[sibling].set_data(sibling_map->bitmap_data());
310 (*
ctx_.
maps_bmp)[sibling].SetPalette(sibling_map->current_palette());
331 return absl::FailedPreconditionError(
"Current overworld map not loaded");
349 bool use_v3_area_sizes =
352 if (use_v3_area_sizes) {
355 auto area_size = current_map->area_size();
357 if (area_size != AreaSizeEnum::SmallArea) {
359 std::vector<int> sibling_maps;
360 int parent_id = current_map->parent();
363 case AreaSizeEnum::LargeArea:
365 sibling_maps = {parent_id, parent_id + 1, parent_id + 8,
368 case AreaSizeEnum::WideArea:
370 sibling_maps = {parent_id, parent_id + 1};
372 case AreaSizeEnum::TallArea:
374 sibling_maps = {parent_id, parent_id + 8};
381 for (
int sibling_index : sibling_maps) {
392 sibling_map->current_palette());
400 if (current_map->is_large_map()) {
402 for (
int i = 1; i < 4; i++) {
403 int sibling_index = current_map->parent() + i;
418 sibling_map->current_palette());
430 return absl::OkStatus();
435 if (map_index >= 0 && map_index <
static_cast<int>(
ctx_.
maps_bmp->size())) {
446 "ForceRefreshGraphics: Map %d marked for refresh", map_index);
452 if (map_index < 0 || map_index >=
static_cast<int>(
ctx_.
maps_bmp->size())) {
461 int parent_id = map->parent();
462 std::vector<int> siblings;
464 switch (map->area_size()) {
466 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
469 siblings = {parent_id, parent_id + 1};
472 siblings = {parent_id, parent_id + 8};
478 for (
int sibling : siblings) {
479 if (sibling >= 0 && sibling < 0xA0) {
481 if (sibling == map_index && !include_self) {
497 "RefreshSiblingMapGraphics: Refreshed sibling map %d", sibling);
503 const auto& current_ow_map =
508 bool use_v3_area_sizes =
511 if (use_v3_area_sizes) {
514 auto area_size = current_ow_map.area_size();
516 if (area_size != AreaSizeEnum::SmallArea) {
518 std::vector<int> sibling_maps;
519 int parent_id = current_ow_map.parent();
522 case AreaSizeEnum::LargeArea:
524 sibling_maps = {parent_id + 1, parent_id + 8, parent_id + 9};
526 case AreaSizeEnum::WideArea:
528 sibling_maps = {parent_id + 1};
530 case AreaSizeEnum::TallArea:
532 sibling_maps = {parent_id + 8};
539 for (
int sibling_index : sibling_maps) {
544 map.set_area_graphics(current_ow_map.area_graphics());
545 map.set_area_palette(current_ow_map.area_palette());
546 map.set_sprite_graphics(
550 map.set_message_id(current_ow_map.message_id());
553 map.LoadAreaGraphics();
558 if (current_ow_map.is_large_map()) {
560 for (
int i = 1; i < 4; i++) {
561 int sibling_index = current_ow_map.parent() + i;
566 map.set_area_graphics(current_ow_map.area_graphics());
567 map.set_area_palette(current_ow_map.area_palette());
568 map.set_sprite_graphics(
572 map.set_message_id(current_ow_map.message_id());
575 map.LoadAreaGraphics();
582 LOG_DEBUG(
"MapRefreshCoordinator",
"RefreshTile16Blockset called");
585 return absl::OkStatus();
617 return absl::OkStatus();
639 constexpr int kTilesPerRow = 8;
640 constexpr int kTileSize = 16;
644 bool atlas_modified =
false;
657 if (!pending_bmp || !pending_bmp->
is_active() ||
658 pending_bmp->
vector().empty()) {
663 int tile_x = (tile_id % kTilesPerRow) * kTileSize;
664 int tile_y = (tile_id / kTilesPerRow) * kTileSize;
667 if (tile_x + kTileSize > atlas_width || tile_y + kTileSize > atlas_height) {
673 const auto& pending_data = pending_bmp->
vector();
675 for (
int y = 0; y < kTileSize && y < pending_bmp->
height(); ++y) {
676 for (
int x = 0; x < kTileSize && x < pending_bmp->
width(); ++x) {
677 int atlas_idx = (tile_y + y) * atlas_width + (tile_x + x);
678 int pending_idx = y * pending_bmp->
width() + x;
680 if (atlas_idx >= 0 && atlas_idx <
static_cast<int>(atlas_data.size()) &&
682 pending_idx <
static_cast<int>(pending_data.size())) {
683 atlas_data[atlas_idx] = pending_data[pending_idx];
684 atlas_modified =
true;
void RefreshMapProperties()
Refresh map properties (copy parent properties to siblings)
void RefreshMultiAreaMapsSafely(int map_index, zelda3::OverworldMap *map)
Safely refresh multi-area maps without recursion.
void RefreshChildMapOnDemand(int map_index)
On-demand child map refresh with selective updates.
void RefreshChildMap(int map_index)
Refresh a child map's graphics pipeline (legacy full rebuild)
absl::Status RefreshMapPalette()
Refresh map palette after palette property changes.
void InvalidateGraphicsCache(int map_id=-1)
Invalidate cached graphics for a specific map or all maps.
void RefreshOverworldMap()
Refresh the current overworld map.
absl::Status RefreshTile16Blockset()
Refresh the tile16 blockset after graphics/palette changes.
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
Refresh sibling map graphics for multi-area maps.
void UpdateBlocksetWithPendingTileChanges()
Update blockset atlas with pending tile16 editor changes.
void RefreshOverworldMapOnDemand(int map_index)
On-demand map refresh that only updates what's actually needed.
void ForceRefreshGraphics(int map_index)
Force refresh graphics for a specific map.
const gfx::Bitmap * GetPendingTileBitmap(int tile_id) const
Get preview bitmap for a pending tile (nullptr if not modified)
bool has_pending_changes() const
Check if any tiles have uncommitted changes.
bool is_tile_modified(int tile_id) const
Check if a specific tile has pending changes.
void set_palette(const gfx::SnesPalette &palette)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Represents a bitmap image optimized for SNES ROM hacking.
TextureHandle texture() const
const std::vector< uint8_t > & vector() const
void set_modified(bool modified)
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
std::vector< uint8_t > & mutable_data()
Represents a single Overworld map screen.
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static bool SupportsAreaEnum(OverworldVersion version)
Check if ROM supports area enum system (v3+ only)
auto tile16_blockset_data() const
auto current_area_palette() const
void ClearGraphicsConfigCache()
Clear entire graphics config cache Call when palette or graphics settings change globally.
std::vector< gfx::Tile16 > tiles16() const
void InvalidateSiblingMapCaches(int map_index)
Invalidate cached tilesets for a map and all its siblings.
auto overworld_map(int i) const
void set_current_map(int i)
auto mutable_overworld_map(int i)
OverworldBlockset & GetMapTiles(int world_type)
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
#define PRINT_IF_ERROR(expression)
Editors are the view controllers for the application.
void UpdateTilemap(IRenderer *renderer, Tilemap &tilemap, const std::vector< uint8_t > &data)
constexpr int kNumTile16Individual
constexpr int kNumOverworldMaps
AreaSizeEnum
Area size enumeration for v3+ ROMs.
#define RETURN_IF_ERROR(expr)
gfx::Tilemap * tile16_blockset
gfx::SnesPalette * palette
zelda3::Overworld * overworld
std::function< void(int map_index)> ensure_map_texture
Callback to ensure a map texture is created (stays in OverworldEditor)
gfx::IRenderer * renderer
Tile16Editor * tile16_editor
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::Bitmap * current_gfx_bmp
bool * map_blockset_loaded
gfx::BitmapTable * current_graphics_set
Bitmap atlas
Master bitmap containing all tiles.