|
|
|
|
@@ -1,382 +1,382 @@
|
|
|
|
|
#ifndef YAZE_APP_EDITOR_OVERWORLDEDITOR_H
|
|
|
|
|
#define YAZE_APP_EDITOR_OVERWORLDEDITOR_H
|
|
|
|
|
|
|
|
|
|
#include "absl/status/status.h"
|
|
|
|
|
#include "app/editor/editor.h"
|
|
|
|
|
#include "app/editor/graphics/gfx_group_editor.h"
|
|
|
|
|
#include "app/editor/palette/palette_editor.h"
|
|
|
|
|
#include "app/gui/editor_card_manager.h"
|
|
|
|
|
#include "app/editor/overworld/tile16_editor.h"
|
|
|
|
|
#include "app/editor/overworld/map_properties.h"
|
|
|
|
|
#include "app/editor/overworld/overworld_entity_renderer.h"
|
|
|
|
|
#include "app/gfx/bitmap.h"
|
|
|
|
|
#include "app/gfx/snes_palette.h"
|
|
|
|
|
#include "app/gfx/tilemap.h"
|
|
|
|
|
#include "app/gui/canvas.h"
|
|
|
|
|
#include "app/gui/widgets/tile_selector_widget.h"
|
|
|
|
|
#include "app/gui/input.h"
|
|
|
|
|
#include "app/rom.h"
|
|
|
|
|
#include "app/zelda3/overworld/overworld.h"
|
|
|
|
|
#include "imgui/imgui.h"
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
|
|
namespace yaze {
|
|
|
|
|
namespace editor {
|
|
|
|
|
|
|
|
|
|
constexpr unsigned int k4BPP = 4;
|
|
|
|
|
constexpr unsigned int kByteSize = 3;
|
|
|
|
|
constexpr unsigned int kMessageIdSize = 5;
|
|
|
|
|
constexpr unsigned int kNumSheetsToLoad = 223;
|
|
|
|
|
constexpr unsigned int kOverworldMapSize = 0x200;
|
|
|
|
|
constexpr ImVec2 kOverworldCanvasSize(kOverworldMapSize * 8,
|
|
|
|
|
kOverworldMapSize * 8);
|
|
|
|
|
constexpr ImVec2 kCurrentGfxCanvasSize(0x100 + 1, 0x10 * 0x40 + 1);
|
|
|
|
|
constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1);
|
|
|
|
|
constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1);
|
|
|
|
|
|
|
|
|
|
constexpr ImGuiTableFlags kOWMapFlags =
|
|
|
|
|
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
|
|
|
|
|
ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp;
|
|
|
|
|
|
|
|
|
|
constexpr absl::string_view kWorldList =
|
|
|
|
|
"Light World\0Dark World\0Extra World\0";
|
|
|
|
|
|
|
|
|
|
constexpr absl::string_view kGamePartComboString = "Part 0\0Part 1\0Part 2\0";
|
|
|
|
|
|
|
|
|
|
constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @class OverworldEditor
|
|
|
|
|
* @brief Manipulates the Overworld and OverworldMap data in a Rom.
|
|
|
|
|
*
|
|
|
|
|
* The `OverworldEditor` class is responsible for managing the editing and
|
|
|
|
|
* manipulation of the overworld in a game. The user can drag and drop tiles,
|
|
|
|
|
* modify OverworldEntrance, OverworldExit, Sprite, and OverworldItem
|
|
|
|
|
* as well as change the gfx and palettes used in each overworld map.
|
|
|
|
|
*
|
|
|
|
|
* The Overworld itself is a series of bitmap images which exist inside each
|
|
|
|
|
* OverworldMap object. The drawing of the overworld is done using the Canvas
|
|
|
|
|
* class in conjunction with these underlying Bitmap objects.
|
|
|
|
|
*
|
|
|
|
|
* Provides access to the GfxGroupEditor and Tile16Editor through popup windows.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
class OverworldEditor : public Editor, public gfx::GfxContext {
|
|
|
|
|
public:
|
|
|
|
|
explicit OverworldEditor(Rom* rom) : rom_(rom) {
|
|
|
|
|
type_ = EditorType::kOverworld;
|
|
|
|
|
gfx_group_editor_.set_rom(rom);
|
|
|
|
|
// MapPropertiesSystem will be initialized after maps_bmp_ and canvas are ready
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Initialize(gfx::IRenderer* renderer, Rom* rom);
|
|
|
|
|
void Initialize() override;
|
|
|
|
|
absl::Status Load() override;
|
|
|
|
|
absl::Status Update() final;
|
|
|
|
|
absl::Status Undo() override { return absl::UnimplementedError("Undo"); }
|
|
|
|
|
absl::Status Redo() override { return absl::UnimplementedError("Redo"); }
|
|
|
|
|
absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
|
|
|
|
|
absl::Status Copy() override;
|
|
|
|
|
absl::Status Paste() override;
|
|
|
|
|
absl::Status Find() override { return absl::UnimplementedError("Find"); }
|
|
|
|
|
absl::Status Save() override;
|
|
|
|
|
absl::Status Clear() override;
|
|
|
|
|
zelda3::Overworld& overworld() { return overworld_; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Apply ZSCustomOverworld ASM patch to upgrade ROM version
|
|
|
|
|
*/
|
|
|
|
|
absl::Status ApplyZSCustomOverworldASM(int target_version);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Update ROM version markers and feature flags after ASM patching
|
|
|
|
|
*/
|
|
|
|
|
absl::Status UpdateROMVersionMarkers(int target_version);
|
|
|
|
|
|
|
|
|
|
int jump_to_tab() { return jump_to_tab_; }
|
|
|
|
|
int jump_to_tab_ = -1;
|
|
|
|
|
|
|
|
|
|
// ROM state methods (from Editor base class)
|
|
|
|
|
bool IsRomLoaded() const override { return rom_ && rom_->is_loaded(); }
|
|
|
|
|
std::string GetRomStatus() const override {
|
|
|
|
|
if (!rom_) return "No ROM loaded";
|
|
|
|
|
if (!rom_->is_loaded()) return "ROM failed to load";
|
|
|
|
|
return absl::StrFormat("ROM loaded: %s", rom_->title());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Jump-to functionality
|
|
|
|
|
void set_current_map(int map_id) {
|
|
|
|
|
if (map_id >= 0 && map_id < zelda3::kNumOverworldMaps) {
|
|
|
|
|
current_map_ = map_id;
|
|
|
|
|
current_world_ = map_id / 0x40; // Calculate which world the map belongs to
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Load the Bitmap objects for each OverworldMap.
|
|
|
|
|
*
|
|
|
|
|
* Calls the Overworld class to load the image data and palettes from the Rom,
|
|
|
|
|
* then renders the area graphics and tile16 blockset Bitmap objects before
|
|
|
|
|
* assembling the OverworldMap Bitmap objects.
|
|
|
|
|
*/
|
|
|
|
|
absl::Status LoadGraphics();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void DrawFullscreenCanvas();
|
|
|
|
|
void DrawToolset();
|
|
|
|
|
|
|
|
|
|
void RefreshChildMap(int map_index);
|
|
|
|
|
void RefreshOverworldMap();
|
|
|
|
|
void RefreshOverworldMapOnDemand(int map_index);
|
|
|
|
|
void RefreshChildMapOnDemand(int map_index);
|
|
|
|
|
void RefreshMultiAreaMapsSafely(int map_index, zelda3::OverworldMap* map);
|
|
|
|
|
absl::Status RefreshMapPalette();
|
|
|
|
|
void RefreshMapProperties();
|
|
|
|
|
absl::Status RefreshTile16Blockset();
|
|
|
|
|
void ForceRefreshGraphics(int map_index);
|
|
|
|
|
void RefreshSiblingMapGraphics(int map_index, bool include_self = false);
|
|
|
|
|
|
|
|
|
|
void DrawOverworldMaps();
|
|
|
|
|
void DrawOverworldEdits();
|
|
|
|
|
void RenderUpdatedMapBitmap(const ImVec2& click_position,
|
|
|
|
|
const std::vector<uint8_t>& tile_data);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Check for changes to the overworld map.
|
|
|
|
|
*
|
|
|
|
|
* This function either draws the tile painter with the current tile16 or
|
|
|
|
|
* group of tile16 data with ow_map_canvas_ and DrawOverworldEdits or it
|
|
|
|
|
* checks for left mouse button click/drag to select a tile16 or group of
|
|
|
|
|
* tile16 data from the overworld map canvas. Similar to ZScream selection.
|
|
|
|
|
*/
|
|
|
|
|
void CheckForOverworldEdits();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Draw and create the tile16 IDs that are currently selected.
|
|
|
|
|
*/
|
|
|
|
|
void CheckForSelectRectangle();
|
|
|
|
|
|
|
|
|
|
// Selected tile IDs for rectangle operations (moved from local static)
|
|
|
|
|
std::vector<int> selected_tile16_ids_;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Check for changes to the overworld map. Calls RefreshOverworldMap
|
|
|
|
|
* and RefreshTile16Blockset on the current map if it is modified and is
|
|
|
|
|
* actively being edited.
|
|
|
|
|
*/
|
|
|
|
|
absl::Status CheckForCurrentMap();
|
|
|
|
|
void CheckForMousePan();
|
|
|
|
|
void DrawOverworldCanvas();
|
|
|
|
|
|
|
|
|
|
absl::Status DrawTile16Selector();
|
|
|
|
|
void DrawTile8Selector();
|
|
|
|
|
absl::Status DrawAreaGraphics();
|
|
|
|
|
void UpdateBlocksetSelectorState();
|
|
|
|
|
|
|
|
|
|
absl::Status LoadSpriteGraphics();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Create textures for deferred map bitmaps on demand
|
|
|
|
|
*
|
|
|
|
|
* This method should be called periodically to create textures for maps
|
|
|
|
|
* that are needed but haven't had their textures created yet. This allows
|
|
|
|
|
* for smooth loading without blocking the main thread during ROM loading.
|
|
|
|
|
*/
|
|
|
|
|
void ProcessDeferredTextures();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Ensure a specific map has its texture created
|
|
|
|
|
*
|
|
|
|
|
* Call this when a map becomes visible or is about to be rendered.
|
|
|
|
|
* It will create the texture if it doesn't exist yet.
|
|
|
|
|
*/
|
|
|
|
|
void EnsureMapTexture(int map_index);
|
|
|
|
|
|
|
|
|
|
void DrawOverworldProperties();
|
|
|
|
|
void HandleMapInteraction();
|
|
|
|
|
// SetupOverworldCanvasContextMenu removed (Phase 3B) - now handled by MapPropertiesSystem
|
|
|
|
|
|
|
|
|
|
// Canvas pan/zoom helpers (Overworld Refactoring)
|
|
|
|
|
void HandleOverworldPan();
|
|
|
|
|
void HandleOverworldZoom();
|
|
|
|
|
void ResetOverworldView();
|
|
|
|
|
void CenterOverworldView();
|
|
|
|
|
|
|
|
|
|
// Canvas Automation API integration (Phase 4)
|
|
|
|
|
void SetupCanvasAutomation();
|
|
|
|
|
gui::Canvas* GetOverworldCanvas() { return &ow_map_canvas_; }
|
|
|
|
|
|
|
|
|
|
// Tile operations for automation callbacks
|
|
|
|
|
bool AutomationSetTile(int x, int y, int tile_id);
|
|
|
|
|
int AutomationGetTile(int x, int y);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Scroll the blockset canvas to show the current selected tile16
|
|
|
|
|
*/
|
|
|
|
|
void ScrollBlocksetCanvasToCurrentTile();
|
|
|
|
|
|
|
|
|
|
// Scratch space canvas methods
|
|
|
|
|
absl::Status DrawScratchSpace();
|
|
|
|
|
absl::Status SaveCurrentSelectionToScratch(int slot);
|
|
|
|
|
absl::Status LoadScratchToSelection(int slot);
|
|
|
|
|
absl::Status ClearScratchSpace(int slot);
|
|
|
|
|
void DrawScratchSpaceEdits();
|
|
|
|
|
void DrawScratchSpacePattern();
|
|
|
|
|
void DrawScratchSpaceSelection();
|
|
|
|
|
void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id, int slot = -1);
|
|
|
|
|
|
|
|
|
|
absl::Status UpdateUsageStats();
|
|
|
|
|
void DrawUsageGrid();
|
|
|
|
|
void DrawDebugWindow();
|
|
|
|
|
|
|
|
|
|
enum class EditingMode {
|
|
|
|
|
MOUSE, // Navigation, selection, entity management via context menu
|
|
|
|
|
DRAW_TILE // Tile painting mode
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EditingMode current_mode = EditingMode::DRAW_TILE;
|
|
|
|
|
EditingMode previous_mode = EditingMode::DRAW_TILE;
|
|
|
|
|
|
|
|
|
|
// Entity editing state (managed via context menu now)
|
|
|
|
|
enum class EntityEditMode {
|
|
|
|
|
NONE,
|
|
|
|
|
ENTRANCES,
|
|
|
|
|
EXITS,
|
|
|
|
|
ITEMS,
|
|
|
|
|
SPRITES,
|
|
|
|
|
TRANSPORTS,
|
|
|
|
|
MUSIC
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EntityEditMode entity_edit_mode_ = EntityEditMode::NONE;
|
|
|
|
|
|
|
|
|
|
enum OverworldProperty {
|
|
|
|
|
LW_AREA_GFX,
|
|
|
|
|
DW_AREA_GFX,
|
|
|
|
|
LW_AREA_PAL,
|
|
|
|
|
DW_AREA_PAL,
|
|
|
|
|
LW_SPR_GFX_PART1,
|
|
|
|
|
LW_SPR_GFX_PART2,
|
|
|
|
|
DW_SPR_GFX_PART1,
|
|
|
|
|
DW_SPR_GFX_PART2,
|
|
|
|
|
LW_SPR_PAL_PART1,
|
|
|
|
|
LW_SPR_PAL_PART2,
|
|
|
|
|
DW_SPR_PAL_PART1,
|
|
|
|
|
DW_SPR_PAL_PART2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int current_world_ = 0;
|
|
|
|
|
int current_map_ = 0;
|
|
|
|
|
int current_parent_ = 0;
|
|
|
|
|
int current_entrance_id_ = 0;
|
|
|
|
|
int current_exit_id_ = 0;
|
|
|
|
|
int current_item_id_ = 0;
|
|
|
|
|
int current_sprite_id_ = 0;
|
|
|
|
|
int current_blockset_ = 0;
|
|
|
|
|
int game_state_ = 1;
|
|
|
|
|
int current_tile16_ = 0;
|
|
|
|
|
int selected_entrance_ = 0;
|
|
|
|
|
int selected_usage_map_ = 0xFFFF;
|
|
|
|
|
|
|
|
|
|
bool all_gfx_loaded_ = false;
|
|
|
|
|
bool map_blockset_loaded_ = false;
|
|
|
|
|
bool selected_tile_loaded_ = false;
|
|
|
|
|
bool show_tile16_editor_ = false;
|
|
|
|
|
bool show_gfx_group_editor_ = false;
|
|
|
|
|
bool show_properties_editor_ = false;
|
|
|
|
|
bool overworld_canvas_fullscreen_ = false;
|
|
|
|
|
bool middle_mouse_dragging_ = false;
|
|
|
|
|
bool is_dragging_entity_ = false;
|
|
|
|
|
bool dragged_entity_free_movement_ = false;
|
|
|
|
|
bool current_map_lock_ = false;
|
|
|
|
|
bool show_custom_bg_color_editor_ = false;
|
|
|
|
|
bool show_overlay_editor_ = false;
|
|
|
|
|
bool use_area_specific_bg_color_ = false;
|
|
|
|
|
bool show_map_properties_panel_ = false;
|
|
|
|
|
bool show_overlay_preview_ = false;
|
|
|
|
|
|
|
|
|
|
// Card visibility states - Start hidden to prevent crash
|
|
|
|
|
bool show_overworld_canvas_ = true;
|
|
|
|
|
bool show_tile16_selector_ = false;
|
|
|
|
|
bool show_tile8_selector_ = false;
|
|
|
|
|
bool show_area_gfx_ = false;
|
|
|
|
|
bool show_scratch_ = false;
|
|
|
|
|
bool show_gfx_groups_ = false;
|
|
|
|
|
bool show_usage_stats_ = false;
|
|
|
|
|
bool show_v3_settings_ = false;
|
|
|
|
|
|
|
|
|
|
// Map properties system for UI organization
|
|
|
|
|
std::unique_ptr<MapPropertiesSystem> map_properties_system_;
|
|
|
|
|
std::unique_ptr<OverworldEntityRenderer> entity_renderer_;
|
|
|
|
|
|
|
|
|
|
// Scratch space for large layouts
|
|
|
|
|
// Scratch space canvas for tile16 drawing (like a mini overworld)
|
|
|
|
|
struct ScratchSpaceSlot {
|
|
|
|
|
gfx::Bitmap scratch_bitmap;
|
|
|
|
|
std::array<std::array<int, 32>, 32> tile_data; // 32x32 grid of tile16 IDs
|
|
|
|
|
bool in_use = false;
|
|
|
|
|
std::string name = "Empty";
|
|
|
|
|
int width = 16; // Default 16x16 tiles
|
|
|
|
|
int height = 16;
|
|
|
|
|
// Independent selection system for scratch space
|
|
|
|
|
std::vector<ImVec2> selected_tiles;
|
|
|
|
|
std::vector<ImVec2> selected_points;
|
|
|
|
|
bool select_rect_active = false;
|
|
|
|
|
};
|
|
|
|
|
std::array<ScratchSpaceSlot, 4> scratch_spaces_;
|
|
|
|
|
int current_scratch_slot_ = 0;
|
|
|
|
|
|
|
|
|
|
gfx::Tilemap tile16_blockset_;
|
|
|
|
|
|
|
|
|
|
Rom* rom_;
|
|
|
|
|
|
|
|
|
|
gfx::IRenderer* renderer_;
|
|
|
|
|
Tile16Editor tile16_editor_{rom_, &tile16_blockset_};
|
|
|
|
|
GfxGroupEditor gfx_group_editor_;
|
|
|
|
|
PaletteEditor palette_editor_;
|
|
|
|
|
|
|
|
|
|
gfx::SnesPalette palette_;
|
|
|
|
|
|
|
|
|
|
gfx::Bitmap selected_tile_bmp_;
|
|
|
|
|
gfx::Bitmap tile16_blockset_bmp_;
|
|
|
|
|
gfx::Bitmap current_gfx_bmp_;
|
|
|
|
|
gfx::Bitmap all_gfx_bmp;
|
|
|
|
|
|
|
|
|
|
std::array<gfx::Bitmap, zelda3::kNumOverworldMaps> maps_bmp_;
|
|
|
|
|
gfx::BitmapTable current_graphics_set_;
|
|
|
|
|
std::vector<gfx::Bitmap> sprite_previews_;
|
|
|
|
|
|
|
|
|
|
// Deferred texture creation for performance optimization
|
|
|
|
|
// Deferred texture management now handled by gfx::Arena::Get()
|
|
|
|
|
|
|
|
|
|
zelda3::Overworld overworld_{rom_};
|
|
|
|
|
zelda3::OverworldBlockset refresh_blockset_;
|
|
|
|
|
|
|
|
|
|
zelda3::Sprite current_sprite_;
|
|
|
|
|
|
|
|
|
|
zelda3::OverworldEntrance current_entrance_;
|
|
|
|
|
zelda3::OverworldExit current_exit_;
|
|
|
|
|
zelda3::OverworldItem current_item_;
|
|
|
|
|
zelda3::OverworldEntranceTileTypes entrance_tiletypes_ = {};
|
|
|
|
|
|
|
|
|
|
zelda3::GameEntity* current_entity_ = nullptr;
|
|
|
|
|
zelda3::GameEntity* dragged_entity_ = nullptr;
|
|
|
|
|
|
|
|
|
|
gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k64x64};
|
|
|
|
|
gui::Canvas current_gfx_canvas_{"CurrentGfx", kCurrentGfxCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k32x32};
|
|
|
|
|
gui::Canvas blockset_canvas_{"OwBlockset", kBlocksetCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k32x32};
|
|
|
|
|
std::unique_ptr<gui::TileSelectorWidget> blockset_selector_;
|
|
|
|
|
gui::Canvas graphics_bin_canvas_{"GraphicsBin", kGraphicsBinCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k16x16};
|
|
|
|
|
gui::Canvas properties_canvas_;
|
|
|
|
|
gui::Canvas scratch_canvas_{"ScratchSpace", ImVec2(320, 480), gui::CanvasGridSize::k32x32};
|
|
|
|
|
|
|
|
|
|
absl::Status status_;
|
|
|
|
|
};
|
|
|
|
|
} // namespace editor
|
|
|
|
|
} // namespace yaze
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef YAZE_APP_EDITOR_OVERWORLDEDITOR_H
|
|
|
|
|
#define YAZE_APP_EDITOR_OVERWORLDEDITOR_H
|
|
|
|
|
|
|
|
|
|
#include "absl/status/status.h"
|
|
|
|
|
#include "app/editor/editor.h"
|
|
|
|
|
#include "app/editor/graphics/gfx_group_editor.h"
|
|
|
|
|
#include "app/editor/palette/palette_editor.h"
|
|
|
|
|
#include "app/gui/editor_card_manager.h"
|
|
|
|
|
#include "app/editor/overworld/tile16_editor.h"
|
|
|
|
|
#include "app/editor/overworld/map_properties.h"
|
|
|
|
|
#include "app/editor/overworld/overworld_entity_renderer.h"
|
|
|
|
|
#include "app/gfx/bitmap.h"
|
|
|
|
|
#include "app/gfx/snes_palette.h"
|
|
|
|
|
#include "app/gfx/tilemap.h"
|
|
|
|
|
#include "app/gui/canvas.h"
|
|
|
|
|
#include "app/gui/widgets/tile_selector_widget.h"
|
|
|
|
|
#include "app/gui/input.h"
|
|
|
|
|
#include "app/rom.h"
|
|
|
|
|
#include "zelda3/overworld/overworld.h"
|
|
|
|
|
#include "imgui/imgui.h"
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
|
|
namespace yaze {
|
|
|
|
|
namespace editor {
|
|
|
|
|
|
|
|
|
|
constexpr unsigned int k4BPP = 4;
|
|
|
|
|
constexpr unsigned int kByteSize = 3;
|
|
|
|
|
constexpr unsigned int kMessageIdSize = 5;
|
|
|
|
|
constexpr unsigned int kNumSheetsToLoad = 223;
|
|
|
|
|
constexpr unsigned int kOverworldMapSize = 0x200;
|
|
|
|
|
constexpr ImVec2 kOverworldCanvasSize(kOverworldMapSize * 8,
|
|
|
|
|
kOverworldMapSize * 8);
|
|
|
|
|
constexpr ImVec2 kCurrentGfxCanvasSize(0x100 + 1, 0x10 * 0x40 + 1);
|
|
|
|
|
constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1);
|
|
|
|
|
constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1);
|
|
|
|
|
|
|
|
|
|
constexpr ImGuiTableFlags kOWMapFlags =
|
|
|
|
|
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
|
|
|
|
|
ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp;
|
|
|
|
|
|
|
|
|
|
constexpr absl::string_view kWorldList =
|
|
|
|
|
"Light World\0Dark World\0Extra World\0";
|
|
|
|
|
|
|
|
|
|
constexpr absl::string_view kGamePartComboString = "Part 0\0Part 1\0Part 2\0";
|
|
|
|
|
|
|
|
|
|
constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @class OverworldEditor
|
|
|
|
|
* @brief Manipulates the Overworld and OverworldMap data in a Rom.
|
|
|
|
|
*
|
|
|
|
|
* The `OverworldEditor` class is responsible for managing the editing and
|
|
|
|
|
* manipulation of the overworld in a game. The user can drag and drop tiles,
|
|
|
|
|
* modify OverworldEntrance, OverworldExit, Sprite, and OverworldItem
|
|
|
|
|
* as well as change the gfx and palettes used in each overworld map.
|
|
|
|
|
*
|
|
|
|
|
* The Overworld itself is a series of bitmap images which exist inside each
|
|
|
|
|
* OverworldMap object. The drawing of the overworld is done using the Canvas
|
|
|
|
|
* class in conjunction with these underlying Bitmap objects.
|
|
|
|
|
*
|
|
|
|
|
* Provides access to the GfxGroupEditor and Tile16Editor through popup windows.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
class OverworldEditor : public Editor, public gfx::GfxContext {
|
|
|
|
|
public:
|
|
|
|
|
explicit OverworldEditor(Rom* rom) : rom_(rom) {
|
|
|
|
|
type_ = EditorType::kOverworld;
|
|
|
|
|
gfx_group_editor_.set_rom(rom);
|
|
|
|
|
// MapPropertiesSystem will be initialized after maps_bmp_ and canvas are ready
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Initialize(gfx::IRenderer* renderer, Rom* rom);
|
|
|
|
|
void Initialize() override;
|
|
|
|
|
absl::Status Load() override;
|
|
|
|
|
absl::Status Update() final;
|
|
|
|
|
absl::Status Undo() override { return absl::UnimplementedError("Undo"); }
|
|
|
|
|
absl::Status Redo() override { return absl::UnimplementedError("Redo"); }
|
|
|
|
|
absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
|
|
|
|
|
absl::Status Copy() override;
|
|
|
|
|
absl::Status Paste() override;
|
|
|
|
|
absl::Status Find() override { return absl::UnimplementedError("Find"); }
|
|
|
|
|
absl::Status Save() override;
|
|
|
|
|
absl::Status Clear() override;
|
|
|
|
|
zelda3::Overworld& overworld() { return overworld_; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Apply ZSCustomOverworld ASM patch to upgrade ROM version
|
|
|
|
|
*/
|
|
|
|
|
absl::Status ApplyZSCustomOverworldASM(int target_version);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Update ROM version markers and feature flags after ASM patching
|
|
|
|
|
*/
|
|
|
|
|
absl::Status UpdateROMVersionMarkers(int target_version);
|
|
|
|
|
|
|
|
|
|
int jump_to_tab() { return jump_to_tab_; }
|
|
|
|
|
int jump_to_tab_ = -1;
|
|
|
|
|
|
|
|
|
|
// ROM state methods (from Editor base class)
|
|
|
|
|
bool IsRomLoaded() const override { return rom_ && rom_->is_loaded(); }
|
|
|
|
|
std::string GetRomStatus() const override {
|
|
|
|
|
if (!rom_) return "No ROM loaded";
|
|
|
|
|
if (!rom_->is_loaded()) return "ROM failed to load";
|
|
|
|
|
return absl::StrFormat("ROM loaded: %s", rom_->title());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Jump-to functionality
|
|
|
|
|
void set_current_map(int map_id) {
|
|
|
|
|
if (map_id >= 0 && map_id < zelda3::kNumOverworldMaps) {
|
|
|
|
|
current_map_ = map_id;
|
|
|
|
|
current_world_ = map_id / 0x40; // Calculate which world the map belongs to
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Load the Bitmap objects for each OverworldMap.
|
|
|
|
|
*
|
|
|
|
|
* Calls the Overworld class to load the image data and palettes from the Rom,
|
|
|
|
|
* then renders the area graphics and tile16 blockset Bitmap objects before
|
|
|
|
|
* assembling the OverworldMap Bitmap objects.
|
|
|
|
|
*/
|
|
|
|
|
absl::Status LoadGraphics();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void DrawFullscreenCanvas();
|
|
|
|
|
void DrawToolset();
|
|
|
|
|
|
|
|
|
|
void RefreshChildMap(int map_index);
|
|
|
|
|
void RefreshOverworldMap();
|
|
|
|
|
void RefreshOverworldMapOnDemand(int map_index);
|
|
|
|
|
void RefreshChildMapOnDemand(int map_index);
|
|
|
|
|
void RefreshMultiAreaMapsSafely(int map_index, zelda3::OverworldMap* map);
|
|
|
|
|
absl::Status RefreshMapPalette();
|
|
|
|
|
void RefreshMapProperties();
|
|
|
|
|
absl::Status RefreshTile16Blockset();
|
|
|
|
|
void ForceRefreshGraphics(int map_index);
|
|
|
|
|
void RefreshSiblingMapGraphics(int map_index, bool include_self = false);
|
|
|
|
|
|
|
|
|
|
void DrawOverworldMaps();
|
|
|
|
|
void DrawOverworldEdits();
|
|
|
|
|
void RenderUpdatedMapBitmap(const ImVec2& click_position,
|
|
|
|
|
const std::vector<uint8_t>& tile_data);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Check for changes to the overworld map.
|
|
|
|
|
*
|
|
|
|
|
* This function either draws the tile painter with the current tile16 or
|
|
|
|
|
* group of tile16 data with ow_map_canvas_ and DrawOverworldEdits or it
|
|
|
|
|
* checks for left mouse button click/drag to select a tile16 or group of
|
|
|
|
|
* tile16 data from the overworld map canvas. Similar to ZScream selection.
|
|
|
|
|
*/
|
|
|
|
|
void CheckForOverworldEdits();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Draw and create the tile16 IDs that are currently selected.
|
|
|
|
|
*/
|
|
|
|
|
void CheckForSelectRectangle();
|
|
|
|
|
|
|
|
|
|
// Selected tile IDs for rectangle operations (moved from local static)
|
|
|
|
|
std::vector<int> selected_tile16_ids_;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Check for changes to the overworld map. Calls RefreshOverworldMap
|
|
|
|
|
* and RefreshTile16Blockset on the current map if it is modified and is
|
|
|
|
|
* actively being edited.
|
|
|
|
|
*/
|
|
|
|
|
absl::Status CheckForCurrentMap();
|
|
|
|
|
void CheckForMousePan();
|
|
|
|
|
void DrawOverworldCanvas();
|
|
|
|
|
|
|
|
|
|
absl::Status DrawTile16Selector();
|
|
|
|
|
void DrawTile8Selector();
|
|
|
|
|
absl::Status DrawAreaGraphics();
|
|
|
|
|
void UpdateBlocksetSelectorState();
|
|
|
|
|
|
|
|
|
|
absl::Status LoadSpriteGraphics();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Create textures for deferred map bitmaps on demand
|
|
|
|
|
*
|
|
|
|
|
* This method should be called periodically to create textures for maps
|
|
|
|
|
* that are needed but haven't had their textures created yet. This allows
|
|
|
|
|
* for smooth loading without blocking the main thread during ROM loading.
|
|
|
|
|
*/
|
|
|
|
|
void ProcessDeferredTextures();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Ensure a specific map has its texture created
|
|
|
|
|
*
|
|
|
|
|
* Call this when a map becomes visible or is about to be rendered.
|
|
|
|
|
* It will create the texture if it doesn't exist yet.
|
|
|
|
|
*/
|
|
|
|
|
void EnsureMapTexture(int map_index);
|
|
|
|
|
|
|
|
|
|
void DrawOverworldProperties();
|
|
|
|
|
void HandleMapInteraction();
|
|
|
|
|
// SetupOverworldCanvasContextMenu removed (Phase 3B) - now handled by MapPropertiesSystem
|
|
|
|
|
|
|
|
|
|
// Canvas pan/zoom helpers (Overworld Refactoring)
|
|
|
|
|
void HandleOverworldPan();
|
|
|
|
|
void HandleOverworldZoom();
|
|
|
|
|
void ResetOverworldView();
|
|
|
|
|
void CenterOverworldView();
|
|
|
|
|
|
|
|
|
|
// Canvas Automation API integration (Phase 4)
|
|
|
|
|
void SetupCanvasAutomation();
|
|
|
|
|
gui::Canvas* GetOverworldCanvas() { return &ow_map_canvas_; }
|
|
|
|
|
|
|
|
|
|
// Tile operations for automation callbacks
|
|
|
|
|
bool AutomationSetTile(int x, int y, int tile_id);
|
|
|
|
|
int AutomationGetTile(int x, int y);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Scroll the blockset canvas to show the current selected tile16
|
|
|
|
|
*/
|
|
|
|
|
void ScrollBlocksetCanvasToCurrentTile();
|
|
|
|
|
|
|
|
|
|
// Scratch space canvas methods
|
|
|
|
|
absl::Status DrawScratchSpace();
|
|
|
|
|
absl::Status SaveCurrentSelectionToScratch(int slot);
|
|
|
|
|
absl::Status LoadScratchToSelection(int slot);
|
|
|
|
|
absl::Status ClearScratchSpace(int slot);
|
|
|
|
|
void DrawScratchSpaceEdits();
|
|
|
|
|
void DrawScratchSpacePattern();
|
|
|
|
|
void DrawScratchSpaceSelection();
|
|
|
|
|
void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id, int slot = -1);
|
|
|
|
|
|
|
|
|
|
absl::Status UpdateUsageStats();
|
|
|
|
|
void DrawUsageGrid();
|
|
|
|
|
void DrawDebugWindow();
|
|
|
|
|
|
|
|
|
|
enum class EditingMode {
|
|
|
|
|
MOUSE, // Navigation, selection, entity management via context menu
|
|
|
|
|
DRAW_TILE // Tile painting mode
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EditingMode current_mode = EditingMode::DRAW_TILE;
|
|
|
|
|
EditingMode previous_mode = EditingMode::DRAW_TILE;
|
|
|
|
|
|
|
|
|
|
// Entity editing state (managed via context menu now)
|
|
|
|
|
enum class EntityEditMode {
|
|
|
|
|
NONE,
|
|
|
|
|
ENTRANCES,
|
|
|
|
|
EXITS,
|
|
|
|
|
ITEMS,
|
|
|
|
|
SPRITES,
|
|
|
|
|
TRANSPORTS,
|
|
|
|
|
MUSIC
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EntityEditMode entity_edit_mode_ = EntityEditMode::NONE;
|
|
|
|
|
|
|
|
|
|
enum OverworldProperty {
|
|
|
|
|
LW_AREA_GFX,
|
|
|
|
|
DW_AREA_GFX,
|
|
|
|
|
LW_AREA_PAL,
|
|
|
|
|
DW_AREA_PAL,
|
|
|
|
|
LW_SPR_GFX_PART1,
|
|
|
|
|
LW_SPR_GFX_PART2,
|
|
|
|
|
DW_SPR_GFX_PART1,
|
|
|
|
|
DW_SPR_GFX_PART2,
|
|
|
|
|
LW_SPR_PAL_PART1,
|
|
|
|
|
LW_SPR_PAL_PART2,
|
|
|
|
|
DW_SPR_PAL_PART1,
|
|
|
|
|
DW_SPR_PAL_PART2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int current_world_ = 0;
|
|
|
|
|
int current_map_ = 0;
|
|
|
|
|
int current_parent_ = 0;
|
|
|
|
|
int current_entrance_id_ = 0;
|
|
|
|
|
int current_exit_id_ = 0;
|
|
|
|
|
int current_item_id_ = 0;
|
|
|
|
|
int current_sprite_id_ = 0;
|
|
|
|
|
int current_blockset_ = 0;
|
|
|
|
|
int game_state_ = 1;
|
|
|
|
|
int current_tile16_ = 0;
|
|
|
|
|
int selected_entrance_ = 0;
|
|
|
|
|
int selected_usage_map_ = 0xFFFF;
|
|
|
|
|
|
|
|
|
|
bool all_gfx_loaded_ = false;
|
|
|
|
|
bool map_blockset_loaded_ = false;
|
|
|
|
|
bool selected_tile_loaded_ = false;
|
|
|
|
|
bool show_tile16_editor_ = false;
|
|
|
|
|
bool show_gfx_group_editor_ = false;
|
|
|
|
|
bool show_properties_editor_ = false;
|
|
|
|
|
bool overworld_canvas_fullscreen_ = false;
|
|
|
|
|
bool middle_mouse_dragging_ = false;
|
|
|
|
|
bool is_dragging_entity_ = false;
|
|
|
|
|
bool dragged_entity_free_movement_ = false;
|
|
|
|
|
bool current_map_lock_ = false;
|
|
|
|
|
bool show_custom_bg_color_editor_ = false;
|
|
|
|
|
bool show_overlay_editor_ = false;
|
|
|
|
|
bool use_area_specific_bg_color_ = false;
|
|
|
|
|
bool show_map_properties_panel_ = false;
|
|
|
|
|
bool show_overlay_preview_ = false;
|
|
|
|
|
|
|
|
|
|
// Card visibility states - Start hidden to prevent crash
|
|
|
|
|
bool show_overworld_canvas_ = true;
|
|
|
|
|
bool show_tile16_selector_ = false;
|
|
|
|
|
bool show_tile8_selector_ = false;
|
|
|
|
|
bool show_area_gfx_ = false;
|
|
|
|
|
bool show_scratch_ = false;
|
|
|
|
|
bool show_gfx_groups_ = false;
|
|
|
|
|
bool show_usage_stats_ = false;
|
|
|
|
|
bool show_v3_settings_ = false;
|
|
|
|
|
|
|
|
|
|
// Map properties system for UI organization
|
|
|
|
|
std::unique_ptr<MapPropertiesSystem> map_properties_system_;
|
|
|
|
|
std::unique_ptr<OverworldEntityRenderer> entity_renderer_;
|
|
|
|
|
|
|
|
|
|
// Scratch space for large layouts
|
|
|
|
|
// Scratch space canvas for tile16 drawing (like a mini overworld)
|
|
|
|
|
struct ScratchSpaceSlot {
|
|
|
|
|
gfx::Bitmap scratch_bitmap;
|
|
|
|
|
std::array<std::array<int, 32>, 32> tile_data; // 32x32 grid of tile16 IDs
|
|
|
|
|
bool in_use = false;
|
|
|
|
|
std::string name = "Empty";
|
|
|
|
|
int width = 16; // Default 16x16 tiles
|
|
|
|
|
int height = 16;
|
|
|
|
|
// Independent selection system for scratch space
|
|
|
|
|
std::vector<ImVec2> selected_tiles;
|
|
|
|
|
std::vector<ImVec2> selected_points;
|
|
|
|
|
bool select_rect_active = false;
|
|
|
|
|
};
|
|
|
|
|
std::array<ScratchSpaceSlot, 4> scratch_spaces_;
|
|
|
|
|
int current_scratch_slot_ = 0;
|
|
|
|
|
|
|
|
|
|
gfx::Tilemap tile16_blockset_;
|
|
|
|
|
|
|
|
|
|
Rom* rom_;
|
|
|
|
|
|
|
|
|
|
gfx::IRenderer* renderer_;
|
|
|
|
|
Tile16Editor tile16_editor_{rom_, &tile16_blockset_};
|
|
|
|
|
GfxGroupEditor gfx_group_editor_;
|
|
|
|
|
PaletteEditor palette_editor_;
|
|
|
|
|
|
|
|
|
|
gfx::SnesPalette palette_;
|
|
|
|
|
|
|
|
|
|
gfx::Bitmap selected_tile_bmp_;
|
|
|
|
|
gfx::Bitmap tile16_blockset_bmp_;
|
|
|
|
|
gfx::Bitmap current_gfx_bmp_;
|
|
|
|
|
gfx::Bitmap all_gfx_bmp;
|
|
|
|
|
|
|
|
|
|
std::array<gfx::Bitmap, zelda3::kNumOverworldMaps> maps_bmp_;
|
|
|
|
|
gfx::BitmapTable current_graphics_set_;
|
|
|
|
|
std::vector<gfx::Bitmap> sprite_previews_;
|
|
|
|
|
|
|
|
|
|
// Deferred texture creation for performance optimization
|
|
|
|
|
// Deferred texture management now handled by gfx::Arena::Get()
|
|
|
|
|
|
|
|
|
|
zelda3::Overworld overworld_{rom_};
|
|
|
|
|
zelda3::OverworldBlockset refresh_blockset_;
|
|
|
|
|
|
|
|
|
|
zelda3::Sprite current_sprite_;
|
|
|
|
|
|
|
|
|
|
zelda3::OverworldEntrance current_entrance_;
|
|
|
|
|
zelda3::OverworldExit current_exit_;
|
|
|
|
|
zelda3::OverworldItem current_item_;
|
|
|
|
|
zelda3::OverworldEntranceTileTypes entrance_tiletypes_ = {};
|
|
|
|
|
|
|
|
|
|
zelda3::GameEntity* current_entity_ = nullptr;
|
|
|
|
|
zelda3::GameEntity* dragged_entity_ = nullptr;
|
|
|
|
|
|
|
|
|
|
gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k64x64};
|
|
|
|
|
gui::Canvas current_gfx_canvas_{"CurrentGfx", kCurrentGfxCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k32x32};
|
|
|
|
|
gui::Canvas blockset_canvas_{"OwBlockset", kBlocksetCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k32x32};
|
|
|
|
|
std::unique_ptr<gui::TileSelectorWidget> blockset_selector_;
|
|
|
|
|
gui::Canvas graphics_bin_canvas_{"GraphicsBin", kGraphicsBinCanvasSize,
|
|
|
|
|
gui::CanvasGridSize::k16x16};
|
|
|
|
|
gui::Canvas properties_canvas_;
|
|
|
|
|
gui::Canvas scratch_canvas_{"ScratchSpace", ImVec2(320, 480), gui::CanvasGridSize::k32x32};
|
|
|
|
|
|
|
|
|
|
absl::Status status_;
|
|
|
|
|
};
|
|
|
|
|
} // namespace editor
|
|
|
|
|
} // namespace yaze
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|