9#include "absl/strings/str_format.h"
22#include "imgui/imgui.h"
36 {.card_id =
"screen.dungeon_maps",
37 .display_name =
"Dungeon Maps",
38 .window_title =
" Dungeon Map Editor",
41 .shortcut_hint =
"Alt+1",
43 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
44 .disabled_tooltip =
"Load a ROM first"});
45 window_manager->RegisterPanel(
46 {.card_id =
"screen.inventory_menu",
47 .display_name =
"Inventory Menu",
48 .window_title =
" Inventory Menu",
51 .shortcut_hint =
"Alt+2",
53 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
54 .disabled_tooltip =
"Load a ROM first"});
55 window_manager->RegisterPanel(
56 {.card_id =
"screen.overworld_map",
57 .display_name =
"Overworld Map",
58 .window_title =
" Overworld Map",
61 .shortcut_hint =
"Alt+3",
63 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
64 .disabled_tooltip =
"Load a ROM first"});
65 window_manager->RegisterPanel(
66 {.card_id =
"screen.title_screen",
67 .display_name =
"Title Screen",
68 .window_title =
" Title Screen",
71 .shortcut_hint =
"Alt+4",
73 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
74 .disabled_tooltip =
"Load a ROM first"});
75 window_manager->RegisterPanel(
76 {.card_id =
"screen.naming_screen",
77 .display_name =
"Naming Screen",
78 .window_title =
" Naming Screen",
81 .shortcut_hint =
"Alt+5",
83 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
84 .disabled_tooltip =
"Load a ROM first"});
87 window_manager->RegisterWindowContent(std::make_unique<DungeonMapsPanel>(
89 window_manager->RegisterWindowContent(std::make_unique<InventoryMenuPanel>(
91 window_manager->RegisterWindowContent(
92 std::make_unique<OverworldMapScreenPanel>(
94 window_manager->RegisterWindowContent(std::make_unique<TitleScreenPanel>(
96 window_manager->RegisterWindowContent(std::make_unique<NamingScreenPanel>(
100 window_manager->OpenWindow(
"screen.title_screen");
124 for (
int i = 0; i < 4; i++) {
126 *
game_data()->palette_groups.dungeon_main.mutable_palette(3));
134 const int tile8_width = 128;
135 const int tile8_height = 128;
136 std::vector<uint8_t> tile8_data(tile8_width * tile8_height);
139 for (
int sheet_idx = 0; sheet_idx < 4; sheet_idx++) {
140 const auto& sheet = *
sheets_[sheet_idx];
141 int dest_y_offset = sheet_idx * 32;
143 for (
int y = 0; y < 32; y++) {
144 for (
int x = 0; x < 128; x++) {
145 int src_index = y * 128 + x;
146 int dest_index = (dest_y_offset + y) * 128 + x;
148 if (src_index < sheet.size() && dest_index < tile8_data.size()) {
149 tile8_data[dest_index] = sheet.data()[src_index];
165 return absl::OkStatus();
175 return absl::OkStatus();
198 ImGui::TextColored(theme.text_error_red,
199 tr(
"Error loading inventory: %s"),
207 if (ImGui::BeginTable(
"InventoryScreen", 4, ImGuiTableFlags_Resizable)) {
208 ImGui::TableSetupColumn(
"Canvas");
209 ImGui::TableSetupColumn(
"Tilesheet");
210 ImGui::TableSetupColumn(
"Item Icons");
211 ImGui::TableSetupColumn(
"Palette");
212 ImGui::TableHeadersRow();
214 ImGui::TableNextColumn();
226 ImGui::TableNextColumn();
229 frame_opts.
canvas_size = ImVec2(128 * 2 + 2, (192 * 2) + 4);
239 ImGui::TableNextColumn();
242 ImGui::TableNextColumn();
258 if (ImGui::BeginTable(
"InventoryToolset", 8, ImGuiTableFlags_SizingFixedFit,
260 ImGui::TableSetupColumn(
"#drawTool");
261 ImGui::TableSetupColumn(
"#sep1");
262 ImGui::TableSetupColumn(
"#zoomOut");
263 ImGui::TableSetupColumn(
"#zoomIN");
264 ImGui::TableSetupColumn(
"#sep2");
265 ImGui::TableSetupColumn(
"#bg2Tool");
266 ImGui::TableSetupColumn(
"#bg3Tool");
267 ImGui::TableSetupColumn(
"#itemTool");
269 ImGui::TableNextColumn();
274 ImGui::EndDisabled();
275 ImGui::TableNextColumn();
280 ImGui::EndDisabled();
281 ImGui::TableNextColumn();
283 ImGui::TableNextColumn();
287 ImGui::TableNextColumn();
291 ImGui::TableNextColumn();
293 ImGui::TableNextColumn();
297 ImGui::TableNextColumn();
307 if (ImGui::BeginChild(
"##ItemIconsList", ImVec2(0, 0),
true,
308 ImGuiWindowFlags_HorizontalScrollbar)) {
309 ImGui::Text(tr(
"Item Icons (2x2 tiles each)"));
315 tr(
"No item icons loaded. Icons will be loaded when the "
316 "inventory is initialized."));
322 if (ImGui::BeginTable(
"##IconsTable", 2,
323 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
324 ImGui::TableSetupColumn(
"Icon Name");
325 ImGui::TableSetupColumn(
"Tile Data");
326 ImGui::TableHeadersRow();
328 for (
size_t i = 0; i < icons.size(); i++) {
329 const auto& icon = icons[i];
331 ImGui::TableNextRow();
332 ImGui::TableNextColumn();
335 if (ImGui::Selectable(icon.name.c_str(),
false,
336 ImGuiSelectableFlags_SpanAllColumns)) {
340 ImGui::TableNextColumn();
342 ImGui::Text(tr(
"TL:%04X TR:%04X"), icon.tile_tl, icon.tile_tr);
344 ImGui::Text(tr(
"BL:%04X BR:%04X"), icon.tile_bl, icon.tile_br);
351 ImGui::TextWrapped(tr(
352 "NOTE: Individual icon editing will be implemented in the future "
353 "Oracle of Secrets menu editor. Each icon is composed of 4 tile words "
354 "representing a 2x2 arrangement of 8x8 tiles in SNES tile format "
355 "(vhopppcc cccccccc)."));
373 auto boss_room = current_dungeon.boss_room;
376 std::vector<int> tile_ids_to_render;
377 std::vector<ImVec2> tile_positions;
382 if (current_dungeon.floor_rooms[
floor_number][j] != 0x0F) {
383 int tile16_id = current_dungeon.floor_gfx[
floor_number][j];
384 int posX = ((j % 5) * 32);
385 int posY = ((j / 5) * 32);
388 tile_ids_to_render.push_back(tile16_id);
389 tile_positions.emplace_back(posX * 2, posY * 2);
394 for (
size_t idx = 0; idx < tile_ids_to_render.size(); ++idx) {
395 int tile16_id = tile_ids_to_render[idx];
396 ImVec2 pos = tile_positions[idx];
400 const int tile_x = (tile16_id % tiles_per_row) * 16;
401 const int tile_y = (tile16_id / tiles_per_row) * 16;
403 std::vector<uint8_t> tile_data(16 * 16);
404 int tile_data_offset = 0;
421 if (cached_tile && cached_tile->is_active()) {
423 if (!cached_tile->texture()) {
434 if (current_dungeon.floor_rooms[
floor_number][j] != 0x0F) {
435 int posX = ((j % 5) * 32);
436 int posY = ((j / 5) * 32);
438 if (current_dungeon.floor_rooms[
floor_number][j] == boss_room) {
466 current_dungeon.nbr_of_floor + current_dungeon.nbr_of_basement;
467 for (
int i = 0; i < nbr_floors; i++) {
468 int basement_num = current_dungeon.nbr_of_basement - i;
469 std::string tab_name = absl::StrFormat(
"Basement %d", basement_num);
470 if (i >= current_dungeon.nbr_of_basement) {
471 tab_name = absl::StrFormat(
"Floor %d",
472 i - current_dungeon.nbr_of_basement + 1);
474 if (ImGui::BeginTabItem(tab_name.data())) {
491 "Edit room assignment"));
506 const auto button_size = ImVec2(130, 0);
508 if (ImGui::Button(tr(
"Add Floor"), button_size) &&
509 current_dungeon.nbr_of_floor < 8) {
511 current_dungeon.nbr_of_floor++;
516 if (ImGui::Button(tr(
"Remove Floor"), button_size) &&
517 current_dungeon.nbr_of_floor > 0) {
519 current_dungeon.nbr_of_floor--;
524 if (ImGui::Button(tr(
"Add Basement"), button_size) &&
525 current_dungeon.nbr_of_basement < 8) {
527 current_dungeon.nbr_of_basement++;
532 if (ImGui::Button(tr(
"Remove Basement"), button_size) &&
533 current_dungeon.nbr_of_basement > 0) {
535 current_dungeon.nbr_of_basement--;
540 if (ImGui::Button(tr(
"Copy Floor"), button_size)) {
544 if (ImGui::Button(tr(
"Paste Floor"), button_size)) {
568 if (ImGui::BeginChild(
"##DungeonMapTiles", ImVec2(0, 0),
true)) {
572 tilesheet_opts.
canvas_size = ImVec2((256 * 2) + 2, (192 * 2) + 4);
588 ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
626 auto current_tile_rt =
635 const int tiles_per_row =
641 std::vector<uint8_t> tile_data(64);
642 for (
int py = 0; py < 8; py++) {
643 for (
int px = 0; px < 8; px++) {
644 int src_x = tile_x + px;
645 int src_y = tile_y + py;
647 int dst_index = py * 8 + px;
658 std::move(new_tile8));
662 if (cached_tile8 && cached_tile8->is_active()) {
664 if (!cached_tile8->texture()) {
686 auto* selected_tile =
688 if (selected_tile && selected_tile->is_active()) {
690 if (!selected_tile->texture()) {
707 if (ImGui::Button(tr(
"Modify Tile16"))) {
751 static std::vector<std::string> dungeon_names = {
752 "Sewers/Sanctuary",
"Hyrule Castle",
"Eastern Palace",
753 "Desert Palace",
"Tower of Hera",
"Agahnim's Tower",
754 "Palace of Darkness",
"Swamp Palace",
"Skull Woods",
755 "Thieves' Town",
"Ice Palace",
"Misery Mire",
756 "Turtle Rock",
"Ganon's Tower"};
758 if (ImGui::BeginTable(
"DungeonMapsTable", 4,
759 ImGuiTableFlags_Resizable |
760 ImGuiTableFlags_Reorderable |
761 ImGuiTableFlags_Hideable)) {
762 ImGui::TableSetupColumn(
"Dungeon");
763 ImGui::TableSetupColumn(
"Map");
764 ImGui::TableSetupColumn(
"Rooms Gfx");
765 ImGui::TableSetupColumn(
"Tiles Gfx");
766 ImGui::TableHeadersRow();
768 ImGui::TableNextColumn();
769 for (
int i = 0; i < dungeon_names.size(); i++) {
773 if (ImGui::IsItemClicked()) {
778 ImGui::TableNextColumn();
781 ImGui::TableNextColumn();
784 ImGui::TableNextColumn();
798 ImGui::Text(tr(
"For use with custom inserted graphics assembly patches."));
799 if (ImGui::Button(tr(
"Load GFX from BIN file")))
808 if (!bin_file.empty()) {
809 std::ifstream file(bin_file, std::ios::binary);
810 if (file.is_open()) {
812 std::vector<uint8_t> bin_data((std::istreambuf_iterator<char>(file)),
813 std::istreambuf_iterator<char>());
819 std::vector<std::vector<uint8_t>> gfx_sheets;
820 for (
int i = 0; i < 4; i++) {
821 gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000),
822 converted_bin.begin() + ((i + 1) * 0x1000));
823 sheets_[i] = std::make_unique<gfx::Bitmap>(128, 32, 8, gfx_sheets[i]);
825 *
game_data()->palette_groups.dungeon_main.mutable_palette(3));
832 status_ = absl::InternalError(
"Failed to load dungeon map tile16");
845 ImGui::TextColored(theme.text_error_red,
846 tr(
"Error loading title screen: %s"),
854 ImGui::Text(tr(
"Title screen not loaded. Ensure ROM is loaded."));
866 ImGui::OpenPopup(
"SaveSuccess");
873 if (ImGui::BeginPopup(
"SaveSuccess")) {
874 ImGui::Text(tr(
"Title screen saved successfully!"));
897 if (ImGui::BeginTable(
"TitleScreenTable", 2,
898 ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders)) {
899 ImGui::TableSetupColumn(
"Title Screen (Composite)");
900 ImGui::TableSetupColumn(
"Tile Selector");
901 ImGui::TableHeadersRow();
904 ImGui::TableNextColumn();
908 ImGui::TableNextColumn();
933 if (composite_bitmap.is_active()) {
942 int tile_x =
static_cast<int>(click_pos.x) / 8;
943 int tile_y =
static_cast<int>(click_pos.y) / 8;
945 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
946 int tilemap_index = tile_y * 32 + tile_x;
988 if (bg1_bitmap.is_active()) {
997 int tile_x =
static_cast<int>(click_pos.x) / 8;
998 int tile_y =
static_cast<int>(click_pos.y) / 8;
1000 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
1001 int tilemap_index = tile_y * 32 + tile_x;
1007 tile_word |= 0x4000;
1009 tile_word |= 0x8000;
1034 if (bg2_bitmap.is_active()) {
1043 int tile_x =
static_cast<int>(click_pos.x) / 8;
1044 int tile_y =
static_cast<int>(click_pos.y) / 8;
1046 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
1047 int tilemap_index = tile_y * 32 + tile_x;
1053 tile_word |= 0x4000;
1055 tile_word |= 0x8000;
1080 if (tiles8_bitmap.is_active()) {
1089 int tile_x =
static_cast<int>(click_pos.x) / 8;
1090 int tile_y =
static_cast<int>(click_pos.y) / 8;
1091 int tiles_per_row = 128 / 8;
1109 ImGui::SetNextItemWidth(100);
1122 ImGui::TextColored(theme.text_error_red,
1123 tr(
"Error loading overworld map: %s"),
1131 ImGui::Text(tr(
"Overworld map not loaded. Ensure ROM is loaded."));
1138 if (ImGui::Button(tr(
"Paint Mode"))) {
1141 if (ImGui::IsItemHovered()) {
1142 ImGui::SetTooltip(tr(
1143 "Paint the pause-menu world map: choose an 8x8 tile in Tileset, then "
1144 "click Map Canvas."));
1147 if (ImGui::Button(tr(
"Save World Map"))) {
1150 ImGui::OpenPopup(
"OWSaveSuccess");
1168 if (ImGui::Button(tr(
"Load Custom Map..."))) {
1170 if (!path.empty()) {
1173 ImGui::OpenPopup(
"CustomMapLoadError");
1178 if (ImGui::Button(tr(
"Save Custom Map..."))) {
1180 if (!path.empty()) {
1183 ImGui::OpenPopup(
"CustomMapSaveSuccess");
1191 ImGui::TextWrapped(tr(
1192 "This edits the pause-menu world map art, not the 160 playable "
1193 "overworld areas. For area-map painting, entrances, exits, items, and "
1194 "sprites, use Overworld Editor. Paint flow here: pick an 8x8 tile from "
1195 "Tileset, then click Map Canvas; use Light/Dark World to choose the "
1200 if (ImGui::BeginPopup(
"CustomMapLoadError")) {
1201 ImGui::Text(tr(
"Error loading custom map: %s"),
status_.message().data());
1204 if (ImGui::BeginPopup(
"CustomMapSaveSuccess")) {
1205 ImGui::Text(tr(
"Custom map saved successfully!"));
1210 if (ImGui::BeginPopup(
"OWSaveSuccess")) {
1211 ImGui::Text(tr(
"Overworld map saved successfully!"));
1216 if (ImGui::BeginTable(
"OWMapTable", 3,
1217 ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders)) {
1218 ImGui::TableSetupColumn(
"Map Canvas");
1219 ImGui::TableSetupColumn(
"Tileset");
1220 ImGui::TableSetupColumn(
"Palette");
1221 ImGui::TableHeadersRow();
1224 ImGui::TableNextColumn();
1230 if (map_bitmap.is_active()) {
1239 int tile_x =
static_cast<int>(click_pos.x) / 8;
1240 int tile_y =
static_cast<int>(click_pos.y) / 8;
1242 if (tile_x >= 0 && tile_x < 64 && tile_y >= 0 && tile_y < 64) {
1243 int tile_index = tile_x + (tile_y * 64);
1267 ImGui::TableNextColumn();
1273 if (tiles8_bitmap.is_active()) {
1281 int tile_x =
static_cast<int>(click_pos.x) / 8;
1282 int tile_y =
static_cast<int>(click_pos.y) / 8;
1291 ImGui::TableNextColumn();
1302 static bool show_bg1 =
true;
1303 static bool show_bg2 =
true;
1304 static bool show_bg3 =
true;
1306 static bool drawing_bg1 =
true;
1307 static bool drawing_bg2 =
false;
1308 static bool drawing_bg3 =
false;
1310 ImGui::Checkbox(tr(
"Show BG1"), &show_bg1);
1312 ImGui::Checkbox(tr(
"Show BG2"), &show_bg2);
1314 ImGui::Checkbox(tr(
"Draw BG1"), &drawing_bg1);
1316 ImGui::Checkbox(tr(
"Draw BG2"), &drawing_bg2);
1318 ImGui::Checkbox(tr(
"Draw BG3"), &drawing_bg3);
1385 if (idx >= 0 && idx <
static_cast<int>(
dungeon_maps_.size())) {
project::ResourceLabelManager * resource_label()
UndoManager undo_manager_
zelda3::GameData * game_data() const
EditorDependencies dependencies_
void DrawTitleScreenEditor()
void DrawDungeonMapsRoomGfx()
Draw dungeon room graphics editor with enhanced tile16 editing.
gfx::SnesPalette palette_
absl::Status Undo() override
void DrawTitleScreenBlocksetSelector()
bool title_screen_loaded_
ScreenSnapshot CaptureTile16CompSnapshot() const
gui::Canvas ow_map_canvas_
gfx::Tilemap tile16_blockset_
ScreenSnapshot pending_dungeon_before_
void DrawTitleScreenBG2Canvas()
gui::Canvas tilemap_canvas_
void DrawInventoryItemIcons()
std::array< gfx::TileInfo, 4 > current_tile16_info
absl::Status Save() override
absl::Status Load() override
void SaveDungeonMapUndoState(const std::string &description)
absl::Status Update() override
gui::Canvas screen_canvas_
std::string pending_tile16_desc_
void DrawTitleScreenBG1Canvas()
gui::Canvas title_bg1_canvas_
void RestoreFromSnapshot(const ScreenSnapshot &snapshot)
zelda3::OverworldMapScreen ow_map_screen_
ScreenSnapshot pending_tile16_before_
void Initialize() override
int selected_title_tile16_
ScreenSnapshot CaptureDungeonMapSnapshot() const
gui::Canvas current_tile_canvas_
void DrawDungeonMapsEditor()
Draw dungeon maps editor with enhanced ROM hacking features.
gui::Canvas title_bg2_canvas_
absl::Status Redo() override
void SaveTile16CompUndoState(const std::string &description)
void DrawInventoryToolset()
void CommitTile16CompUndo()
gfx::Tilemap tile8_tilemap_
bool has_pending_dungeon_undo_
void DrawTitleScreenCompositeCanvas()
zelda3::TitleScreen title_screen_
void DrawOverworldMapEditor()
zelda3::Inventory inventory_
EditingMode current_mode_
zelda3::DungeonMapLabels dungeon_map_labels_
bool paste_button_pressed
gui::Canvas ow_tileset_canvas_
gui::Canvas title_blockset_canvas_
void DrawDungeonMapToolset()
gui::Canvas tilesheet_canvas_
void DrawNamingScreenEditor()
void DrawDungeonMapScreen(int i)
bool has_pending_tile16_undo_
void DrawDungeonMapsTabs()
std::vector< zelda3::DungeonMap > dungeon_maps_
std::string pending_dungeon_desc_
void CommitDungeonMapUndo()
void DrawInventoryMenuEditor()
void Push(std::unique_ptr< UndoAction > action)
void RegisterPanel(size_t session_id, const WindowDescriptor &base_info)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Represents a bitmap image optimized for SNES ROM hacking.
const uint8_t * data() const
const SnesPalette & palette() const
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
void set_data(const std::vector< uint8_t > &data)
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
void Get16x16Tile(int tile_x, int tile_y, std::vector< uint8_t > &tile_data, int &tile_data_offset)
Extract a 16x16 tile from the bitmap (SNES metatile size)
RAII timer for automatic timing management.
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color)
ImVector< ImVec2 > * mutable_points()
int GetTileIdFromMousePos()
bool DrawTileSelector(int size, int size_y=0)
bool DrawTilePainter(const Bitmap &bitmap, int size, float scale=1.0f)
CanvasConfig & GetConfig()
bool IsMouseHovering() const
void DrawBitmapTable(const BitmapTable &gfx_bin)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0))
const ImVector< ImVec2 > & points() const
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
void DrawText(const std::string &text, int x, int y)
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
absl::Status Create(Rom *rom, GameData *game_data=nullptr)
Initialize and load inventory screen data from ROM.
auto & mutable_lw_tiles()
absl::Status SaveCustomMap(const std::string &file_path, bool use_dark_world)
Save map data to external binary file.
auto & mutable_dw_tiles()
absl::Status LoadCustomMap(const std::string &file_path)
Load custom map from external binary file.
absl::Status Save(Rom *rom)
Save changes back to ROM.
absl::Status RenderMapLayer(bool use_dark_world)
Render map tiles into bitmap.
absl::Status Create(Rom *rom)
Initialize and load overworld map data from ROM.
auto & composite_bitmap()
auto & mutable_bg1_buffer()
absl::Status Create(Rom *rom, GameData *game_data=nullptr)
Initialize and load title screen data from ROM.
auto & mutable_bg2_buffer()
absl::Status RenderCompositeLayer(bool show_bg1, bool show_bg2)
Render composite layer with BG1 on top of BG2 with transparency.
absl::Status Save(Rom *rom)
absl::Status RenderBG2Layer()
Render BG2 tilemap into bitmap pixels Converts tile IDs from tiles_bg2_buffer_ into pixel data.
absl::Status RenderBG1Layer()
Render BG1 tilemap into bitmap pixels Converts tile IDs from tiles_bg1_buffer_ into pixel data.
#define ICON_MD_MORE_VERT
#define ICON_MD_INVENTORY
#define PRINT_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
const AgentUITheme & GetTheme()
void EnsureCompositeBitmapTextureQueued(gfx::Bitmap &composite)
void RenderTile16(IRenderer *renderer, Tilemap &tilemap, int tile_id)
void ModifyTile16(Tilemap &tilemap, const std::vector< uint8_t > &data, const TileInfo &top_left, const TileInfo &top_right, const TileInfo &bottom_left, const TileInfo &bottom_right, int sheet_offset, int tile_id)
void UpdateTile16(IRenderer *renderer, Tilemap &tilemap, int tile_id)
std::vector< uint8_t > SnesTo8bppSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
void EndCanvas(Canvas &canvas)
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
bool DrawTileSelector(const CanvasRuntime &rt, int size, int size_y, ImVec2 *out_selected_pos)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
void DrawBitmap(const CanvasRuntime &rt, gfx::Bitmap &bitmap, int border_offset=2, float scale=1.0f)
bool BeginThemedTabBar(const char *id, ImGuiTabBarFlags flags)
A stylized tab bar with "Mission Control" branding.
IMGUI_API absl::Status InlinePaletteEditor(gfx::SnesPalette &palette, const std::string &title, ImGuiColorEditFlags flags)
Full inline palette editor with color picker and copy options.
bool InputTileInfo(const char *label, gfx::TileInfo *tile_info)
IMGUI_API bool DisplayPalette(gfx::SnesPalette &palette, bool loaded)
bool ToolbarIconButton(const char *icon, const char *tooltip, bool is_active)
Convenience wrapper for toolbar-sized icon buttons.
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
std::string HexByte(uint8_t byte, HexStringParams params)
absl::Status LoadDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom, GameData *game_data, const std::vector< uint8_t > &gfx_data, bool bin_mode)
Load the dungeon map tile16 from the ROM.
absl::Status SaveDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom)
Save the dungeon map tile16 to the ROM.
absl::StatusOr< std::vector< DungeonMap > > LoadDungeonMaps(Rom &rom, DungeonMapLabels &dungeon_map_labels)
Load the dungeon maps from the ROM.
absl::Status SaveDungeonMaps(Rom &rom, std::vector< DungeonMap > &dungeon_maps)
Save the dungeon maps to the ROM.
#define RETURN_IF_ERROR(expr)
zelda3::DungeonMap map_data
std::vector< std::array< std::string, zelda3::kNumRooms > > labels
WorkspaceWindowManager * window_manager
Unified screen editor snapshot.
DungeonMapSnapshot dungeon_map
Tile16CompSnapshot tile16_comp
std::array< gfx::TileInfo, 4 > tile_info
PaletteGroup dungeon_main
auto mutable_palette(int i)
void CacheTile(int tile_id, const Bitmap &bitmap)
Cache a tile bitmap by copying it.
Bitmap * GetTile(int tile_id)
Get a cached tile by ID.
Pair tile_size
Size of individual tiles (8x8 or 16x16)
TileCache tile_cache
Smart tile cache with LRU eviction.
Pair map_size
Size of tilemap in tiles.
Bitmap atlas
Master bitmap containing all tiles.
std::vector< std::array< gfx::TileInfo, 4 > > tile_info
Tile metadata (4 tiles per 16x16)
std::optional< float > grid_step
void SelectableLabelWithNameEdit(bool selected, const std::string &type, const std::string &key, const std::string &defaultValue)
gfx::PaletteGroupMap palette_groups