backend-infra-engineer: Release v0.3.3 snapshot

This commit is contained in:
scawful
2025-11-21 21:35:50 -05:00
parent 3d71417f62
commit 476dd1cd1c
818 changed files with 65706 additions and 35514 deletions

View File

@@ -112,7 +112,7 @@ void GfxGroupEditor::DrawBlocksetViewer(bool sheet_only) {
BeginGroup();
for (int i = 0; i < 8; i++) {
int sheet_id = rom()->main_blockset_ids[selected_blockset_][i];
auto &sheet = gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id);
auto& sheet = gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id);
gui::BitmapCanvasPipeline(blockset_canvas_, sheet, 256, 0x10 * 0x04,
0x20, true, false, 22);
}
@@ -165,7 +165,7 @@ void GfxGroupEditor::DrawRoomsetViewer() {
BeginGroup();
for (int i = 0; i < 4; i++) {
int sheet_id = rom()->room_blockset_ids[selected_roomset_][i];
auto &sheet = gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id);
auto& sheet = gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id);
gui::BitmapCanvasPipeline(roomset_canvas_, sheet, 256, 0x10 * 0x04,
0x20, true, false, 23);
}
@@ -203,7 +203,7 @@ void GfxGroupEditor::DrawSpritesetViewer(bool sheet_only) {
BeginGroup();
for (int i = 0; i < 4; i++) {
int sheet_id = rom()->spriteset_ids[selected_spriteset_][i];
auto &sheet =
auto& sheet =
gfx::Arena::Get().mutable_gfx_sheets()->at(115 + sheet_id);
gui::BitmapCanvasPipeline(spriteset_canvas_, sheet, 256, 0x10 * 0x04,
0x20, true, false, 24);
@@ -215,20 +215,20 @@ void GfxGroupEditor::DrawSpritesetViewer(bool sheet_only) {
}
namespace {
void DrawPaletteFromPaletteGroup(gfx::SnesPalette &palette) {
void DrawPaletteFromPaletteGroup(gfx::SnesPalette& palette) {
if (palette.empty()) {
return;
}
for (size_t n = 0; n < palette.size(); n++) {
PushID(n);
if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y);
if ((n % 8) != 0)
SameLine(0.0f, GetStyle().ItemSpacing.y);
// Small icon of the color in the palette
if (gui::SnesColorButton(absl::StrCat("Palette", n), palette[n],
ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_NoPicker |
ImGuiColorEditFlags_NoTooltip)) {
}
ImGuiColorEditFlags_NoTooltip)) {}
PopID();
}
@@ -247,13 +247,13 @@ void GfxGroupEditor::DrawPaletteViewer() {
false, "paletteset", "0x" + std::to_string(selected_paletteset_),
"Paletteset " + std::to_string(selected_paletteset_));
uint8_t &dungeon_main_palette_val =
uint8_t& dungeon_main_palette_val =
rom()->paletteset_ids[selected_paletteset_][0];
uint8_t &dungeon_spr_pal_1_val =
uint8_t& dungeon_spr_pal_1_val =
rom()->paletteset_ids[selected_paletteset_][1];
uint8_t &dungeon_spr_pal_2_val =
uint8_t& dungeon_spr_pal_2_val =
rom()->paletteset_ids[selected_paletteset_][2];
uint8_t &dungeon_spr_pal_3_val =
uint8_t& dungeon_spr_pal_3_val =
rom()->paletteset_ids[selected_paletteset_][3];
gui::InputHexByte("Dungeon Main", &dungeon_main_palette_val);
@@ -261,13 +261,13 @@ void GfxGroupEditor::DrawPaletteViewer() {
rom()->resource_label()->SelectableLabelWithNameEdit(
false, kPaletteGroupNames[PaletteCategory::kDungeons].data(),
std::to_string(dungeon_main_palette_val), "Unnamed dungeon palette");
auto &palette = *rom()->mutable_palette_group()->dungeon_main.mutable_palette(
auto& palette = *rom()->mutable_palette_group()->dungeon_main.mutable_palette(
rom()->paletteset_ids[selected_paletteset_][0]);
DrawPaletteFromPaletteGroup(palette);
Separator();
gui::InputHexByte("Dungeon Spr Pal 1", &dungeon_spr_pal_1_val);
auto &spr_aux_pal1 =
auto& spr_aux_pal1 =
*rom()->mutable_palette_group()->sprites_aux1.mutable_palette(
rom()->paletteset_ids[selected_paletteset_][1]);
DrawPaletteFromPaletteGroup(spr_aux_pal1);
@@ -278,7 +278,7 @@ void GfxGroupEditor::DrawPaletteViewer() {
Separator();
gui::InputHexByte("Dungeon Spr Pal 2", &dungeon_spr_pal_2_val);
auto &spr_aux_pal2 =
auto& spr_aux_pal2 =
*rom()->mutable_palette_group()->sprites_aux2.mutable_palette(
rom()->paletteset_ids[selected_paletteset_][2]);
DrawPaletteFromPaletteGroup(spr_aux_pal2);
@@ -289,7 +289,7 @@ void GfxGroupEditor::DrawPaletteViewer() {
Separator();
gui::InputHexByte("Dungeon Spr Pal 3", &dungeon_spr_pal_3_val);
auto &spr_aux_pal3 =
auto& spr_aux_pal3 =
*rom()->mutable_palette_group()->sprites_aux3.mutable_palette(
rom()->paletteset_ids[selected_paletteset_][3]);
DrawPaletteFromPaletteGroup(spr_aux_pal3);

View File

@@ -1,31 +1,31 @@
#include "graphics_editor.h"
#include "app/editor/system/editor_card_registry.h"
#include <filesystem>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "app/gui/core/ui_helpers.h"
#include "util/file_util.h"
#include "app/platform/window.h"
#include "app/gfx/resource/arena.h"
#include "app/editor/system/editor_card_registry.h"
#include "app/gfx/core/bitmap.h"
#include "app/gfx/util/compression.h"
#include "app/gfx/util/scad_format.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "app/gfx/resource/arena.h"
#include "app/gfx/types/snes_palette.h"
#include "app/gfx/types/snes_tile.h"
#include "app/gfx/util/compression.h"
#include "app/gfx/util/scad_format.h"
#include "app/gui/canvas/canvas.h"
#include "app/gui/core/color.h"
#include "app/gui/core/icons.h"
#include "app/gui/core/input.h"
#include "app/gui/widgets/asset_browser.h"
#include "app/gui/core/style.h"
#include "app/gui/core/ui_helpers.h"
#include "app/gui/widgets/asset_browser.h"
#include "app/platform/window.h"
#include "app/rom.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "imgui/imgui.h"
#include "imgui/misc/cpp/imgui_stdlib.h"
#include "imgui_memory_editor.h"
#include "util/file_util.h"
#include "util/log.h"
namespace yaze {
@@ -44,47 +44,61 @@ constexpr ImGuiTableFlags kGfxEditTableFlags =
ImGuiTableFlags_SizingFixedFit;
void GraphicsEditor::Initialize() {
if (!dependencies_.card_registry) return;
if (!dependencies_.card_registry)
return;
auto* card_registry = dependencies_.card_registry;
card_registry->RegisterCard({.card_id = "graphics.sheet_editor", .display_name = "Sheet Editor",
.icon = ICON_MD_EDIT, .category = "Graphics",
.shortcut_hint = "Ctrl+Shift+1", .priority = 10});
card_registry->RegisterCard({.card_id = "graphics.sheet_browser", .display_name = "Sheet Browser",
.icon = ICON_MD_VIEW_LIST, .category = "Graphics",
.shortcut_hint = "Ctrl+Shift+2", .priority = 20});
card_registry->RegisterCard({.card_id = "graphics.player_animations", .display_name = "Player Animations",
.icon = ICON_MD_PERSON, .category = "Graphics",
.shortcut_hint = "Ctrl+Shift+3", .priority = 30});
card_registry->RegisterCard({.card_id = "graphics.prototype_viewer", .display_name = "Prototype Viewer",
.icon = ICON_MD_CONSTRUCTION, .category = "Graphics",
.shortcut_hint = "Ctrl+Shift+4", .priority = 40});
card_registry->RegisterCard({.card_id = "graphics.sheet_editor",
.display_name = "Sheet Editor",
.icon = ICON_MD_EDIT,
.category = "Graphics",
.shortcut_hint = "Ctrl+Shift+1",
.priority = 10});
card_registry->RegisterCard({.card_id = "graphics.sheet_browser",
.display_name = "Sheet Browser",
.icon = ICON_MD_VIEW_LIST,
.category = "Graphics",
.shortcut_hint = "Ctrl+Shift+2",
.priority = 20});
card_registry->RegisterCard({.card_id = "graphics.player_animations",
.display_name = "Player Animations",
.icon = ICON_MD_PERSON,
.category = "Graphics",
.shortcut_hint = "Ctrl+Shift+3",
.priority = 30});
card_registry->RegisterCard({.card_id = "graphics.prototype_viewer",
.display_name = "Prototype Viewer",
.icon = ICON_MD_CONSTRUCTION,
.category = "Graphics",
.shortcut_hint = "Ctrl+Shift+4",
.priority = 40});
// Show sheet editor by default when Graphics Editor is activated
card_registry->ShowCard("graphics.sheet_editor");
}
absl::Status GraphicsEditor::Load() {
absl::Status GraphicsEditor::Load() {
gfx::ScopedTimer timer("GraphicsEditor::Load");
// Initialize all graphics sheets with appropriate palettes from ROM
// This ensures textures are created for editing
if (rom()->is_loaded()) {
auto& sheets = gfx::Arena::Get().gfx_sheets();
// Apply default palettes to all sheets based on common SNES ROM structure
// Sheets 0-112: Use overworld/dungeon palettes
// Sheets 113-127: Use sprite palettes
// Sheets 128-222: Use auxiliary/menu palettes
LOG_INFO("GraphicsEditor", "Initializing textures for %d graphics sheets", kNumGfxSheets);
LOG_INFO("GraphicsEditor", "Initializing textures for %d graphics sheets",
kNumGfxSheets);
int sheets_queued = 0;
for (int i = 0; i < kNumGfxSheets; i++) {
if (!sheets[i].is_active() || !sheets[i].surface()) {
continue; // Skip inactive or surface-less sheets
}
// Palettes are now applied during ROM loading in LoadAllGraphicsData()
// Just queue texture creation for sheets that don't have textures yet
if (!sheets[i].texture()) {
@@ -93,29 +107,34 @@ absl::Status GraphicsEditor::Load() {
sheets_queued++;
}
}
LOG_INFO("GraphicsEditor", "Queued texture creation for %d graphics sheets", sheets_queued);
LOG_INFO("GraphicsEditor", "Queued texture creation for %d graphics sheets",
sheets_queued);
}
return absl::OkStatus();
return absl::OkStatus();
}
absl::Status GraphicsEditor::Update() {
if (!dependencies_.card_registry) return absl::OkStatus();
if (!dependencies_.card_registry)
return absl::OkStatus();
auto* card_registry = dependencies_.card_registry;
static gui::EditorCard sheet_editor_card("Sheet Editor", ICON_MD_EDIT);
static gui::EditorCard sheet_browser_card("Sheet Browser", ICON_MD_VIEW_LIST);
static gui::EditorCard player_anims_card("Player Animations", ICON_MD_PERSON);
static gui::EditorCard prototype_card("Prototype Viewer", ICON_MD_CONSTRUCTION);
static gui::EditorCard prototype_card("Prototype Viewer",
ICON_MD_CONSTRUCTION);
sheet_editor_card.SetDefaultSize(900, 700);
sheet_browser_card.SetDefaultSize(400, 600);
player_anims_card.SetDefaultSize(500, 600);
prototype_card.SetDefaultSize(600, 500);
// Sheet Editor Card - Check visibility flag exists and is true before rendering
bool* sheet_editor_visible = card_registry->GetVisibilityFlag("graphics.sheet_editor");
// Sheet Editor Card - Check visibility flag exists and is true before
// rendering
bool* sheet_editor_visible =
card_registry->GetVisibilityFlag("graphics.sheet_editor");
if (sheet_editor_visible && *sheet_editor_visible) {
if (sheet_editor_card.Begin(sheet_editor_visible)) {
status_ = UpdateGfxEdit();
@@ -123,8 +142,10 @@ absl::Status GraphicsEditor::Update() {
sheet_editor_card.End();
}
// Sheet Browser Card - Check visibility flag exists and is true before rendering
bool* sheet_browser_visible = card_registry->GetVisibilityFlag("graphics.sheet_browser");
// Sheet Browser Card - Check visibility flag exists and is true before
// rendering
bool* sheet_browser_visible =
card_registry->GetVisibilityFlag("graphics.sheet_browser");
if (sheet_browser_visible && *sheet_browser_visible) {
if (sheet_browser_card.Begin(sheet_browser_visible)) {
if (asset_browser_.Initialized == false) {
@@ -135,8 +156,10 @@ absl::Status GraphicsEditor::Update() {
sheet_browser_card.End();
}
// Player Animations Card - Check visibility flag exists and is true before rendering
bool* player_anims_visible = card_registry->GetVisibilityFlag("graphics.player_animations");
// Player Animations Card - Check visibility flag exists and is true before
// rendering
bool* player_anims_visible =
card_registry->GetVisibilityFlag("graphics.player_animations");
if (player_anims_visible && *player_anims_visible) {
if (player_anims_card.Begin(player_anims_visible)) {
status_ = UpdateLinkGfxView();
@@ -144,8 +167,10 @@ absl::Status GraphicsEditor::Update() {
player_anims_card.End();
}
// Prototype Viewer Card - Check visibility flag exists and is true before rendering
bool* prototype_visible = card_registry->GetVisibilityFlag("graphics.prototype_viewer");
// Prototype Viewer Card - Check visibility flag exists and is true before
// rendering
bool* prototype_visible =
card_registry->GetVisibilityFlag("graphics.prototype_viewer");
if (prototype_visible && *prototype_visible) {
if (prototype_card.Begin(prototype_visible)) {
status_ = UpdateScadView();
@@ -158,42 +183,42 @@ absl::Status GraphicsEditor::Update() {
}
absl::Status GraphicsEditor::UpdateGfxEdit() {
if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags,
ImVec2(0, 0))) {
for (const auto& name :
{"Tilesheets", "Current Graphics", "Palette Controls"})
ImGui::TableSetupColumn(name);
if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags,
ImVec2(0, 0))) {
for (const auto& name :
{"Tilesheets", "Current Graphics", "Palette Controls"})
ImGui::TableSetupColumn(name);
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
status_ = UpdateGfxSheetList();
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
status_ = UpdateGfxSheetList();
ImGui::TableNextColumn();
if (rom()->is_loaded()) {
DrawGfxEditToolset();
status_ = UpdateGfxTabView();
}
ImGui::TableNextColumn();
if (rom()->is_loaded()) {
status_ = UpdatePaletteColumn();
}
ImGui::TableNextColumn();
if (rom()->is_loaded()) {
DrawGfxEditToolset();
status_ = UpdateGfxTabView();
}
ImGui::EndTable();
ImGui::TableNextColumn();
if (rom()->is_loaded()) {
status_ = UpdatePaletteColumn();
}
}
ImGui::EndTable();
return absl::OkStatus();
}
/**
* @brief Draw the graphics editing toolset with enhanced ROM hacking features
*
*
* Enhanced Features:
* - Multi-tool selection for different editing modes
* - Real-time zoom controls for precise pixel editing
* - Sheet copy/paste operations for ROM graphics management
* - Color picker integration with SNES palette system
* - Tile size controls for 8x8 and 16x16 SNES tiles
*
*
* Performance Notes:
* - Toolset updates are batched to minimize ImGui overhead
* - Color buttons use cached palette data for fast rendering
@@ -254,31 +279,32 @@ void GraphicsEditor::DrawGfxEditToolset() {
// Enhanced palette color picker with SNES-specific features
auto bitmap = gfx::Arena::Get().gfx_sheets()[current_sheet_];
auto palette = bitmap.palette();
// Display palette colors in a grid layout for better ROM hacking workflow
for (int i = 0; i < palette.size(); i++) {
if (i > 0 && i % 8 == 0) {
ImGui::NewLine(); // New row every 8 colors (SNES palette standard)
ImGui::NewLine(); // New row every 8 colors (SNES palette standard)
}
ImGui::SameLine();
// Convert SNES color to ImGui format with proper scaling
auto color = ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f,
palette[i].rgb().z / 255.0f, 1.0f);
auto color =
ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f,
palette[i].rgb().z / 255.0f, 1.0f);
// Enhanced color button with tooltip showing SNES color value
if (ImGui::ColorButton(absl::StrFormat("Palette Color %d", i).c_str(),
color, ImGuiColorEditFlags_NoTooltip)) {
current_color_ = color;
}
// Add tooltip with SNES color information
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("SNES Color: $%04X\nRGB: (%d, %d, %d)",
palette[i].snes(),
static_cast<int>(palette[i].rgb().x),
static_cast<int>(palette[i].rgb().y),
static_cast<int>(palette[i].rgb().z));
ImGui::SetTooltip("SNES Color: $%04X\nRGB: (%d, %d, %d)",
palette[i].snes(),
static_cast<int>(palette[i].rgb().x),
static_cast<int>(palette[i].rgb().y),
static_cast<int>(palette[i].rgb().z));
}
}
@@ -322,7 +348,7 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, &value);
}
auto texture = value.texture();
if (texture) {
graphics_bin_canvas_.draw_list()->AddImage(
@@ -347,8 +373,8 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
ImVec2 rect_min(text_pos.x, text_pos.y);
ImVec2 rect_max(text_pos.x + text_size.x, text_pos.y + text_size.y);
graphics_bin_canvas_.draw_list()->AddRectFilled(rect_min, rect_max,
IM_COL32(0, 125, 0, 128));
graphics_bin_canvas_.draw_list()->AddRectFilled(
rect_min, rect_max, IM_COL32(0, 125, 0, 128));
graphics_bin_canvas_.draw_list()->AddText(
text_pos, IM_COL32(125, 255, 125, 255),
@@ -371,7 +397,7 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
absl::Status GraphicsEditor::UpdateGfxTabView() {
gfx::ScopedTimer timer("graphics_editor_update_gfx_tab_view");
static int next_tab_id = 0;
constexpr ImGuiTabBarFlags kGfxEditTabBarFlags =
ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
@@ -412,22 +438,25 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
auto draw_tile_event = [&]() {
current_sheet_canvas_.DrawTileOnBitmap(tile_size_, &current_bitmap,
current_color_);
// Notify Arena that this sheet has been modified for cross-editor synchronization
gfx::Arena::Get().NotifySheetModified(sheet_id);
// Notify Arena that this sheet has been modified for cross-editor
// synchronization
gfx::Arena::Get().NotifySheetModified(sheet_id);
};
current_sheet_canvas_.UpdateColorPainter(
nullptr, gfx::Arena::Get().mutable_gfx_sheets()->at(sheet_id),
current_color_, draw_tile_event, tile_size_, current_scale_);
// Notify Arena that this sheet has been modified for cross-editor synchronization
// Notify Arena that this sheet has been modified for cross-editor
// synchronization
gfx::Arena::Get().NotifySheetModified(sheet_id);
ImGui::EndChild();
ImGui::EndTabItem();
}
if (!open) release_queue_.push(sheet_id);
if (!open)
release_queue_.push(sheet_id);
}
ImGui::EndTabBar();
@@ -453,7 +482,8 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
current_sheet_ = id;
// ImVec2(0x100, 0x40),
current_sheet_canvas_.UpdateColorPainter(
nullptr, gfx::Arena::Get().mutable_gfx_sheets()->at(id), current_color_,
nullptr, gfx::Arena::Get().mutable_gfx_sheets()->at(id),
current_color_,
[&]() {
},
@@ -478,7 +508,7 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
kPaletteGroupAddressesKeys[edit_palette_group_name_index_]);
auto palette = palette_group.palette(edit_palette_index_);
gui::TextWithSeparators("ROM Palette Management");
// Quick palette presets for common SNES graphics types
ImGui::Text("Quick Presets:");
if (ImGui::Button("Overworld")) {
@@ -499,7 +529,7 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
refresh_graphics_ = true;
}
ImGui::Separator();
// Apply current palette to current sheet
if (ImGui::Button("Apply to Current Sheet") && !open_sheets_.empty()) {
refresh_graphics_ = true;
@@ -517,7 +547,7 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
}
}
ImGui::Separator();
ImGui::SetNextItemWidth(150.f);
ImGui::Combo("Palette Group", (int*)&edit_palette_group_name_index_,
kPaletteGroupAddressesKeys,
@@ -531,7 +561,8 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
palette);
if (refresh_graphics_ && !open_sheets_.empty()) {
auto& current = gfx::Arena::Get().mutable_gfx_sheets()->data()[current_sheet_];
auto& current =
gfx::Arena::Get().mutable_gfx_sheets()->data()[current_sheet_];
if (current.is_active() && current.surface()) {
current.SetPaletteWithTransparent(palette, edit_palette_sub_index_);
// Notify Arena that this sheet has been modified
@@ -613,7 +644,9 @@ absl::Status GraphicsEditor::UpdateScadView() {
status_ = DrawExperimentalFeatures();
}
NEXT_COLUMN() { status_ = DrawPaletteControls(); }
NEXT_COLUMN() {
status_ = DrawPaletteControls();
}
NEXT_COLUMN()
gui::BitmapCanvasPipeline(scr_canvas_, scr_bitmap_, 0x200, 0x200, 0x20,
@@ -908,8 +941,8 @@ absl::Status GraphicsEditor::DecompressImportData(int size) {
}
}
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, &bin_bitmap_);
gfx::Arena::Get().QueueTextureCommand(gfx::Arena::TextureCommandType::UPDATE,
&bin_bitmap_);
gfx_loaded_ = true;
return absl::OkStatus();

View File

@@ -8,13 +8,13 @@
#include "app/editor/palette/palette_editor.h"
#include "app/gfx/core/bitmap.h"
#include "app/gfx/types/snes_tile.h"
#include "app/gui/canvas/canvas.h"
#include "app/gui/app/editor_layout.h"
#include "app/gui/canvas/canvas.h"
#include "app/gui/widgets/asset_browser.h"
#include "app/rom.h"
#include "zelda3/overworld/overworld.h"
#include "imgui/imgui.h"
#include "imgui_memory_editor.h"
#include "zelda3/overworld/overworld.h"
namespace yaze {
namespace editor {
@@ -57,8 +57,8 @@ const std::string kSuperDonkeySprites[] = {
*/
class GraphicsEditor : public Editor {
public:
explicit GraphicsEditor(Rom* rom = nullptr) : rom_(rom) {
type_ = EditorType::kGraphics;
explicit GraphicsEditor(Rom* rom = nullptr) : rom_(rom) {
type_ = EditorType::kGraphics;
}
void Initialize() override;
@@ -71,10 +71,10 @@ class GraphicsEditor : public Editor {
absl::Status Undo() override { return absl::UnimplementedError("Undo"); }
absl::Status Redo() override { return absl::UnimplementedError("Redo"); }
absl::Status Find() override { return absl::UnimplementedError("Find"); }
// Set the ROM pointer
void set_rom(Rom* rom) { rom_ = rom; }
// Get the ROM pointer
Rom* rom() const { return rom_; }

View File

@@ -1,50 +1,65 @@
#include "screen_editor.h"
#include "app/editor/system/editor_card_registry.h"
#include <fstream>
#include <iostream>
#include <string>
#include "absl/strings/str_format.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "util/file_util.h"
#include "app/gfx/resource/arena.h"
#include "app/editor/system/editor_card_registry.h"
#include "app/gfx/core/bitmap.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "app/gfx/resource/arena.h"
#include "app/gfx/types/snes_tile.h"
#include "app/gui/canvas/canvas.h"
#include "app/gui/core/color.h"
#include "app/gui/core/icons.h"
#include "app/gui/core/input.h"
#include "imgui/imgui.h"
#include "util/file_util.h"
#include "util/hex.h"
#include "util/macro.h"
namespace yaze {
namespace editor {
constexpr uint32_t kRedPen = 0xFF0000FF;
void ScreenEditor::Initialize() {
if (!dependencies_.card_registry) return;
if (!dependencies_.card_registry)
return;
auto* card_registry = dependencies_.card_registry;
card_registry->RegisterCard({.card_id = "screen.dungeon_maps", .display_name = "Dungeon Maps",
.icon = ICON_MD_MAP, .category = "Screen",
.shortcut_hint = "Alt+1", .priority = 10});
card_registry->RegisterCard({.card_id = "screen.inventory_menu", .display_name = "Inventory Menu",
.icon = ICON_MD_INVENTORY, .category = "Screen",
.shortcut_hint = "Alt+2", .priority = 20});
card_registry->RegisterCard({.card_id = "screen.overworld_map", .display_name = "Overworld Map",
.icon = ICON_MD_PUBLIC, .category = "Screen",
.shortcut_hint = "Alt+3", .priority = 30});
card_registry->RegisterCard({.card_id = "screen.title_screen", .display_name = "Title Screen",
.icon = ICON_MD_TITLE, .category = "Screen",
.shortcut_hint = "Alt+4", .priority = 40});
card_registry->RegisterCard({.card_id = "screen.naming_screen", .display_name = "Naming Screen",
.icon = ICON_MD_EDIT, .category = "Screen",
.shortcut_hint = "Alt+5", .priority = 50});
card_registry->RegisterCard({.card_id = "screen.dungeon_maps",
.display_name = "Dungeon Maps",
.icon = ICON_MD_MAP,
.category = "Screen",
.shortcut_hint = "Alt+1",
.priority = 10});
card_registry->RegisterCard({.card_id = "screen.inventory_menu",
.display_name = "Inventory Menu",
.icon = ICON_MD_INVENTORY,
.category = "Screen",
.shortcut_hint = "Alt+2",
.priority = 20});
card_registry->RegisterCard({.card_id = "screen.overworld_map",
.display_name = "Overworld Map",
.icon = ICON_MD_PUBLIC,
.category = "Screen",
.shortcut_hint = "Alt+3",
.priority = 30});
card_registry->RegisterCard({.card_id = "screen.title_screen",
.display_name = "Title Screen",
.icon = ICON_MD_TITLE,
.category = "Screen",
.shortcut_hint = "Alt+4",
.priority = 40});
card_registry->RegisterCard({.card_id = "screen.naming_screen",
.display_name = "Naming Screen",
.icon = ICON_MD_EDIT,
.category = "Screen",
.shortcut_hint = "Alt+5",
.priority = 50});
// Show title screen by default
card_registry->ShowCard("screen.title_screen");
}
@@ -76,45 +91,48 @@ absl::Status ScreenEditor::Load() {
const int tile8_width = 128;
const int tile8_height = 128; // 4 sheets × 32 pixels each
std::vector<uint8_t> tile8_data(tile8_width * tile8_height);
// Copy data from all 4 sheets into the combined bitmap
for (int sheet_idx = 0; sheet_idx < 4; sheet_idx++) {
const auto& sheet = sheets_[sheet_idx];
int dest_y_offset = sheet_idx * 32; // Each sheet is 32 pixels tall
for (int y = 0; y < 32; y++) {
for (int x = 0; x < 128; x++) {
int src_index = y * 128 + x;
int dest_index = (dest_y_offset + y) * 128 + x;
if (src_index < sheet.size() && dest_index < tile8_data.size()) {
tile8_data[dest_index] = sheet.data()[src_index];
}
}
}
}
// Create tilemap with 8x8 tile size
tile8_tilemap_.tile_size = {8, 8};
tile8_tilemap_.map_size = {256, 256}; // Logical size for tile count
tile8_tilemap_.atlas.Create(tile8_width, tile8_height, 8, tile8_data);
tile8_tilemap_.atlas.SetPalette(*rom()->mutable_dungeon_palette(3));
// Queue single texture creation for the atlas (not individual tiles)
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, &tile8_tilemap_.atlas);
gfx::Arena::Get().QueueTextureCommand(gfx::Arena::TextureCommandType::CREATE,
&tile8_tilemap_.atlas);
return absl::OkStatus();
}
absl::Status ScreenEditor::Update() {
if (!dependencies_.card_registry) return absl::OkStatus();
if (!dependencies_.card_registry)
return absl::OkStatus();
auto* card_registry = dependencies_.card_registry;
static gui::EditorCard dungeon_maps_card("Dungeon Maps", ICON_MD_MAP);
static gui::EditorCard inventory_menu_card("Inventory Menu", ICON_MD_INVENTORY);
static gui::EditorCard inventory_menu_card("Inventory Menu",
ICON_MD_INVENTORY);
static gui::EditorCard overworld_map_card("Overworld Map", ICON_MD_PUBLIC);
static gui::EditorCard title_screen_card("Title Screen", ICON_MD_TITLE);
static gui::EditorCard naming_screen_card("Naming Screen", ICON_MD_EDIT_ATTRIBUTES);
static gui::EditorCard naming_screen_card("Naming Screen",
ICON_MD_EDIT_ATTRIBUTES);
dungeon_maps_card.SetDefaultSize(800, 600);
inventory_menu_card.SetDefaultSize(800, 600);
@@ -122,44 +140,54 @@ absl::Status ScreenEditor::Update() {
title_screen_card.SetDefaultSize(600, 500);
naming_screen_card.SetDefaultSize(500, 400);
// Dungeon Maps Card - Check visibility flag exists and is true before rendering
bool* dungeon_maps_visible = card_registry->GetVisibilityFlag("screen.dungeon_maps");
// Dungeon Maps Card - Check visibility flag exists and is true before
// rendering
bool* dungeon_maps_visible =
card_registry->GetVisibilityFlag("screen.dungeon_maps");
if (dungeon_maps_visible && *dungeon_maps_visible) {
if (dungeon_maps_card.Begin(dungeon_maps_visible)) {
DrawDungeonMapsEditor();
}
dungeon_maps_card.End();
}
// Inventory Menu Card - Check visibility flag exists and is true before rendering
bool* inventory_menu_visible = card_registry->GetVisibilityFlag("screen.inventory_menu");
// Inventory Menu Card - Check visibility flag exists and is true before
// rendering
bool* inventory_menu_visible =
card_registry->GetVisibilityFlag("screen.inventory_menu");
if (inventory_menu_visible && *inventory_menu_visible) {
if (inventory_menu_card.Begin(inventory_menu_visible)) {
DrawInventoryMenuEditor();
}
inventory_menu_card.End();
}
// Overworld Map Card - Check visibility flag exists and is true before rendering
bool* overworld_map_visible = card_registry->GetVisibilityFlag("screen.overworld_map");
// Overworld Map Card - Check visibility flag exists and is true before
// rendering
bool* overworld_map_visible =
card_registry->GetVisibilityFlag("screen.overworld_map");
if (overworld_map_visible && *overworld_map_visible) {
if (overworld_map_card.Begin(overworld_map_visible)) {
DrawOverworldMapEditor();
}
overworld_map_card.End();
}
// Title Screen Card - Check visibility flag exists and is true before rendering
bool* title_screen_visible = card_registry->GetVisibilityFlag("screen.title_screen");
// Title Screen Card - Check visibility flag exists and is true before
// rendering
bool* title_screen_visible =
card_registry->GetVisibilityFlag("screen.title_screen");
if (title_screen_visible && *title_screen_visible) {
if (title_screen_card.Begin(title_screen_visible)) {
DrawTitleScreenEditor();
}
title_screen_card.End();
}
// Naming Screen Card - Check visibility flag exists and is true before rendering
bool* naming_screen_visible = card_registry->GetVisibilityFlag("screen.naming_screen");
// Naming Screen Card - Check visibility flag exists and is true before
// rendering
bool* naming_screen_visible =
card_registry->GetVisibilityFlag("screen.naming_screen");
if (naming_screen_visible && *naming_screen_visible) {
if (naming_screen_card.Begin(naming_screen_visible)) {
DrawNamingScreenEditor();
@@ -176,58 +204,58 @@ void ScreenEditor::DrawToolset() {
}
void ScreenEditor::DrawInventoryMenuEditor() {
static bool create = false;
if (!create && rom()->is_loaded()) {
status_ = inventory_.Create(rom());
if (status_.ok()) {
palette_ = inventory_.palette();
create = true;
} else {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Error loading inventory: %s",
status_.message().data());
return;
}
static bool create = false;
if (!create && rom()->is_loaded()) {
status_ = inventory_.Create(rom());
if (status_.ok()) {
palette_ = inventory_.palette();
create = true;
} else {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Error loading inventory: %s",
status_.message().data());
return;
}
}
DrawInventoryToolset();
DrawInventoryToolset();
if (ImGui::BeginTable("InventoryScreen", 4, ImGuiTableFlags_Resizable)) {
ImGui::TableSetupColumn("Canvas");
ImGui::TableSetupColumn("Tilesheet");
ImGui::TableSetupColumn("Item Icons");
ImGui::TableSetupColumn("Palette");
ImGui::TableHeadersRow();
if (ImGui::BeginTable("InventoryScreen", 4, ImGuiTableFlags_Resizable)) {
ImGui::TableSetupColumn("Canvas");
ImGui::TableSetupColumn("Tilesheet");
ImGui::TableSetupColumn("Item Icons");
ImGui::TableSetupColumn("Palette");
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
screen_canvas_.DrawBackground();
screen_canvas_.DrawContextMenu();
screen_canvas_.DrawBitmap(inventory_.bitmap(), 2, create);
screen_canvas_.DrawGrid(32.0f);
screen_canvas_.DrawOverlay();
ImGui::TableNextColumn();
screen_canvas_.DrawBackground();
screen_canvas_.DrawContextMenu();
screen_canvas_.DrawBitmap(inventory_.bitmap(), 2, create);
screen_canvas_.DrawGrid(32.0f);
screen_canvas_.DrawOverlay();
ImGui::TableNextColumn();
tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
tilesheet_canvas_.DrawContextMenu();
tilesheet_canvas_.DrawBitmap(inventory_.tilesheet(), 2, create);
tilesheet_canvas_.DrawGrid(16.0f);
tilesheet_canvas_.DrawOverlay();
ImGui::TableNextColumn();
tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
tilesheet_canvas_.DrawContextMenu();
tilesheet_canvas_.DrawBitmap(inventory_.tilesheet(), 2, create);
tilesheet_canvas_.DrawGrid(16.0f);
tilesheet_canvas_.DrawOverlay();
ImGui::TableNextColumn();
DrawInventoryItemIcons();
ImGui::TableNextColumn();
DrawInventoryItemIcons();
ImGui::TableNextColumn();
gui::DisplayPalette(palette_, create);
ImGui::TableNextColumn();
gui::DisplayPalette(palette_, create);
ImGui::EndTable();
}
ImGui::Separator();
ImGui::EndTable();
}
ImGui::Separator();
// TODO(scawful): Future Oracle of Secrets menu editor integration
// - Full inventory screen layout editor
// - Item slot assignment and positioning
// - Heart container and magic meter editor
// - Equipment display customization
// - A/B button equipment quick-select editor
// TODO(scawful): Future Oracle of Secrets menu editor integration
// - Full inventory screen layout editor
// - Item slot assignment and positioning
// - Heart container and magic meter editor
// - Equipment display customization
// - A/B button equipment quick-select editor
}
void ScreenEditor::DrawInventoryToolset() {
@@ -283,8 +311,9 @@ void ScreenEditor::DrawInventoryItemIcons() {
auto& icons = inventory_.item_icons();
if (icons.empty()) {
ImGui::TextWrapped("No item icons loaded. Icons will be loaded when the "
"inventory is initialized.");
ImGui::TextWrapped(
"No item icons loaded. Icons will be loaded when the "
"inventory is initialized.");
ImGui::EndChild();
return;
}
@@ -366,11 +395,12 @@ void ScreenEditor::DrawDungeonMapScreen(int i) {
const int tiles_per_row = tile16_blockset_.atlas.width() / 16;
const int tile_x = (tile16_id % tiles_per_row) * 16;
const int tile_y = (tile16_id / tiles_per_row) * 16;
std::vector<uint8_t> tile_data(16 * 16);
int tile_data_offset = 0;
tile16_blockset_.atlas.Get16x16Tile(tile_x, tile_y, tile_data, tile_data_offset);
tile16_blockset_.atlas.Get16x16Tile(tile_x, tile_y, tile_data,
tile_data_offset);
// Create or update cached tile
auto* cached_tile = tile16_blockset_.tile_cache.GetTile(tile16_id);
if (!cached_tile) {
@@ -383,7 +413,7 @@ void ScreenEditor::DrawDungeonMapScreen(int i) {
// Update existing cached tile data
cached_tile->set_data(tile_data);
}
if (cached_tile && cached_tile->is_active()) {
// Ensure the cached tile has a valid texture
if (!cached_tile->texture()) {
@@ -488,14 +518,14 @@ void ScreenEditor::DrawDungeonMapsTabs() {
/**
* @brief Draw dungeon room graphics editor with enhanced tile16 editing
*
*
* Enhanced Features:
* - Interactive tile16 selector with visual feedback
* - Real-time tile16 composition from 4x 8x8 tiles
* - Tile metadata editing (mirroring, palette, etc.)
* - Integration with ROM graphics buffer
* - Undo/redo support for tile modifications
*
*
* Performance Notes:
* - Cached tile16 rendering to avoid repeated composition
* - Efficient tile selector with grid-based snapping
@@ -535,17 +565,18 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() {
ImGui::Separator();
current_tile_canvas_.DrawBackground(); // ImVec2(64 * 2 + 2, 64 * 2 + 4));
current_tile_canvas_.DrawContextMenu();
// Get tile8 from cache on-demand (only create texture when needed)
if (selected_tile8_ >= 0 && selected_tile8_ < 256) {
auto* cached_tile8 = tile8_tilemap_.tile_cache.GetTile(selected_tile8_);
if (!cached_tile8) {
// Extract tile from atlas and cache it
const int tiles_per_row = tile8_tilemap_.atlas.width() / 8; // 128 / 8 = 16
const int tiles_per_row =
tile8_tilemap_.atlas.width() / 8; // 128 / 8 = 16
const int tile_x = (selected_tile8_ % tiles_per_row) * 8;
const int tile_y = (selected_tile8_ / tiles_per_row) * 8;
// Extract 8x8 tile data from atlas
std::vector<uint8_t> tile_data(64);
for (int py = 0; py < 8; py++) {
@@ -554,28 +585,30 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() {
int src_y = tile_y + py;
int src_index = src_y * tile8_tilemap_.atlas.width() + src_x;
int dst_index = py * 8 + px;
if (src_index < tile8_tilemap_.atlas.size() && dst_index < 64) {
tile_data[dst_index] = tile8_tilemap_.atlas.data()[src_index];
}
}
}
gfx::Bitmap new_tile8(8, 8, 8, tile_data);
new_tile8.SetPalette(tile8_tilemap_.atlas.palette());
tile8_tilemap_.tile_cache.CacheTile(selected_tile8_, std::move(new_tile8));
tile8_tilemap_.tile_cache.CacheTile(selected_tile8_,
std::move(new_tile8));
cached_tile8 = tile8_tilemap_.tile_cache.GetTile(selected_tile8_);
}
if (cached_tile8 && cached_tile8->is_active()) {
// Create texture on-demand only when needed
if (!cached_tile8->texture()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, cached_tile8);
}
if (current_tile_canvas_.DrawTilePainter(*cached_tile8, 16)) {
// Modify the tile16 based on the selected tile and current_tile16_info
// Modify the tile16 based on the selected tile and
// current_tile16_info
gfx::ModifyTile16(tile16_blockset_, rom()->graphics_buffer(),
current_tile16_info[0], current_tile16_info[1],
current_tile16_info[2], current_tile16_info[3], 212,
@@ -618,14 +651,14 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() {
/**
* @brief Draw dungeon maps editor with enhanced ROM hacking features
*
*
* Enhanced Features:
* - Multi-mode editing (DRAW, EDIT, SELECT)
* - Real-time tile16 preview and editing
* - Floor/basement management for complex dungeons
* - Copy/paste operations for floor layouts
* - Integration with ROM tile16 data
*
*
* Performance Notes:
* - Lazy loading of dungeon graphics
* - Cached tile16 rendering for fast updates
@@ -775,13 +808,14 @@ void ScreenEditor::DrawTitleScreenEditor() {
ImGui::Checkbox("Show BG1", &show_title_bg1_);
ImGui::SameLine();
ImGui::Checkbox("Show BG2", &show_title_bg2_);
// Re-render composite if visibility changed
if (prev_bg1 != show_title_bg1_ || prev_bg2 != show_title_bg2_) {
status_ = title_screen_.RenderCompositeLayer(show_title_bg1_, show_title_bg2_);
status_ =
title_screen_.RenderCompositeLayer(show_title_bg1_, show_title_bg2_);
if (status_.ok()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE,
gfx::Arena::TextureCommandType::UPDATE,
&title_screen_.composite_bitmap());
}
}
@@ -822,27 +856,30 @@ void ScreenEditor::DrawTitleScreenCompositeCanvas() {
auto click_pos = title_bg1_canvas_.points().front();
int tile_x = static_cast<int>(click_pos.x) / 8;
int tile_y = static_cast<int>(click_pos.y) / 8;
if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
int tilemap_index = tile_y * 32 + tile_x;
// Create tile word: tile_id | (palette << 10) | h_flip | v_flip
uint16_t tile_word = selected_title_tile16_ & 0x3FF;
tile_word |= (title_palette_ & 0x07) << 10;
if (title_h_flip_) tile_word |= 0x4000;
if (title_v_flip_) tile_word |= 0x8000;
if (title_h_flip_)
tile_word |= 0x4000;
if (title_v_flip_)
tile_word |= 0x8000;
// Update BG1 buffer and re-render both layers and composite
title_screen_.mutable_bg1_buffer()[tilemap_index] = tile_word;
status_ = title_screen_.RenderBG1Layer();
if (status_.ok()) {
// Update BG1 texture
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE,
gfx::Arena::TextureCommandType::UPDATE,
&title_screen_.bg1_bitmap());
// Re-render and update composite
status_ = title_screen_.RenderCompositeLayer(show_title_bg1_, show_title_bg2_);
status_ = title_screen_.RenderCompositeLayer(show_title_bg1_,
show_title_bg2_);
if (status_.ok()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, &composite_bitmap);
@@ -874,16 +911,18 @@ void ScreenEditor::DrawTitleScreenBG1Canvas() {
auto click_pos = title_bg1_canvas_.points().front();
int tile_x = static_cast<int>(click_pos.x) / 8;
int tile_y = static_cast<int>(click_pos.y) / 8;
if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
int tilemap_index = tile_y * 32 + tile_x;
// Create tile word: tile_id | (palette << 10) | h_flip | v_flip
uint16_t tile_word = selected_title_tile16_ & 0x3FF;
tile_word |= (title_palette_ & 0x07) << 10;
if (title_h_flip_) tile_word |= 0x4000;
if (title_v_flip_) tile_word |= 0x8000;
if (title_h_flip_)
tile_word |= 0x4000;
if (title_v_flip_)
tile_word |= 0x8000;
// Update buffer and re-render
title_screen_.mutable_bg1_buffer()[tilemap_index] = tile_word;
status_ = title_screen_.RenderBG1Layer();
@@ -917,16 +956,18 @@ void ScreenEditor::DrawTitleScreenBG2Canvas() {
auto click_pos = title_bg2_canvas_.points().front();
int tile_x = static_cast<int>(click_pos.x) / 8;
int tile_y = static_cast<int>(click_pos.y) / 8;
if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
int tilemap_index = tile_y * 32 + tile_x;
// Create tile word: tile_id | (palette << 10) | h_flip | v_flip
uint16_t tile_word = selected_title_tile16_ & 0x3FF;
tile_word |= (title_palette_ & 0x07) << 10;
if (title_h_flip_) tile_word |= 0x4000;
if (title_v_flip_) tile_word |= 0x8000;
if (title_h_flip_)
tile_word |= 0x4000;
if (title_v_flip_)
tile_word |= 0x8000;
// Update buffer and re-render
title_screen_.mutable_bg2_buffer()[tilemap_index] = tile_word;
status_ = title_screen_.RenderBG2Layer();
@@ -971,20 +1012,19 @@ void ScreenEditor::DrawTitleScreenBlocksetSelector() {
// Show selected tile preview and controls
if (selected_title_tile16_ >= 0) {
ImGui::Text("Selected Tile: %d", selected_title_tile16_);
// Flip controls
ImGui::Checkbox("H Flip", &title_h_flip_);
ImGui::SameLine();
ImGui::Checkbox("V Flip", &title_v_flip_);
// Palette selector (0-7 for 3BPP graphics)
ImGui::SetNextItemWidth(100);
ImGui::SliderInt("Palette", &title_palette_, 0, 7);
}
}
void ScreenEditor::DrawNamingScreenEditor() {
}
void ScreenEditor::DrawNamingScreenEditor() {}
void ScreenEditor::DrawOverworldMapEditor() {
// Initialize overworld map on first draw
@@ -1015,7 +1055,7 @@ void ScreenEditor::DrawOverworldMapEditor() {
}
}
ImGui::SameLine();
// World toggle
if (ImGui::Button(ow_show_dark_world_ ? "Dark World" : "Light World")) {
ow_show_dark_world_ = !ow_show_dark_world_;
@@ -1027,7 +1067,7 @@ void ScreenEditor::DrawOverworldMapEditor() {
}
}
ImGui::SameLine();
// Custom map load/save buttons
if (ImGui::Button("Load Custom Map...")) {
std::string path = util::FileDialogWrapper::ShowOpenFileDialog();
@@ -1048,10 +1088,10 @@ void ScreenEditor::DrawOverworldMapEditor() {
}
}
}
ImGui::SameLine();
ImGui::Text("Selected Tile: %d", selected_ow_tile_);
// Custom map error/success popups
if (ImGui::BeginPopup("CustomMapLoadError")) {
ImGui::Text("Error loading custom map: %s", status_.message().data());
@@ -1093,17 +1133,17 @@ void ScreenEditor::DrawOverworldMapEditor() {
auto click_pos = ow_map_canvas_.points().front();
int tile_x = static_cast<int>(click_pos.x) / 8;
int tile_y = static_cast<int>(click_pos.y) / 8;
if (tile_x >= 0 && tile_x < 64 && tile_y >= 0 && tile_y < 64) {
int tile_index = tile_x + (tile_y * 64);
// Update appropriate world's tile data
if (ow_show_dark_world_) {
ow_map_screen_.mutable_dw_tiles()[tile_index] = selected_ow_tile_;
} else {
ow_map_screen_.mutable_lw_tiles()[tile_index] = selected_ow_tile_;
}
// Re-render map
status_ = ow_map_screen_.RenderMapLayer(ow_show_dark_world_);
if (status_.ok()) {
@@ -1143,7 +1183,7 @@ void ScreenEditor::DrawOverworldMapEditor() {
// Column 3: Palette Display
ImGui::TableNextColumn();
auto& palette = ow_show_dark_world_ ? ow_map_screen_.dw_palette()
auto& palette = ow_show_dark_world_ ? ow_map_screen_.dw_palette()
: ow_map_screen_.lw_palette();
// Use inline palette editor for full 128-color palette
gui::InlinePaletteEditor(palette, "Overworld Map Palette");

View File

@@ -6,16 +6,16 @@
#include "absl/status/status.h"
#include "app/editor/editor.h"
#include "app/gfx/core/bitmap.h"
#include "app/gfx/types/snes_palette.h"
#include "app/gfx/render/tilemap.h"
#include "app/gfx/types/snes_palette.h"
#include "app/gui/app/editor_layout.h"
#include "app/gui/canvas/canvas.h"
#include "app/rom.h"
#include "imgui/imgui.h"
#include "zelda3/screen/dungeon_map.h"
#include "zelda3/screen/inventory.h"
#include "zelda3/screen/title_screen.h"
#include "zelda3/screen/overworld_map_screen.h"
#include "app/gui/app/editor_layout.h"
#include "imgui/imgui.h"
#include "zelda3/screen/title_screen.h"
namespace yaze {
namespace editor {
@@ -120,8 +120,7 @@ class ScreenEditor : public Editor {
gui::Canvas title_bg2_canvas_{"##TitleBG2Canvas", ImVec2(256, 256),
gui::CanvasGridSize::k8x8, 2.0f};
// Blockset is 128 pixels wide x 512 pixels tall (16x64 8x8 tiles)
gui::Canvas title_blockset_canvas_{"##TitleBlocksetCanvas",
ImVec2(128, 512),
gui::Canvas title_blockset_canvas_{"##TitleBlocksetCanvas", ImVec2(128, 512),
gui::CanvasGridSize::k8x8, 2.0f};
zelda3::Inventory inventory_;