backend-infra-engineer: Release v0.3.1 snapshot

This commit is contained in:
scawful
2025-09-28 03:07:45 -04:00
parent e32ac75b9c
commit 4371618a9b
88 changed files with 17940 additions and 4600 deletions

View File

@@ -1,6 +1,8 @@
#include "dungeon_object_selector.h"
#include <algorithm>
#include <iterator>
#include <cstring>
#include "app/core/window.h"
#include "app/gfx/arena.h"
@@ -1045,7 +1047,10 @@ void DungeonObjectSelector::DrawCompactPropertiesEditor() {
static int music_id = 0;
// Copy current values
strncpy(room_name, properties.name.c_str(), sizeof(room_name) - 1);
// Safe string copy with bounds checking
size_t name_len = std::min(properties.name.length(), sizeof(room_name) - 1);
std::memcpy(room_name, properties.name.c_str(), name_len);
room_name[name_len] = '\0';
dungeon_id = properties.dungeon_id;
floor_level = properties.floor_level;
is_boss_room = properties.is_boss_room;

View File

@@ -11,6 +11,7 @@ set(
app/editor/dungeon/dungeon_room_loader.cc
app/editor/dungeon/dungeon_usage_tracker.cc
app/editor/overworld/overworld_editor.cc
app/editor/overworld/overworld_editor_manager.cc
app/editor/sprite/sprite_editor.cc
app/editor/music/music_editor.cc
app/editor/message/message_editor.cc

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@
#include <vector>
#include "absl/status/status.h"
#include "app/core/features.h"
#include "app/core/project.h"
#include "app/editor/code/assembly_editor.h"
#include "app/editor/code/memory_editor.h"
@@ -19,10 +20,9 @@
#include "app/editor/overworld/overworld_editor.h"
#include "app/editor/sprite/sprite_editor.h"
#include "app/editor/system/popup_manager.h"
#include "app/editor/system/toast_manager.h"
#include "app/editor/system/settings_editor.h"
#include "app/editor/system/toast_manager.h"
#include "app/emu/emulator.h"
#include "app/core/features.h"
#include "app/rom.h"
#include "yaze_config.h"
@@ -100,34 +100,41 @@ class EditorManager {
absl::Status SetCurrentRom(Rom* rom);
auto GetCurrentRom() -> Rom* { return current_rom_; }
auto GetCurrentEditorSet() -> EditorSet* { return current_editor_set_; }
// Get current session's feature flags (falls back to global if no session)
core::FeatureFlags::Flags* GetCurrentFeatureFlags() {
size_t current_index = GetCurrentSessionIndex();
if (current_index < sessions_.size()) {
return &sessions_[current_index].feature_flags;
}
return &core::FeatureFlags::get(); // Fallback to global
return &core::FeatureFlags::get(); // Fallback to global
}
void SetFontGlobalScale(float scale) {
font_global_scale_ = scale;
ImGui::GetIO().FontGlobalScale = scale;
SaveUserSettings();
}
private:
void DrawHomepage();
void DrawWelcomeScreen();
absl::Status DrawRomSelector();
absl::Status LoadRom();
absl::Status LoadAssets();
absl::Status SaveRom();
absl::Status SaveRomAs(const std::string& filename);
absl::Status OpenRomOrProject(const std::string& filename);
// Enhanced project management
absl::Status CreateNewProject(const std::string& template_name = "Basic ROM Hack");
absl::Status CreateNewProject(
const std::string& template_name = "Basic ROM Hack");
absl::Status OpenProject();
absl::Status SaveProject();
absl::Status SaveProjectAs();
absl::Status ImportProject(const std::string& project_path);
absl::Status RepairCurrentProject();
void ShowProjectHelp();
// Testing system
void InitializeTestSuites();
@@ -157,9 +164,10 @@ class EditorManager {
bool show_global_search_ = false;
bool show_session_rename_dialog_ = false;
bool show_welcome_screen_ = false;
bool welcome_screen_manually_closed_ = false;
size_t session_to_rename_ = 0;
char session_rename_buffer_[256] = {};
// Testing interface
bool show_test_dashboard_ = false;
@@ -177,18 +185,17 @@ class EditorManager {
struct RomSession {
Rom rom;
EditorSet editors;
std::string custom_name; // User-defined session name
std::string filepath; // ROM filepath for duplicate detection
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
std::string custom_name; // User-defined session name
std::string filepath; // ROM filepath for duplicate detection
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
RomSession() = default;
explicit RomSession(Rom&& r)
: rom(std::move(r)), editors(&rom) {
explicit RomSession(Rom&& r) : rom(std::move(r)), editors(&rom) {
filepath = rom.filename();
// Initialize with default feature flags
feature_flags = core::FeatureFlags::Flags{};
}
// Get display name (custom name or ROM title)
std::string GetDisplayName() const {
if (!custom_name.empty()) {
@@ -212,20 +219,24 @@ class EditorManager {
// Settings helpers
void LoadUserSettings();
void SaveUserSettings();
void RefreshWorkspacePresets();
void SaveWorkspacePreset(const std::string& name);
void LoadWorkspacePreset(const std::string& name);
// Workspace management
void CreateNewSession();
void DuplicateCurrentSession();
void CloseCurrentSession();
void RemoveSession(size_t index);
void SwitchToSession(size_t index);
size_t GetCurrentSessionIndex() const;
size_t GetActiveSessionCount() const;
void ResetWorkspaceLayout();
// Multi-session editor management
std::string GenerateUniqueEditorTitle(EditorType type, size_t session_index) const;
std::string GenerateUniqueEditorTitle(EditorType type,
size_t session_index) const;
void SaveWorkspaceLayout();
void LoadWorkspaceLayout();
void ShowAllWindows();
@@ -236,12 +247,12 @@ class EditorManager {
void LoadDeveloperLayout();
void LoadDesignerLayout();
void LoadModderLayout();
// Session management helpers
bool HasDuplicateSession(const std::string& filepath);
void RenameSession(size_t index, const std::string& new_name);
std::string GenerateUniqueEditorTitle(EditorType type, size_t session_index);
// UI drawing helpers
void DrawSessionSwitcher();
void DrawSessionManager();

File diff suppressed because it is too large Load Diff

View File

@@ -64,6 +64,7 @@ class MapPropertiesSystem {
void DrawSpritePropertiesTab(int current_map);
void DrawCustomFeaturesTab(int current_map);
void DrawTileGraphicsTab(int current_map);
void DrawMusicTab(int current_map);
// Utility methods
void RefreshMapProperties();

File diff suppressed because it is too large Load Diff

View File

@@ -12,9 +12,9 @@
#include "app/gfx/tilemap.h"
#include "app/gui/canvas.h"
#include "app/gui/input.h"
#include "app/gui/zeml.h"
#include "app/rom.h"
#include "app/zelda3/overworld/overworld.h"
#include "app/editor/overworld/overworld_editor_manager.h"
#include "imgui/imgui.h"
namespace yaze {
@@ -188,6 +188,16 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
void DrawMapPropertiesPanel();
void HandleMapInteraction();
void SetupOverworldCanvasContextMenu();
// 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();
@@ -253,6 +263,24 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
// Map properties system for UI organization
std::unique_ptr<MapPropertiesSystem> map_properties_system_;
std::unique_ptr<OverworldEditorManager> overworld_manager_;
// 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_;
@@ -295,12 +323,12 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
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};
gui::Table toolset_table_{"##ToolsetTable0", 12, kToolsetTableFlags};
gui::Table map_settings_table_{kOWMapTable.data(), 8, kOWMapFlags,
ImVec2(0, 0)};
gui::zeml::Node layout_node_;
absl::Status status_;
};
} // namespace editor

View File

@@ -0,0 +1,423 @@
#include "overworld_editor_manager.h"
#include "app/gfx/snes_color.h"
#include "app/gui/icons.h"
#include "app/gui/input.h"
#include "app/gui/style.h"
#include "app/zelda3/overworld/overworld_map.h"
namespace yaze {
namespace editor {
using namespace ImGui;
absl::Status OverworldEditorManager::DrawV3SettingsPanel() {
if (BeginTabItem("v3 Settings")) {
Text("ZSCustomOverworld v3 Settings");
Separator();
// Check if custom ASM is applied
uint8_t asm_version = GetCustomASMVersion();
if (asm_version >= 3 && asm_version != 0xFF) {
TextColored(ImVec4(0, 1, 0, 1), "Custom Overworld ASM v%d Applied", asm_version);
} else if (asm_version == 0x00) {
TextColored(ImVec4(1, 1, 0, 1), "Vanilla ROM - Custom features available via flag");
} else {
TextColored(ImVec4(1, 0, 0, 1), "Custom ASM v%d - Consider upgrading to v3", asm_version);
}
Separator();
RETURN_IF_ERROR(DrawCustomOverworldSettings());
RETURN_IF_ERROR(DrawAreaSpecificSettings());
RETURN_IF_ERROR(DrawTransitionSettings());
RETURN_IF_ERROR(DrawOverlaySettings());
EndTabItem();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawCustomOverworldSettings() {
if (TreeNode("Custom Overworld Features")) {
RETURN_IF_ERROR(DrawBooleanSetting("Enable Area-Specific Background Colors",
&enable_area_specific_bg_,
"Allows each overworld area to have its own background color"));
RETURN_IF_ERROR(DrawBooleanSetting("Enable Main Palette Override",
&enable_main_palette_,
"Allows each area to override the main palette"));
RETURN_IF_ERROR(DrawBooleanSetting("Enable Mosaic Transitions",
&enable_mosaic_,
"Enables mosaic screen transitions between areas"));
RETURN_IF_ERROR(DrawBooleanSetting("Enable Custom GFX Groups",
&enable_gfx_groups_,
"Allows each area to have custom tile GFX groups"));
RETURN_IF_ERROR(DrawBooleanSetting("Enable Subscreen Overlays",
&enable_subscreen_overlay_,
"Enables custom subscreen overlays (fog, sky, etc.)"));
RETURN_IF_ERROR(DrawBooleanSetting("Enable Animated GFX Override",
&enable_animated_gfx_,
"Allows each area to have custom animated tiles"));
Separator();
if (Button("Apply Custom Overworld ASM")) {
RETURN_IF_ERROR(ApplyCustomOverworldASM());
}
SameLine();
HOVER_HINT("Writes the custom overworld settings to ROM");
TreePop();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawAreaSpecificSettings() {
if (TreeNode("Area-Specific Settings")) {
// Map selection
int map_count = zelda3::kNumOverworldMaps;
SliderInt("Map Index", &current_map_index_, 0, map_count - 1);
auto* current_map = overworld_->mutable_overworld_map(current_map_index_);
// Area size controls
RETURN_IF_ERROR(DrawAreaSizeControls());
// Background color
if (enable_area_specific_bg_) {
uint16_t bg_color = current_map->area_specific_bg_color();
RETURN_IF_ERROR(DrawColorPicker("Background Color", &bg_color));
current_map->set_area_specific_bg_color(bg_color);
}
// Main palette
if (enable_main_palette_) {
uint8_t main_palette = current_map->main_palette();
SliderInt("Main Palette", (int*)&main_palette, 0, 5);
current_map->set_main_palette(main_palette);
}
// Mosaic settings
if (enable_mosaic_) {
RETURN_IF_ERROR(DrawMosaicControls());
}
// GFX groups
if (enable_gfx_groups_) {
RETURN_IF_ERROR(DrawGfxGroupControls());
}
// Subscreen overlay
if (enable_subscreen_overlay_) {
uint16_t overlay = current_map->subscreen_overlay();
RETURN_IF_ERROR(DrawOverlaySetting("Subscreen Overlay", &overlay));
current_map->set_subscreen_overlay(overlay);
}
// Animated GFX
if (enable_animated_gfx_) {
uint8_t animated_gfx = current_map->animated_gfx();
RETURN_IF_ERROR(DrawGfxGroupSetting("Animated GFX", &animated_gfx));
current_map->set_animated_gfx(animated_gfx);
}
TreePop();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawAreaSizeControls() {
auto* current_map = overworld_->mutable_overworld_map(current_map_index_);
const char* area_size_names[] = {"Small", "Large", "Wide", "Tall"};
int current_size = static_cast<int>(current_map->area_size());
if (Combo("Area Size", &current_size, area_size_names, 4)) {
current_map->SetAreaSize(static_cast<zelda3::AreaSizeEnum>(current_size));
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawMosaicControls() {
auto* current_map = overworld_->mutable_overworld_map(current_map_index_);
const auto& mosaic = current_map->mosaic_expanded();
bool mosaic_up = mosaic[0];
bool mosaic_down = mosaic[1];
bool mosaic_left = mosaic[2];
bool mosaic_right = mosaic[3];
if (Checkbox("Mosaic Up", &mosaic_up)) {
current_map->set_mosaic_expanded(0, mosaic_up);
}
SameLine();
if (Checkbox("Mosaic Down", &mosaic_down)) {
current_map->set_mosaic_expanded(1, mosaic_down);
}
if (Checkbox("Mosaic Left", &mosaic_left)) {
current_map->set_mosaic_expanded(2, mosaic_left);
}
SameLine();
if (Checkbox("Mosaic Right", &mosaic_right)) {
current_map->set_mosaic_expanded(3, mosaic_right);
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawGfxGroupControls() {
auto* current_map = overworld_->mutable_overworld_map(current_map_index_);
Text("Custom Tile GFX Groups:");
for (int i = 0; i < 8; i++) {
uint8_t gfx_id = current_map->custom_tileset(i);
std::string label = "GFX " + std::to_string(i);
RETURN_IF_ERROR(DrawGfxGroupSetting(label.c_str(), &gfx_id));
current_map->set_custom_tileset(i, gfx_id);
if (i < 7) SameLine();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawTransitionSettings() {
if (TreeNode("Transition Settings")) {
Text("Complex area transition calculations are automatically handled");
Text("based on neighboring area sizes (Large, Wide, Tall, Small).");
if (GetCustomASMVersion() >= 3) {
TextColored(ImVec4(0, 1, 0, 1), "Using v3+ enhanced transitions");
} else {
TextColored(ImVec4(1, 1, 0, 1), "Using vanilla/v2 transitions");
}
TreePop();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawOverlaySettings() {
if (TreeNode("Interactive Overlay Settings")) {
Text("Interactive overlays reveal holes and change map elements.");
auto* current_map = overworld_->mutable_overworld_map(current_map_index_);
Text("Map %d has %s", current_map_index_,
current_map->has_overlay() ? "interactive overlay" : "no overlay");
if (current_map->has_overlay()) {
Text("Overlay ID: 0x%04X", current_map->overlay_id());
Text("Overlay data size: %zu bytes", current_map->overlay_data().size());
}
TreePop();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::ApplyCustomOverworldASM() {
return overworld_->SaveCustomOverworldASM(
enable_area_specific_bg_, enable_main_palette_, enable_mosaic_,
enable_gfx_groups_, enable_subscreen_overlay_, enable_animated_gfx_);
}
bool OverworldEditorManager::ValidateV3Compatibility() {
uint8_t asm_version = GetCustomASMVersion();
return (asm_version >= 3 && asm_version != 0xFF);
}
bool OverworldEditorManager::CheckCustomASMApplied() {
uint8_t asm_version = GetCustomASMVersion();
return (asm_version != 0xFF && asm_version != 0x00);
}
uint8_t OverworldEditorManager::GetCustomASMVersion() {
return (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
}
absl::Status OverworldEditorManager::DrawBooleanSetting(const char* label, bool* setting,
const char* help_text) {
Checkbox(label, setting);
if (help_text && IsItemHovered()) {
SetTooltip("%s", help_text);
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawColorPicker(const char* label, uint16_t* color) {
gfx::SnesColor snes_color(*color);
ImVec4 imgui_color = snes_color.rgb();
if (ColorEdit3(label, &imgui_color.x)) {
gfx::SnesColor new_color;
new_color.set_rgb(imgui_color);
*color = new_color.snes();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawOverlaySetting(const char* label, uint16_t* overlay) {
int overlay_int = *overlay;
if (InputInt(label, &overlay_int, 1, 16, ImGuiInputTextFlags_CharsHexadecimal)) {
*overlay = static_cast<uint16_t>(overlay_int & 0xFFFF);
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawGfxGroupSetting(const char* label, uint8_t* gfx_id,
int max_value) {
int gfx_int = *gfx_id;
if (SliderInt(label, &gfx_int, 0, max_value)) {
*gfx_id = static_cast<uint8_t>(gfx_int);
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawUnifiedSettingsTable() {
// Create a comprehensive settings table that combines toolset and properties
if (BeginTable("##UnifiedOverworldSettings", 6,
ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter |
ImGuiTableFlags_BordersV | ImGuiTableFlags_SizingFixedFit)) {
// Setup columns with proper widths
TableSetupColumn(ICON_MD_BUILD " Tools", ImGuiTableColumnFlags_WidthFixed, 120);
TableSetupColumn(ICON_MD_MAP " World", ImGuiTableColumnFlags_WidthFixed, 100);
TableSetupColumn(ICON_MD_IMAGE " Graphics", ImGuiTableColumnFlags_WidthFixed, 100);
TableSetupColumn(ICON_MD_PALETTE " Palette", ImGuiTableColumnFlags_WidthFixed, 100);
TableSetupColumn(ICON_MD_SETTINGS " Properties", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn(ICON_MD_EXTENSION " v3 Features", ImGuiTableColumnFlags_WidthFixed, 120);
TableHeadersRow();
TableNextRow();
// Tools column
TableNextColumn();
RETURN_IF_ERROR(DrawToolsetInSettings());
// World column
TableNextColumn();
Text(ICON_MD_PUBLIC " Current World");
SetNextItemWidth(80.f);
// if (Combo("##world", &current_world_, kWorldList.data(), 3)) {
// // World change logic would go here
// }
// Graphics column
TableNextColumn();
Text(ICON_MD_IMAGE " Area Graphics");
// Graphics controls would go here
// Palette column
TableNextColumn();
Text(ICON_MD_PALETTE " Area Palette");
// Palette controls would go here
// Properties column
TableNextColumn();
Text(ICON_MD_SETTINGS " Map Properties");
// Map properties would go here
// v3 Features column
TableNextColumn();
uint8_t asm_version = GetCustomASMVersion();
if (asm_version >= 3 && asm_version != 0xFF) {
TextColored(ImVec4(0, 1, 0, 1), ICON_MD_NEW_RELEASES " v3 Active");
if (Button(ICON_MD_TUNE " Settings")) {
// Open v3 settings
}
} else {
TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1), ICON_MD_UPGRADE " v3 Available");
if (Button(ICON_MD_UPGRADE " Upgrade")) {
// Trigger upgrade
}
}
EndTable();
}
return absl::OkStatus();
}
absl::Status OverworldEditorManager::DrawToolsetInSettings() {
// Compact toolset layout within the settings table
BeginGroup();
// Core editing tools in a compact grid
if (Button(ICON_MD_PAN_TOOL_ALT, ImVec2(25, 25))) {
// Set PAN mode
}
HOVER_HINT("Pan (1)");
SameLine();
if (Button(ICON_MD_DRAW, ImVec2(25, 25))) {
// Set DRAW_TILE mode
}
HOVER_HINT("Draw Tile (2)");
SameLine();
if (Button(ICON_MD_DOOR_FRONT, ImVec2(25, 25))) {
// Set ENTRANCES mode
}
HOVER_HINT("Entrances (3)");
SameLine();
if (Button(ICON_MD_DOOR_BACK, ImVec2(25, 25))) {
// Set EXITS mode
}
HOVER_HINT("Exits (4)");
// Second row
if (Button(ICON_MD_GRASS, ImVec2(25, 25))) {
// Set ITEMS mode
}
HOVER_HINT("Items (5)");
SameLine();
if (Button(ICON_MD_PEST_CONTROL_RODENT, ImVec2(25, 25))) {
// Set SPRITES mode
}
HOVER_HINT("Sprites (6)");
SameLine();
if (Button(ICON_MD_ADD_LOCATION, ImVec2(25, 25))) {
// Set TRANSPORTS mode
}
HOVER_HINT("Transports (7)");
SameLine();
if (Button(ICON_MD_MUSIC_NOTE, ImVec2(25, 25))) {
// Set MUSIC mode
}
HOVER_HINT("Music (8)");
EndGroup();
return absl::OkStatus();
}
absl::Status OverworldEditorManager::HandleCanvasSelectionTransfer() {
// This could be called to manage bidirectional selection transfer
// For now, it's a placeholder for future canvas interaction management
return absl::OkStatus();
}
absl::Status OverworldEditorManager::TransferOverworldSelectionToScratch() {
// Transfer logic would go here to copy selections from overworld to scratch
// This could be integrated with the editor's context system
return absl::OkStatus();
}
absl::Status OverworldEditorManager::TransferScratchSelectionToOverworld() {
// Transfer logic would go here to copy selections from scratch to overworld
// This could be integrated with the editor's context system
return absl::OkStatus();
}
} // namespace editor
} // namespace yaze

View File

@@ -0,0 +1,108 @@
#ifndef YAZE_APP_EDITOR_OVERWORLD_OVERWORLD_EDITOR_MANAGER_H
#define YAZE_APP_EDITOR_OVERWORLD_OVERWORLD_EDITOR_MANAGER_H
#include <memory>
#include "absl/status/status.h"
#include "app/rom.h"
#include "app/zelda3/overworld/overworld.h"
#include "app/gui/canvas.h"
#include "app/gui/input.h"
namespace yaze {
namespace editor {
// Forward declarations
enum class EditingMode;
class OverworldEditor;
/**
* @class OverworldEditorManager
* @brief Manages the complex overworld editor functionality and v3 features
*
* This class separates the complex overworld editing functionality from the main
* OverworldEditor class to improve maintainability and organization, especially
* for ZSCustomOverworld v3 features.
*/
class OverworldEditorManager {
public:
OverworldEditorManager(zelda3::Overworld* overworld, Rom* rom,
OverworldEditor* editor = nullptr)
: overworld_(overworld), rom_(rom), editor_(editor) {}
// Set editor context for mode changes
void SetEditorContext(OverworldEditor* editor) { editor_ = editor; }
// v3 Feature Management
absl::Status DrawV3SettingsPanel();
absl::Status DrawCustomOverworldSettings();
absl::Status DrawAreaSpecificSettings();
absl::Status DrawTransitionSettings();
absl::Status DrawOverlaySettings();
// Map Properties Management
absl::Status DrawMapPropertiesTable();
absl::Status DrawUnifiedSettingsTable();
absl::Status DrawToolsetInSettings();
absl::Status DrawAreaSizeControls();
absl::Status DrawMosaicControls();
absl::Status DrawPaletteControls();
absl::Status DrawGfxGroupControls();
// Save/Load Operations for v3
absl::Status SaveCustomOverworldData();
absl::Status LoadCustomOverworldData();
absl::Status ApplyCustomOverworldASM();
// Canvas Interaction Management
absl::Status HandleCanvasSelectionTransfer();
absl::Status TransferOverworldSelectionToScratch();
absl::Status TransferScratchSelectionToOverworld();
// Validation and Checks
bool ValidateV3Compatibility();
bool CheckCustomASMApplied();
uint8_t GetCustomASMVersion();
// Getters/Setters for v3 settings
auto enable_area_specific_bg() const { return enable_area_specific_bg_; }
auto enable_main_palette() const { return enable_main_palette_; }
auto enable_mosaic() const { return enable_mosaic_; }
auto enable_gfx_groups() const { return enable_gfx_groups_; }
auto enable_subscreen_overlay() const { return enable_subscreen_overlay_; }
auto enable_animated_gfx() const { return enable_animated_gfx_; }
void set_enable_area_specific_bg(bool value) { enable_area_specific_bg_ = value; }
void set_enable_main_palette(bool value) { enable_main_palette_ = value; }
void set_enable_mosaic(bool value) { enable_mosaic_ = value; }
void set_enable_gfx_groups(bool value) { enable_gfx_groups_ = value; }
void set_enable_subscreen_overlay(bool value) { enable_subscreen_overlay_ = value; }
void set_enable_animated_gfx(bool value) { enable_animated_gfx_ = value; }
private:
zelda3::Overworld* overworld_;
Rom* rom_;
OverworldEditor* editor_;
// v3 Feature flags
bool enable_area_specific_bg_ = false;
bool enable_main_palette_ = false;
bool enable_mosaic_ = false;
bool enable_gfx_groups_ = false;
bool enable_subscreen_overlay_ = false;
bool enable_animated_gfx_ = false;
// Current editing state
int current_map_index_ = 0;
// Helper methods
absl::Status DrawBooleanSetting(const char* label, bool* setting, const char* help_text = nullptr);
absl::Status DrawColorPicker(const char* label, uint16_t* color);
absl::Status DrawOverlaySetting(const char* label, uint16_t* overlay);
absl::Status DrawGfxGroupSetting(const char* label, uint8_t* gfx_id, int max_value = 255);
};
} // namespace editor
} // namespace yaze
#endif // YAZE_APP_EDITOR_OVERWORLD_OVERWORLD_EDITOR_MANAGER_H

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,8 @@
#define YAZE_APP_EDITOR_TILE16EDITOR_H
#include <array>
#include <chrono>
#include <functional>
#include <vector>
#include "absl/status/status.h"
@@ -19,29 +21,43 @@
namespace yaze {
namespace editor {
// Constants for tile editing
constexpr int kTile16Size = 16;
constexpr int kTile8Size = 8;
constexpr int kTilesheetEditorWidth = 0x100;
constexpr int kTilesheetEditorHeight = 0x4000;
constexpr int kTile16CanvasSize = 0x20;
constexpr int kTile8CanvasHeight = 0x175;
constexpr int kNumScratchSlots = 4;
constexpr int kNumPalettes = 8;
constexpr int kTile8PixelCount = 64;
constexpr int kTile16PixelCount = 256;
/**
* @brief Popup window to edit Tile16 data
*/
class Tile16Editor : public gfx::GfxContext {
public:
Tile16Editor(Rom *rom, gfx::Tilemap *tile16_blockset)
Tile16Editor(Rom* rom, gfx::Tilemap* tile16_blockset)
: rom_(rom), tile16_blockset_(tile16_blockset) {}
absl::Status Initialize(const gfx::Bitmap &tile16_blockset_bmp,
const gfx::Bitmap &current_gfx_bmp,
std::array<uint8_t, 0x200> &all_tiles_types);
absl::Status Initialize(const gfx::Bitmap& tile16_blockset_bmp,
const gfx::Bitmap& current_gfx_bmp,
std::array<uint8_t, 0x200>& all_tiles_types);
absl::Status Update();
void DrawTile16Editor();
absl::Status UpdateTile16Transfer();
absl::Status UpdateBlockset();
absl::Status DrawToCurrentTile16(ImVec2 pos);
// Scratch space for tile16 layouts
void DrawScratchSpace();
absl::Status SaveLayoutToScratch(int slot);
absl::Status LoadLayoutFromScratch(int slot);
absl::Status DrawToCurrentTile16(ImVec2 pos, const gfx::Bitmap* source_tile = nullptr);
absl::Status UpdateTile16Edit();
absl::Status UpdateTransferTileCanvas();
absl::Status LoadTile8();
absl::Status SetCurrentTile(int id);
@@ -53,14 +69,69 @@ class Tile16Editor : public gfx::GfxContext {
absl::Status LoadTile16FromScratchSpace(int slot);
absl::Status ClearScratchSpace(int slot);
void set_rom(Rom *rom) { rom_ = rom; }
Rom *rom() const { return rom_; }
// Advanced editing features
absl::Status FlipTile16Horizontal();
absl::Status FlipTile16Vertical();
absl::Status RotateTile16();
absl::Status FillTile16WithTile8(int tile8_id);
absl::Status AutoTileTile16();
absl::Status ClearTile16();
// Palette management
absl::Status CyclePalette(bool forward = true);
absl::Status ApplyPaletteToAll(uint8_t palette_id);
absl::Status PreviewPaletteChange(uint8_t palette_id);
// Batch operations
absl::Status ApplyToSelection(const std::function<void(int)>& operation);
absl::Status BatchEdit(const std::vector<int>& tile_ids,
const std::function<void(int)>& operation);
// History and undo system
absl::Status Undo();
absl::Status Redo();
void SaveUndoState();
// Live preview system
void EnableLivePreview(bool enable) { live_preview_enabled_ = enable; }
absl::Status UpdateLivePreview();
// Validation and integrity checks
absl::Status ValidateTile16Data();
bool IsTile16Valid(int tile_id) const;
// Integration with overworld system
absl::Status SaveTile16ToROM();
absl::Status UpdateOverworldTilemap();
absl::Status CommitChangesToBlockset();
absl::Status CommitChangesToOverworld();
absl::Status DiscardChanges();
// Helper methods for palette management
absl::Status UpdateTile8Palette(int tile8_id);
absl::Status RefreshAllPalettes();
void DrawPaletteSettings();
// ROM data access and modification
absl::Status UpdateROMTile16Data();
absl::Status RefreshTile16Blockset();
gfx::Tile16* GetCurrentTile16Data();
absl::Status RegenerateTile16BitmapFromROM();
// Manual tile8 input controls
void DrawManualTile8Inputs();
void set_rom(Rom* rom) { rom_ = rom; }
Rom* rom() const { return rom_; }
// Callback for when changes are committed to notify parent editor
void set_on_changes_committed(std::function<absl::Status()> callback) {
on_changes_committed_ = callback;
}
private:
Rom *rom_ = nullptr;
Rom* rom_ = nullptr;
bool map_blockset_loaded_ = false;
bool transfer_started_ = false;
bool transfer_blockset_loaded_ = false;
bool x_flip = false;
bool y_flip = false;
bool priority_tile = false;
@@ -78,19 +149,67 @@ class Tile16Editor : public gfx::GfxContext {
std::array<gfx::Bitmap, 4> scratch_space_;
std::array<bool, 4> scratch_space_used_ = {false, false, false, false};
// Layout scratch space for tile16 arrangements (4 slots of 8x8 grids)
struct LayoutScratch {
std::array<std::array<int, 8>, 8> tile_layout; // 8x8 grid of tile16 IDs
bool in_use = false;
std::string name = "Empty";
};
std::array<LayoutScratch, 4> layout_scratch_;
// Undo/Redo system
struct UndoState {
int tile_id;
gfx::Bitmap tile_bitmap;
gfx::Tile16 tile_data;
uint8_t palette;
bool x_flip, y_flip, priority;
};
std::vector<UndoState> undo_stack_;
std::vector<UndoState> redo_stack_;
static constexpr size_t kMaxUndoStates_ = 50;
// Live preview system
bool live_preview_enabled_ = true;
gfx::Bitmap preview_tile16_;
bool preview_dirty_ = false;
// Selection system
std::vector<int> selected_tiles_;
int selection_start_tile_ = -1;
bool multi_select_mode_ = false;
// Advanced editing state
bool auto_tile_mode_ = false;
bool grid_snap_enabled_ = true;
bool show_tile_info_ = true;
bool show_palette_preview_ = true;
// Palette management settings
bool show_palette_settings_ = false;
int current_palette_group_ = 0; // 0=overworld_main, 1=aux1, 2=aux2, etc.
uint8_t palette_normalization_mask_ = 0x0F; // Default 4-bit mask
bool auto_normalize_pixels_ = true;
// Performance tracking
std::chrono::steady_clock::time_point last_edit_time_;
bool batch_mode_ = false;
util::NotifyValue<uint32_t> notify_tile16;
util::NotifyValue<uint8_t> notify_palette;
std::array<uint8_t, 0x200> all_tiles_types_;
// Tile16 blockset for selecting the tile to edit
gui::Canvas blockset_canvas_{"blocksetCanvas", ImVec2(0x100, 0x4000),
gui::CanvasGridSize::k32x32,};
gui::Canvas blockset_canvas_{
"blocksetCanvas", ImVec2(kTilesheetEditorWidth, kTilesheetEditorHeight),
gui::CanvasGridSize::k32x32};
gfx::Bitmap tile16_blockset_bmp_;
// Canvas for editing the selected tile
gui::Canvas tile16_edit_canvas_{"Tile16EditCanvas", ImVec2(0x40, 0x40),
gui::CanvasGridSize::k64x64};
// Canvas for editing the selected tile - optimized for 2x2 grid of 8x8 tiles (16x16 total)
gui::Canvas tile16_edit_canvas_{"Tile16EditCanvas",
ImVec2(64, 64), // Fixed 64x64 display size (16x16 pixels at 4x scale)
gui::CanvasGridSize::k8x8, 4.0F}; // 8x8 grid with 4x scale for clarity
gfx::Bitmap current_tile16_bmp_;
// Tile8 canvas to get the tile to drawing in the tile16_edit_canvas_
@@ -100,23 +219,18 @@ class Tile16Editor : public gfx::GfxContext {
gui::CanvasGridSize::k32x32};
gfx::Bitmap current_gfx_bmp_;
gui::Canvas transfer_canvas_;
gfx::Bitmap transfer_blockset_bmp_;
gui::Table tile_edit_table_{"##TileEditTable", 3, ImGuiTableFlags_Borders};
gfx::Tilemap *tile16_blockset_ = nullptr;
gfx::Tilemap* tile16_blockset_ = nullptr;
std::vector<gfx::Bitmap> current_gfx_individual_;
PaletteEditor palette_editor_;
gfx::SnesPalette palette_;
absl::Status status_;
Rom *transfer_rom_ = nullptr;
zelda3::Overworld transfer_overworld_{transfer_rom_};
std::array<gfx::Bitmap, kNumGfxSheets> transfer_gfx_;
absl::Status transfer_status_;
// Callback to notify parent editor when changes are committed
std::function<absl::Status()> on_changes_committed_;
};
} // namespace editor

View File

@@ -38,6 +38,9 @@ void PopupManager::Initialize() {
popups_["Workspace Help"] = {"Workspace Help", false, [this]() { DrawWorkspaceHelpPopup(); }};
popups_["Session Limit Warning"] = {"Session Limit Warning", false, [this]() { DrawSessionLimitWarningPopup(); }};
popups_["Layout Reset Confirm"] = {"Reset Layout Confirmation", false, [this]() { DrawLayoutResetConfirmPopup(); }};
// Settings popups (accessible without ROM)
popups_["Display Settings"] = {"Display Settings", false, [this]() { DrawDisplaySettingsPopup(); }};
}
void PopupManager::DrawPopups() {
@@ -48,7 +51,14 @@ void PopupManager::DrawPopups() {
for (auto& [name, params] : popups_) {
if (params.is_visible) {
OpenPopup(name.c_str());
if (BeginPopupModal(name.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
// Special handling for Display Settings popup to make it resizable
ImGuiWindowFlags popup_flags = ImGuiWindowFlags_AlwaysAutoResize;
if (name == "Display Settings") {
popup_flags = ImGuiWindowFlags_None; // Allow resizing for display settings
}
if (BeginPopupModal(name.c_str(), nullptr, popup_flags)) {
params.draw_function();
EndPopup();
}
@@ -491,5 +501,46 @@ void PopupManager::DrawLayoutResetConfirmPopup() {
}
}
void PopupManager::DrawDisplaySettingsPopup() {
// Set a comfortable default size with natural constraints
SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
Text("%s Display & Theme Settings", ICON_MD_DISPLAY_SETTINGS);
TextWrapped("Customize your YAZE experience - accessible anytime!");
Separator();
// Create a child window for scrollable content to avoid table conflicts
// Use remaining space minus the close button area
float available_height = GetContentRegionAvail().y - 60; // Reserve space for close button
if (BeginChild("DisplaySettingsContent", ImVec2(0, available_height), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
// Use the popup-safe version to avoid table conflicts
gui::DrawDisplaySettingsForPopup();
Separator();
gui::TextWithSeparators("Font Manager");
gui::DrawFontManager();
// Global font scale (moved from the old display settings window)
ImGuiIO &io = GetIO();
Separator();
Text("Global Font Scale");
static float font_global_scale = io.FontGlobalScale;
if (SliderFloat("##global_scale", &font_global_scale, 0.5f, 1.8f, "%.2f")) {
if (editor_manager_) {
editor_manager_->SetFontGlobalScale(font_global_scale);
} else {
io.FontGlobalScale = font_global_scale;
}
}
}
EndChild();
Separator();
if (Button("Close", gui::kDefaultModalSize)) {
Hide("Display Settings");
}
}
} // namespace editor
} // namespace yaze

View File

@@ -86,6 +86,9 @@ class PopupManager {
void DrawWorkspaceHelpPopup();
void DrawSessionLimitWarningPopup();
void DrawLayoutResetConfirmPopup();
// Settings popups (accessible without ROM)
void DrawDisplaySettingsPopup();
EditorManager* editor_manager_;
std::unordered_map<std::string, PopupParams> popups_;