yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_editor.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_OVERWORLDEDITOR_H
2#define YAZE_APP_EDITOR_OVERWORLDEDITOR_H
3
4#include <chrono>
5#include <optional>
6
7#include "absl/status/status.h"
8#include "app/editor/editor.h"
19#include "app/gfx/core/bitmap.h"
23#include "app/gui/core/input.h"
25#include "rom/rom.h"
26#include "imgui/imgui.h"
28
29// =============================================================================
30// Overworld Editor - UI Layer
31// =============================================================================
32//
33// ARCHITECTURE OVERVIEW:
34// ----------------------
35// The OverworldEditor is the main UI class for editing overworld maps.
36// It orchestrates several subsystems:
37//
38// 1. TILE EDITING SYSTEM
39// - Tile16Editor: Popup for editing individual 16x16 tiles
40// - Tile selection and painting on the main canvas
41// - Undo/Redo stack for paint operations
42//
43// 2. ENTITY SYSTEM
44// - OverworldEntityRenderer: Draws entities on the canvas
45// - entity_operations.cc: Insertion/deletion logic
46// - overworld_entity_interaction.cc: Drag/drop and click handling
47//
48// 3. MAP PROPERTIES SYSTEM
49// - MapPropertiesSystem: Toolbar and context menus
50// - OverworldSidebar: Property editing tabs
51// - Graphics, palettes, music per area
52//
53// 4. CANVAS SYSTEM
54// - ow_map_canvas_: Main overworld display (4096x4096)
55// - blockset_canvas_: Tile16 selector
56// - scratch_canvas_: Layout workspace
57//
58// EDITING MODES:
59// --------------
60// - DRAW_TILE: Left-click paints tiles, right-click opens tile16 editor
61// - MOUSE: Left-click selects entities, right-click opens context menus
62//
63// KEY WORKFLOWS:
64// --------------
65// See README.md in this directory for complete workflow documentation.
66//
67// SUBSYSTEM ORGANIZATION:
68// -----------------------
69// The class is organized into logical sections marked with comment blocks.
70// Each section groups related methods and state for a specific subsystem.
71// =============================================================================
72
73namespace yaze {
74namespace editor {
75
76// =============================================================================
77// Constants
78// =============================================================================
79
80constexpr unsigned int k4BPP = 4;
81constexpr unsigned int kByteSize = 3;
82constexpr unsigned int kMessageIdSize = 5;
83constexpr unsigned int kNumSheetsToLoad = 223;
84constexpr unsigned int kOverworldMapSize = 0x200;
87constexpr ImVec2 kCurrentGfxCanvasSize(0x100 + 1, 0x10 * 0x40 + 1);
88constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1);
89constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1);
90
91constexpr ImGuiTableFlags kOWMapFlags =
92 ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
93 ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp;
94
95constexpr absl::string_view kWorldList =
96 "Light World\0Dark World\0Extra World\0";
97
98constexpr absl::string_view kGamePartComboString = "Part 0\0Part 1\0Part 2\0";
99
100// Zoom/pan constants - centralized for consistency across all zoom controls
101constexpr float kOverworldMinZoom = 0.1f;
102constexpr float kOverworldMaxZoom = 5.0f;
103constexpr float kOverworldZoomStep = 0.25f;
104
105constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
106
125class OverworldEditor : public Editor, public gfx::GfxContext {
126 public:
127 // ===========================================================================
128 // Construction and Initialization
129 // ===========================================================================
130
134 // MapPropertiesSystem will be initialized after maps_bmp_ and canvas are
135 // ready
136 }
137
140 dependencies_ = deps;
141 }
142
149
150 // ===========================================================================
151 // Editor Interface Implementation
152 // ===========================================================================
153
154 void Initialize() override;
155 absl::Status Load() override;
156 absl::Status Update() final;
157 absl::Status Undo() override;
158 absl::Status Redo() override;
159 absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
160 absl::Status Copy() override;
161 absl::Status Paste() override;
162 absl::Status Find() override { return absl::UnimplementedError("Find"); }
163 absl::Status Save() override;
164 absl::Status Clear() override;
165
168
169 // ===========================================================================
170 // ZSCustomOverworld ASM Patching
171 // ===========================================================================
172 // These methods handle upgrading vanilla ROMs to support expanded features.
173 // See overworld_version_helper.h for version detection and feature matrix.
174
177 absl::Status ApplyZSCustomOverworldASM(int target_version);
178
180 absl::Status UpdateROMVersionMarkers(int target_version);
181
182 int jump_to_tab() { return jump_to_tab_; }
183 int jump_to_tab_ = -1;
184
185 // ===========================================================================
186 // ROM State
187 // ===========================================================================
188
189 bool IsRomLoaded() const override { return rom_ && rom_->is_loaded(); }
190 std::string GetRomStatus() const override {
191 if (!rom_)
192 return "No ROM loaded";
193 if (!rom_->is_loaded())
194 return "ROM failed to load";
195 return absl::StrFormat("ROM loaded: %s", rom_->title());
196 }
197
198 Rom* rom() const { return rom_; }
199
201 void set_current_map(int map_id) {
202 if (map_id >= 0 && map_id < zelda3::kNumOverworldMaps) {
203 // Finalize any pending paint operation before switching maps
205 current_map_ = map_id;
207 map_id / 0x40; // Calculate which world the map belongs to
210 }
211 }
212
213 // ===========================================================================
214 // Graphics Loading
215 // ===========================================================================
216
224 absl::Status LoadGraphics();
225
226 // ===========================================================================
227 // Entity System - Insertion and Editing
228 // ===========================================================================
229 // Entity operations are delegated to entity_operations.cc helper functions.
230 // Entity rendering is handled by OverworldEntityRenderer.
231 // Entity interaction (drag/drop) is in overworld_entity_interaction.cc.
232
235 void HandleEntityInsertion(const std::string& entity_type);
236
241
244 void HandleTile16Edit();
245
246 // ===========================================================================
247 // Keyboard Shortcuts
248 // ===========================================================================
249
250 void ToggleBrushTool();
251 void ActivateFillTool();
252 void CycleTileSelection(int delta);
253
258
259 // ===========================================================================
260 // Panel Drawing Methods
261 // ===========================================================================
262 // These are called by the panel wrapper classes in the panels/ subdirectory.
263
264 absl::Status DrawAreaGraphics();
265 absl::Status DrawTile16Selector();
266 void DrawMapProperties();
267
271 void InvalidateGraphicsCache(int map_id = -1);
272 absl::Status DrawScratchSpace();
273 void DrawTile8Selector();
274 absl::Status UpdateGfxGroupEditor();
275 void DrawV3Settings();
276
279
282
285
287 void DrawOverworldCanvas();
288
289 private:
290 // ===========================================================================
291 // Canvas Drawing
292 // ===========================================================================
293
295 void DrawOverworldMaps();
296 void DrawOverworldEdits();
298
299 // ===========================================================================
300 // Entity Interaction System
301 // ===========================================================================
302 // Handles mouse interactions with entities in MOUSE mode.
303
306
310
312 void HandleEntityContextMenus(zelda3::GameEntity* hovered_entity);
313
315 void HandleEntityDoubleClick(zelda3::GameEntity* hovered_entity);
316
319
320 // ===========================================================================
321 // Map Refresh System
322 // ===========================================================================
323 // Methods to refresh map graphics after property changes.
324
325 void RefreshChildMap(int map_index);
326 void RefreshOverworldMap();
327 void RefreshOverworldMapOnDemand(int map_index);
328 void RefreshChildMapOnDemand(int map_index);
329 void RefreshMultiAreaMapsSafely(int map_index, zelda3::OverworldMap* map);
330 absl::Status RefreshMapPalette();
332 absl::Status RefreshTile16Blockset();
334 void ForceRefreshGraphics(int map_index);
335 void RefreshSiblingMapGraphics(int map_index, bool include_self = false);
336
337 // ===========================================================================
338 // Tile Editing System
339 // ===========================================================================
340 // Handles tile painting and selection on the main canvas.
341
342 void RenderUpdatedMapBitmap(const ImVec2& click_position,
343 const std::vector<uint8_t>& tile_data);
344
347
350
352 absl::Status CheckForCurrentMap();
353
354 void CheckForMousePan();
357
360
361 // ===========================================================================
362 // Texture and Graphics Loading
363 // ===========================================================================
364
365 absl::Status LoadSpriteGraphics();
366
369
371 void EnsureMapTexture(int map_index);
372
373 // ===========================================================================
374 // Canvas Navigation
375 // ===========================================================================
376
377 void HandleOverworldPan();
378 void HandleOverworldZoom(); // No-op, use ZoomIn/ZoomOut instead
379 void ZoomIn();
380 void ZoomOut();
381 void ClampOverworldScroll(); // Re-clamp scroll to valid bounds
382 void ResetOverworldView();
383 void CenterOverworldView();
384
385 // ===========================================================================
386 // Canvas Automation API
387 // ===========================================================================
388 // Integration with automation testing system.
389
392 bool AutomationSetTile(int x, int y, int tile_id);
393 int AutomationGetTile(int x, int y);
394
395 // ===========================================================================
396 // Scratch Space System
397 // ===========================================================================
398 // Workspace for planning tile layouts before placing them on the map.
399
400 absl::Status SaveCurrentSelectionToScratch();
401 absl::Status LoadScratchToSelection();
402 absl::Status ClearScratchSpace();
406 void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id);
407
408 // ===========================================================================
409 // Background Map Pre-loading
410 // ===========================================================================
411 // Optimization to load adjacent maps before they're needed.
412
414 void QueueAdjacentMapsForPreload(int center_map);
415
417 void ProcessPreloadQueue();
418
419 // ===========================================================================
420 // Undo/Redo System
421 // ===========================================================================
422 // Tracks tile paint operations for undo/redo functionality.
423 // Operations within 500ms are batched to reduce undo point count.
424
426 int map_id = 0;
427 int world = 0; // 0=Light, 1=Dark, 2=Special
428 std::vector<std::pair<std::pair<int, int>, int>>
429 tile_changes; // ((x,y), old_tile_id)
430 std::chrono::steady_clock::time_point timestamp;
431 };
432
433 void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id);
435 void ApplyUndoPoint(const OverworldUndoPoint& point);
436 auto& GetWorldTiles(int world);
437
438 // ===========================================================================
439 // Editing Mode State
440 // ===========================================================================
441
445
451
452 // ===========================================================================
453 // Current Selection State
454 // ===========================================================================
455
456 int current_world_ = 0; // 0=Light, 1=Dark, 2=Special
457 int current_map_ = 0; // Current map index (0-159)
458 int current_parent_ = 0; // Parent map for multi-area
464 int game_state_ = 1; // 0=Beginning, 1=Pendants, 2=Crystals
465 int current_tile16_ = 0; // Selected tile16 for painting
468
469 // Selected tile IDs for rectangle selection
470 std::vector<int> selected_tile16_ids_;
471
472 // ===========================================================================
473 // Loading State
474 // ===========================================================================
475
476 bool all_gfx_loaded_ = false;
478
479 // ===========================================================================
480 // Canvas Interaction State
481 // ===========================================================================
482
486 bool current_map_lock_ = false;
487
488 // ===========================================================================
489 // Property Windows (Standalone, Not PanelManager)
490 // ===========================================================================
491
496
497 // ===========================================================================
498 // Performance Optimization State
499 // ===========================================================================
500
501 // Hover optimization - debounce map building during rapid hover
503 float hover_time_ = 0.0f;
504 static constexpr float kHoverBuildDelay = 0.15f;
505
506 // Background pre-loading for adjacent maps
507 std::vector<int> preload_queue_;
508 static constexpr float kPreloadStartDelay = 0.3f;
509
510 // ===========================================================================
511 // UI Subsystem Components
512 // ===========================================================================
513
514 std::unique_ptr<MapPropertiesSystem> map_properties_system_;
515 std::unique_ptr<OverworldSidebar> sidebar_;
516 std::unique_ptr<OverworldEntityRenderer> entity_renderer_;
517 std::unique_ptr<OverworldToolbar> toolbar_;
518
519 // ===========================================================================
520 // Scratch Space System (Unified Single Workspace)
521 // ===========================================================================
522
525 std::array<std::array<int, 32>, 32> tile_data{};
526 bool in_use = false;
527 std::string name = "Scratch Space";
528 int width = 16;
529 int height = 16;
530 std::vector<ImVec2> selected_tiles;
531 std::vector<ImVec2> selected_points;
532 bool select_rect_active = false;
533 };
535
536 // ===========================================================================
537 // Core Data References
538 // ===========================================================================
539
541
545
546 // Sub-editors
550
551 // ===========================================================================
552 // Graphics Data
553 // ===========================================================================
554
560 std::array<gfx::Bitmap, zelda3::kNumOverworldMaps> maps_bmp_;
562 std::vector<gfx::Bitmap> sprite_previews_;
563
564 // ===========================================================================
565 // Overworld Data Layer
566 // ===========================================================================
567
570
571 // ===========================================================================
572 // Entity State
573 // ===========================================================================
574
580
583
584 // Deferred entity insertion (needed for popup flow from context menu)
588
589 // ===========================================================================
590 // Canvas Components
591 // ===========================================================================
592
599 std::unique_ptr<gui::TileSelectorWidget> blockset_selector_;
603 gui::Canvas scratch_canvas_{"ScratchSpace", ImVec2(320, 480),
605
606 // ===========================================================================
607 // Panel Cards
608 // ===========================================================================
609
610 std::unique_ptr<UsageStatisticsCard> usage_stats_card_;
611 std::unique_ptr<DebugWindowCard> debug_window_card_;
612
613 absl::Status status_;
614
615 // ===========================================================================
616 // Undo/Redo State
617 // ===========================================================================
618
619 std::vector<OverworldUndoPoint> undo_stack_;
620 std::vector<OverworldUndoPoint> redo_stack_;
621 std::optional<OverworldUndoPoint> current_paint_operation_;
622 std::chrono::steady_clock::time_point last_paint_time_;
623 static constexpr size_t kMaxUndoHistory = 50;
624 static constexpr auto kPaintBatchTimeout = std::chrono::milliseconds(500);
625
626 // ===========================================================================
627 // Event Listeners
628 // ===========================================================================
629
631};
632} // namespace editor
633} // namespace yaze
634
635#endif
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
bool is_loaded() const
Definition rom.h:128
auto title() const
Definition rom.h:133
Interface for editor classes.
Definition editor.h:179
zelda3::GameData * game_data() const
Definition editor.h:228
EditorDependencies dependencies_
Definition editor.h:237
EditorType type_
Definition editor.h:236
Manage graphics group configurations in a Rom.
void SetGameData(zelda3::GameData *data)
Main UI class for editing overworld maps in A Link to the Past.
std::unique_ptr< UsageStatisticsCard > usage_stats_card_
absl::Status Clear() override
std::unique_ptr< MapPropertiesSystem > map_properties_system_
zelda3::OverworldItem current_item_
void HandleEntityInteraction()
Handle entity interaction in MOUSE mode Includes: right-click context menus, double-click navigation,...
static constexpr float kHoverBuildDelay
zelda3::OverworldEntranceTileTypes entrance_tiletypes_
zelda3::OverworldEntrance current_entrance_
void HandleTile16Edit()
Handle tile16 editing from context menu (MOUSE mode) Gets the tile16 under the cursor and opens the T...
absl::Status ApplyZSCustomOverworldASM(int target_version)
Apply ZSCustomOverworld ASM patch to upgrade ROM version.
std::optional< OverworldUndoPoint > current_paint_operation_
absl::Status CheckForCurrentMap()
Check for map changes and refresh if needed.
void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id)
absl::Status Cut() override
void ForceRefreshGraphics(int map_index)
std::vector< int > selected_tile16_ids_
void ProcessPendingEntityInsertion()
Process any pending entity insertion request Called from Update() - needed because ImGui::OpenPopup()...
Definition automation.cc:88
std::vector< OverworldUndoPoint > undo_stack_
zelda3::OverworldBlockset refresh_blockset_
void HandleEntityInsertion(const std::string &entity_type)
Handle entity insertion from context menu.
Definition automation.cc:75
zelda3::GameEntity * dragged_entity_
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > maps_bmp_
void CheckForOverworldEdits()
Check for tile edits - handles painting and selection.
absl::Status UpdateROMVersionMarkers(int target_version)
Update ROM version markers and feature flags after ASM patching.
void ProcessPreloadQueue()
Process one map from the preload queue (called each frame)
void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id)
zelda3::OverworldExit current_exit_
UsageStatisticsCard * usage_stats_card()
Access usage statistics card for panel.
void SetGameData(zelda3::GameData *game_data) override
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
std::vector< OverworldUndoPoint > redo_stack_
void RenderUpdatedMapBitmap(const ImVec2 &click_position, const std::vector< uint8_t > &tile_data)
void set_current_map(int map_id)
Set the current map for editing (also updates world)
void RefreshOverworldMapOnDemand(int map_index)
On-demand map refresh that only updates what's actually needed.
std::unique_ptr< OverworldSidebar > sidebar_
static constexpr float kPreloadStartDelay
std::chrono::steady_clock::time_point last_paint_time_
void InvalidateGraphicsCache(int map_id=-1)
Invalidate cached graphics for a specific map or all maps.
DebugWindowCard * debug_window_card()
Access debug window card for panel.
void HandleEntityDoubleClick(zelda3::GameEntity *hovered_entity)
Handle double-click actions on entities (e.g., jump to room)
void HandleEntityContextMenus(zelda3::GameEntity *hovered_entity)
Handle right-click context menus for entities.
absl::Status SaveCurrentSelectionToScratch()
bool AutomationSetTile(int x, int y, int tile_id)
Definition automation.cc:29
void RefreshMultiAreaMapsSafely(int map_index, zelda3::OverworldMap *map)
Safely refresh multi-area maps without recursion.
void DrawOverworldCanvas()
Draw the main overworld canvas.
zelda3::Overworld & overworld()
Access the underlying Overworld data.
void CheckForSelectRectangle()
Draw and create the tile16 IDs that are currently selected.
std::unique_ptr< OverworldEntityRenderer > entity_renderer_
absl::Status Load() override
void EnsureMapTexture(int map_index)
Ensure a specific map has its texture created.
std::vector< gfx::Bitmap > sprite_previews_
OverworldEditor(Rom *rom, const EditorDependencies &deps)
std::string GetRomStatus() const override
std::unique_ptr< OverworldToolbar > toolbar_
bool IsRomLoaded() const override
Tile16Editor & tile16_editor()
Access the Tile16 Editor for panel integration.
void ProcessDeferredTextures()
Create textures for deferred map bitmaps on demand.
std::unique_ptr< gui::TileSelectorWidget > blockset_selector_
void DrawEntityEditorPopups()
Draw entity editor popups and update entity data.
absl::Status Paste() override
void ScrollBlocksetCanvasToCurrentTile()
Scroll the blockset canvas to show the current selected tile16.
static constexpr auto kPaintBatchTimeout
static constexpr size_t kMaxUndoHistory
absl::Status LoadGraphics()
Load the Bitmap objects for each OverworldMap.
void RefreshChildMapOnDemand(int map_index)
On-demand child map refresh with selective updates.
absl::Status Find() override
std::unique_ptr< DebugWindowCard > debug_window_card_
void ApplyUndoPoint(const OverworldUndoPoint &point)
zelda3::GameEntity * current_entity_
void HandleKeyboardShortcuts()
Handle keyboard shortcuts for the Overworld Editor Shortcuts: 1-2 (modes), 3-8 (entities),...
int AutomationGetTile(int x, int y)
Definition automation.cc:58
void QueueAdjacentMapsForPreload(int center_map)
Queue adjacent maps for background pre-loading.
Allows the user to view and edit in game palettes.
Popup window to edit Tile16 data.
void SetGameData(zelda3::GameData *game_data)
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
Shared graphical context across editors.
Defines an abstract interface for all rendering operations.
Definition irenderer.h:40
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:150
Base class for all overworld and dungeon entities.
Definition common.h:31
Represents an overworld exit that transitions from dungeon to overworld.
Represents a single Overworld map screen.
Represents the full Overworld data, light and dark world.
Definition overworld.h:217
void set_current_world(int world)
Definition overworld.h:535
void SetGameData(GameData *game_data)
Definition overworld.h:222
void set_current_map(int i)
Definition overworld.h:534
A class for managing sprites in the overworld and underworld.
Definition sprite.h:35
constexpr ImVec2 kOverworldCanvasSize(kOverworldMapSize *8, kOverworldMapSize *8)
constexpr absl::string_view kOWMapTable
constexpr ImGuiTableFlags kOWMapFlags
constexpr unsigned int kOverworldMapSize
constexpr float kOverworldMaxZoom
constexpr absl::string_view kWorldList
constexpr absl::string_view kGamePartComboString
constexpr float kOverworldMinZoom
constexpr unsigned int kNumSheetsToLoad
constexpr ImVec2 kCurrentGfxCanvasSize(0x100+1, 0x10 *0x40+1)
constexpr ImVec2 kBlocksetCanvasSize(0x100+1, 0x4000+1)
constexpr ImVec2 kGraphicsBinCanvasSize(0x100+1, kNumSheetsToLoad *0x40+1)
constexpr unsigned int kByteSize
constexpr float kOverworldZoomStep
constexpr unsigned int k4BPP
constexpr unsigned int kMessageIdSize
std::unordered_map< int, std::unique_ptr< gfx::Bitmap > > BitmapTable
Definition bitmap.h:497
constexpr int kNumOverworldMaps
Definition common.h:85
std::vector< std::vector< uint16_t > > OverworldBlockset
Represents tile32 data for the overworld.
Unified dependency container for all editor types.
Definition editor.h:111
std::vector< std::pair< std::pair< int, int >, int > > tile_changes
std::chrono::steady_clock::time_point timestamp
std::array< std::array< int, 32 >, 32 > tile_data
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118