48 if (ImGui::BeginTable(
"DungeonObjectEditorTable", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV, ImVec2(0, 0))) {
49 ImGui::TableSetupColumn(
"Object Browser", ImGuiTableColumnFlags_WidthFixed, 400);
50 ImGui::TableSetupColumn(
"Preview Canvas", ImGuiTableColumnFlags_WidthStretch);
51 ImGui::TableHeadersRow();
54 ImGui::TableNextColumn();
55 ImGui::BeginChild(
"AssetBrowser", ImVec2(0, 0),
true, ImGuiWindowFlags_AlwaysVerticalScrollbar);
62 ImGui::TableNextColumn();
63 ImGui::BeginChild(
"PreviewCanvas", ImVec2(0, 0),
true);
66 ImGui::SeparatorText(
"Object Placement");
67 static int place_x = 0, place_y = 0;
68 ImGui::InputInt(
"X Position", &place_x);
69 ImGui::InputInt(
"Y Position", &place_y);
84 int preview_x = 128 - 16;
85 int preview_y = 128 - 16;
107 ImGui::Text(
"Placement Controls:");
108 static int place_x = 0, place_y = 0;
109 ImGui::InputInt(
"X Position", &place_x);
110 ImGui::InputInt(
"Y Position", &place_y);
112 if (ImGui::Button(
"Place Object")) {
114 ImGui::Text(
"Object placed at (%d, %d)", place_x, place_y);
122 static int selected_object_type = 0;
123 static int selected_object_id = 0;
126 const char* object_types[] = {
"Type 1 (0x00-0xFF)",
"Type 2 (0x100-0x1FF)",
"Type 3 (0x200+)"};
127 if (ImGui::Combo(
"Object Type", &selected_object_type, object_types, 3)) {
128 selected_object_id = 0;
134 const int preview_size = 48;
135 const int items_per_row = 5;
141 int start_id, end_id;
142 switch (selected_object_type) {
143 case 0: start_id = 0x00; end_id = 0xFF;
break;
144 case 1: start_id = 0x100; end_id = 0x1FF;
break;
145 case 2: start_id = 0x200; end_id = 0x2FF;
break;
146 default: start_id = 0x00; end_id = 0xFF;
break;
153 for (
int obj_id = start_id; obj_id <= end_id && obj_id <= start_id + 63; ++obj_id) {
156 test_object.set_rom(
rom_);
157 test_object.EnsureTilesLoaded();
160 float available_width = ImGui::GetContentRegionAvail().x;
161 float spacing = ImGui::GetStyle().ItemSpacing.x;
162 float item_width = (available_width - (items_per_row - 1) * spacing) / items_per_row;
163 float item_height = preview_size + 30;
165 ImGui::PushID(obj_id);
168 bool is_selected = (selected_object_id == obj_id);
169 if (ImGui::Selectable(
"", is_selected, ImGuiSelectableFlags_None, ImVec2(item_width, item_height))) {
170 selected_object_id = obj_id;
184 ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
185 ImVec2 preview_pos = ImVec2(cursor_pos.x + (item_width - preview_size) / 2,
186 cursor_pos.y - item_height + 5);
189 ImGui::SetCursorScreenPos(preview_pos);
193 ImGui::GetWindowDrawList()->AddRectFilled(
195 ImVec2(preview_pos.x + preview_size, preview_pos.y + preview_size),
199 ImGui::GetWindowDrawList()->AddRect(
201 ImVec2(preview_pos.x + preview_size, preview_pos.y + preview_size),
202 IM_COL32(0, 0, 0, 255), 0.0f, 0, 2.0f);
206 ImVec2 text_size = ImGui::CalcTextSize(symbol.c_str());
207 ImVec2 text_pos = ImVec2(
208 preview_pos.x + (preview_size - text_size.x) / 2,
209 preview_pos.y + (preview_size - text_size.y) / 2);
211 ImGui::GetWindowDrawList()->AddText(
212 text_pos, IM_COL32(255, 255, 255, 255), symbol.c_str());
215 ImGui::SetCursorScreenPos(ImVec2(preview_pos.x, preview_pos.y + preview_size + 2));
216 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 255));
217 ImGui::Text(
"0x%02X", obj_id);
218 ImGui::PopStyleColor();
221 std::string object_name =
"Unknown";
222 if (obj_id < 0x100) {
223 if (obj_id < std::size(zelda3::Type1RoomObjectNames)) {
224 const char* name_ptr = zelda3::Type1RoomObjectNames[obj_id];
225 if (name_ptr !=
nullptr) {
226 object_name = std::string(name_ptr);
229 }
else if (obj_id < 0x140) {
230 int type2_index = obj_id - 0x100;
231 if (type2_index >= 0 && type2_index < std::size(zelda3::Type2RoomObjectNames)) {
232 const char* name_ptr = zelda3::Type2RoomObjectNames[type2_index];
233 if (name_ptr !=
nullptr) {
234 object_name = std::string(name_ptr);
237 }
else if (obj_id < 0x1C0) {
238 int type3_index = obj_id - 0x140;
239 if (type3_index >= 0 && type3_index < std::size(zelda3::Type3RoomObjectNames)) {
240 const char* name_ptr = zelda3::Type3RoomObjectNames[type3_index];
241 if (name_ptr !=
nullptr) {
242 object_name = std::string(name_ptr);
248 ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 2, cursor_pos.y - 8));
249 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(200, 200, 200, 255));
251 if (object_name.length() > 8) {
252 object_name = object_name.substr(0, 8) +
"...";
254 ImGui::Text(
"%s", object_name.c_str());
255 ImGui::PopStyleColor();
261 if (current_col >= items_per_row) {
270 ImGui::Text(
"ROM not loaded");
277 ImGui::Text(
"Selected: 0x%03X", selected_object_id);
419 ImGui::Text(
"Object editor not initialized");
425 ImGui::Text(
"Object Editor");
429 auto mode = editor.GetMode();
430 const char *mode_names[] = {
"Select",
"Insert",
"Delete",
"Edit",
"Layer",
"Preview"};
431 ImGui::Text(
"Mode: %s", mode_names[
static_cast<int>(mode)]);
434 if (ImGui::Button(
"Select"))
437 if (ImGui::Button(
"Insert"))
440 if (ImGui::Button(
"Edit"))
444 int current_layer = editor.GetCurrentLayer();
445 if (ImGui::SliderInt(
"Layer", ¤t_layer, 0, 2)) {
446 editor.SetCurrentLayer(current_layer);
449 int current_object_type = editor.GetCurrentObjectType();
450 if (ImGui::InputInt(
"Object Type", ¤t_object_type, 1, 16)) {
451 if (current_object_type >= 0 && current_object_type <= 0x3FF) {
452 editor.SetCurrentObjectType(current_object_type);
457 auto config = editor.GetConfig();
458 if (ImGui::Checkbox(
"Snap to Grid", &config.snap_to_grid)) {
459 editor.SetConfig(config);
462 if (ImGui::Checkbox(
"Show Grid", &config.show_grid)) {
463 editor.SetConfig(config);
468 ImGui::Text(
"Objects: %zu", editor.GetObjectCount());
470 auto selection = editor.GetSelection();
471 if (!selection.selected_objects.empty()) {
472 ImGui::Text(
"Selected: %zu", selection.selected_objects.size());
477 if (ImGui::Button(
"Undo") && editor.CanUndo()) {
481 if (ImGui::Button(
"Redo") && editor.CanRedo()) {
488 if (object_id >= 0x10 && object_id <= 0x1F) {
489 return IM_COL32(128, 128, 128, 255);
490 }
else if (object_id >= 0x20 && object_id <= 0x2F) {
491 return IM_COL32(139, 69, 19, 255);
492 }
else if (object_id == 0xF9 || object_id == 0xFA) {
493 return IM_COL32(255, 215, 0, 255);
494 }
else if (object_id >= 0x17 && object_id <= 0x1E) {
495 return IM_COL32(139, 69, 19, 255);
496 }
else if (object_id == 0x2F || object_id == 0x2B) {
497 return IM_COL32(160, 82, 45, 255);
498 }
else if (object_id >= 0x138 && object_id <= 0x13B) {
499 return IM_COL32(255, 255, 0, 255);
500 }
else if (object_id >= 0x30 && object_id <= 0x3F) {
501 return IM_COL32(105, 105, 105, 255);
503 return IM_COL32(96, 96, 96, 255);
547 ImGui::SeparatorText(
"Dungeon Objects");
550 ImGui::Text(
"Asset Browser Debug: Available width: %.1f", ImGui::GetContentRegionAvail().x);
553 static int object_type_filter = 0;
554 const char* object_types[] = {
"All",
"Walls",
"Floors",
"Chests",
"Doors",
"Decorations",
"Stairs"};
555 if (ImGui::Combo(
"Object Type", &object_type_filter, object_types, 7)) {
562 const float item_size = 64.0f;
563 const float item_spacing = 8.0f;
564 const int columns = std::max(1,
static_cast<int>((ImGui::GetContentRegionAvail().x - item_spacing) / (item_size + item_spacing)));
566 ImGui::Text(
"Columns: %d, Item size: %.1f", columns, item_size);
568 int current_column = 0;
572 for (
int obj_id = 0; obj_id <= 0xFF && items_drawn < 100; ++obj_id) {
578 if (current_column > 0) {
582 ImGui::PushID(obj_id);
586 ImVec2 button_size(item_size, item_size);
588 if (ImGui::Selectable(
"", is_selected, ImGuiSelectableFlags_None, button_size)) {
607 ImVec2 button_pos = ImGui::GetItemRectMin();
608 ImDrawList* draw_list = ImGui::GetWindowDrawList();
612 draw_list->AddRectFilled(button_pos,
613 ImVec2(button_pos.x + item_size, button_pos.y + item_size),
617 ImU32 border_color = is_selected ? IM_COL32(255, 255, 0, 255) : IM_COL32(0, 0, 0, 255);
618 draw_list->AddRect(button_pos,
619 ImVec2(button_pos.x + item_size, button_pos.y + item_size),
620 border_color, 0.0f, 0, is_selected ? 3.0f : 1.0f);
624 ImVec2 text_size = ImGui::CalcTextSize(symbol.c_str());
625 ImVec2 text_pos = ImVec2(
626 button_pos.x + (item_size - text_size.x) / 2,
627 button_pos.y + (item_size - text_size.y) / 2);
628 draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 255), symbol.c_str());
631 std::string id_text = absl::StrFormat(
"%02X", obj_id);
632 ImVec2 id_size = ImGui::CalcTextSize(id_text.c_str());
633 ImVec2 id_pos = ImVec2(
634 button_pos.x + (item_size - id_size.x) / 2,
635 button_pos.y + item_size - id_size.y - 2);
636 draw_list->AddText(id_pos, IM_COL32(255, 255, 255, 255), id_text.c_str());
640 current_column = (current_column + 1) % columns;
641 if (current_column == 0) {
649 ImGui::Text(
"Items drawn: %d", items_drawn);
1014 ImGui::Text(
"Dungeon editor system not initialized");
1020 ImGui::Text(
"Room Properties");
1023 auto current_room = system.GetCurrentRoom();
1024 auto properties_result = system.GetRoomProperties(current_room);
1026 if (properties_result.ok()) {
1027 auto properties = properties_result.value();
1029 static char room_name[128] = {0};
1030 static int dungeon_id = 0;
1031 static int floor_level = 0;
1032 static bool is_boss_room =
false;
1033 static bool is_save_room =
false;
1034 static int music_id = 0;
1038 size_t name_len = std::min(properties.name.length(),
sizeof(room_name) - 1);
1039 std::memcpy(room_name, properties.name.c_str(), name_len);
1040 room_name[name_len] =
'\0';
1041 dungeon_id = properties.dungeon_id;
1042 floor_level = properties.floor_level;
1043 is_boss_room = properties.is_boss_room;
1044 is_save_room = properties.is_save_room;
1045 music_id = properties.music_id;
1047 ImGui::InputText(
"Name", room_name,
sizeof(room_name));
1048 ImGui::InputInt(
"Dungeon ID", &dungeon_id);
1049 ImGui::InputInt(
"Floor", &floor_level);
1050 ImGui::InputInt(
"Music", &music_id);
1051 ImGui::Checkbox(
"Boss Room", &is_boss_room);
1052 ImGui::Checkbox(
"Save Room", &is_save_room);
1054 if (ImGui::Button(
"Save Properties")) {
1056 new_properties.
room_id = current_room;
1057 new_properties.
name = room_name;
1062 new_properties.
music_id = music_id;
1064 auto status = system.SetRoomProperties(current_room, new_properties);
1066 ImGui::Text(
"Error saving properties");
1070 ImGui::Text(
"Error loading properties");
1075 ImGui::Text(
"Dungeon Settings");
1077 auto dungeon_settings_result = system.GetDungeonSettings();
1078 if (dungeon_settings_result.ok()) {
1079 auto settings = dungeon_settings_result.value();
1080 ImGui::Text(
"Dungeon: %s", settings.name.c_str());
1081 ImGui::Text(
"Rooms: %d", settings.total_rooms);
1082 ImGui::Text(
"Start: %d", settings.starting_room_id);
1083 ImGui::Text(
"Boss: %d", settings.boss_room_id);