12#include "imgui/imgui.h"
21using ImGui::BeginChild;
22using ImGui::BeginTabBar;
23using ImGui::BeginTabItem;
24using ImGui::BeginTable;
27using ImGui::EndTabBar;
28using ImGui::EndTabItem;
29using ImGui::RadioButton;
31using ImGui::TableHeadersRow;
32using ImGui::TableNextColumn;
33using ImGui::TableNextRow;
34using ImGui::TableSetupColumn;
38 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable |
39 ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter |
40 ImGuiTableFlags_BordersV;
53 TAB_BAR(
"##DungeonEditorTabBar")
59 static bool calc_stats =
false;
69 return absl::OkStatus();
73 auto dungeon_man_pal_group =
rom()->palette_group().dungeon_main;
74 for (
int i = 0; i < 0x100 + 40; i++) {
77 rooms_[i].LoadRoomFromROM();
78 if (
flags()->kDrawDungeonRoomGraphics) {
79 rooms_[i].LoadRoomGraphics();
83 if (
rooms_[i].room_size_ptr() != 0x0A8000) {
87 auto dungeon_palette_ptr =
rom()->paletteset_ids[
rooms_[i].palette][0];
89 rom()->ReadWord(0xDEC4B + dungeon_palette_ptr));
90 int p_id = palette_id / 180;
91 auto color = dungeon_man_pal_group[p_id][3];
97 for (
int i = 0; i < 0x07; ++i) {
101 for (
int i = 0; i < 0x85; ++i) {
115 return absl::OkStatus();
119 for (
int i = 0; i < 8; i++) {
125 auto sprites_aux1_pal_group =
rom()->palette_group().sprites_aux1;
126 for (
int i = 9; i < 16; i++) {
132 return absl::OkStatus();
136 std::map<int, std::vector<int>> rooms_by_bank;
138 int bank = room.second >> 16;
139 rooms_by_bank[bank].push_back(room.second);
143 for (
auto& bank_rooms : rooms_by_bank) {
145 std::sort(bank_rooms.second.begin(), bank_rooms.second.end());
147 for (
size_t i = 0; i < bank_rooms.second.size(); ++i) {
148 int room_ptr = bank_rooms.second[i];
153 [room_ptr](
const auto& entry) {
154 return entry.second == room_ptr;
158 if (room_ptr != 0x0A8000) {
159 if (i < bank_rooms.second.size() - 1) {
162 rooms_[room_id].set_room_size(bank_rooms.second[i + 1] - room_ptr);
165 int bank_end_address = (bank_rooms.first << 16) | 0xFFFF;
166 rooms_[room_id].set_room_size(bank_end_address - room_ptr + 1);
171 rooms_[room_id].set_room_size(0x00);
182 auto dungeon_main_pal_group =
rom()->palette_group().dungeon_main;
190 TableSetupColumn(
"Room Selector");
191 TableSetupColumn(
"Canvas", ImGuiTableColumnFlags_WidthStretch,
192 ImGui::GetContentRegionAvail().x);
193 TableSetupColumn(
"Object Selector");
198 TAB_BAR(
"##DungeonRoomTabBar");
214 return absl::OkStatus();
218 if (BeginTable(
"DWToolset", 13, ImGuiTableFlags_SizingFixedFit,
220 TableSetupColumn(
"#undoTool");
221 TableSetupColumn(
"#redoTool");
222 TableSetupColumn(
"#separator");
223 TableSetupColumn(
"#anyTool");
225 TableSetupColumn(
"#bg1Tool");
226 TableSetupColumn(
"#bg2Tool");
227 TableSetupColumn(
"#bg3Tool");
228 TableSetupColumn(
"#separator");
229 TableSetupColumn(
"#spriteTool");
230 TableSetupColumn(
"#itemTool");
231 TableSetupColumn(
"#doorTool");
232 TableSetupColumn(
"#blockTool");
274 if (ImGui::IsItemHovered()) {
275 ImGui::SetTooltip(
"Sprites");
282 if (ImGui::IsItemHovered()) {
283 ImGui::SetTooltip(
"Items");
290 if (ImGui::IsItemHovered()) {
291 ImGui::SetTooltip(
"Doors");
298 if (ImGui::IsItemHovered()) {
299 ImGui::SetTooltip(
"Blocks");
312 if (
rom()->is_loaded()) {
316 if (ImGuiID child_id = ImGui::GetID((
void*)(intptr_t)9);
317 BeginChild(child_id, ImGui::GetContentRegionAvail(),
true,
318 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
321 rom()->resource_label()->SelectableLabelWithNameEdit(
324 if (ImGui::IsItemClicked()) {
338using ImGui::Separator;
341 if (
rom()->is_loaded()) {
371 Text(
"Camera Boundaries");
373 Text(
"\t\t\t\t\tNorth East South West");
392 if (BeginChild(
"EntranceSelector", ImVec2(0, 0),
true,
393 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
394 for (
int i = 0; i < 0x85 + 7; i++) {
395 rom()->resource_label()->SelectableLabelWithNameEdit(
400 if (ImGui::IsItemClicked()) {
413 static int next_tab_id = 0;
435 &open, ImGuiTabItemFlags_None)) {
486 const auto height = 0x40;
487 const int num_sheets = 0x10;
493 int current_block = 0;
494 for (
int block : blocks) {
495 int offset = height * (current_block + 1);
497 if (current_block >= 1) {
513 if (BeginTabBar(
"##TabBar", ImGuiTabBarFlags_FittingPolicyScroll)) {
514 if (BeginTabItem(
"Room Graphics")) {
515 if (ImGuiID child_id = ImGui::GetID((
void*)(intptr_t)3);
516 BeginChild(child_id, ImGui::GetContentRegionAvail(),
true,
517 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
524 if (BeginTabItem(
"Object Renderer")) {
535 TableSetupColumn(
"Dungeon Objects", ImGuiTableColumnFlags_WidthStretch,
536 ImGui::GetContentRegionAvail().x);
537 TableSetupColumn(
"Canvas");
540 BeginChild(
"DungeonObjectButtons", ImVec2(250, 0),
true);
542 int selected_object = 0;
544 for (
const auto object_name : zelda3::dungeon::Type1RoomObjectNames) {
545 if (ImGui::Selectable(object_name.data(), selected_object == i)) {
560 BeginChild(
"DungeonObjectCanvas", ImVec2(276, 0x10 * 0x40 + 1),
true);
577 static MemoryEditor mem_edit;
587 for (
const auto& room :
rooms_) {
609 const absl::flat_hash_map<uint16_t, int>& usage_map, uint16_t& selected_set,
610 int spriteset_offset) {
612 std::vector<std::pair<uint16_t, int>> sorted_usage(usage_map.begin(),
614 std::sort(sorted_usage.begin(), sorted_usage.end(),
615 [](
const auto& a,
const auto& b) { return a.first < b.first; });
617 for (
const auto& [set, count] : sorted_usage) {
618 std::string display_str;
619 if (spriteset_offset != 0x00) {
620 display_str = absl::StrFormat(
"%#02x, %#02x: %d", set,
621 (set + spriteset_offset), count);
624 absl::StrFormat(
"%#02x: %d", (set + spriteset_offset), count);
626 if (ImGui::Selectable(display_str.c_str(), selected_set == set)) {
639 int spriteset_offset = 0x00) {
640 std::vector<int> unused_sets;
641 for (
int i = 0; i < max_set; i++) {
642 if (usage_map.find(i) == usage_map.end()) {
643 unused_sets.push_back(i);
646 for (
const auto& set : unused_sets) {
647 if (spriteset_offset != 0x00) {
648 Text(
"%#02x, %#02x", set, (set + spriteset_offset));
657 if (Button(
"Refresh")) {
667 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
668 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
669 if (BeginTable(
"DungeonUsageStatsTable", 8,
671 ImGui::GetContentRegionAvail())) {
672 TableSetupColumn(
"Blockset Usage");
673 TableSetupColumn(
"Unused Blockset");
674 TableSetupColumn(
"Palette Usage");
675 TableSetupColumn(
"Unused Palette");
676 TableSetupColumn(
"Spriteset Usage");
677 TableSetupColumn(
"Unused Spriteset");
678 TableSetupColumn(
"Usage Grid");
679 TableSetupColumn(
"Group Preview");
681 ImGui::PopStyleVar(2);
684 BeginChild(
"BlocksetUsageScroll", ImVec2(0, 0),
true,
685 ImGuiWindowFlags_HorizontalScrollbar);
690 BeginChild(
"UnusedBlocksetScroll", ImVec2(0, 0),
true,
691 ImGuiWindowFlags_HorizontalScrollbar);
696 BeginChild(
"PaletteUsageScroll", ImVec2(0, 0),
true,
697 ImGuiWindowFlags_HorizontalScrollbar);
702 BeginChild(
"UnusedPaletteScroll", ImVec2(0, 0),
true,
703 ImGuiWindowFlags_HorizontalScrollbar);
709 BeginChild(
"SpritesetUsageScroll", ImVec2(0, 0),
true,
710 ImGuiWindowFlags_HorizontalScrollbar);
715 BeginChild(
"UnusedSpritesetScroll", ImVec2(0, 0),
true,
716 ImGuiWindowFlags_HorizontalScrollbar);
721 BeginChild(
"UsageGrid", ImVec2(0, 0),
true,
722 ImGuiWindowFlags_HorizontalScrollbar);
723 Text(
"%s", absl::StrFormat(
"Total size of all rooms: %d hex format: %#06x",
742 int totalSquares = 296;
743 int squaresWide = 16;
744 int squaresTall = (totalSquares + squaresWide - 1) /
747 for (
int row = 0; row < squaresTall; ++row) {
750 for (
int col = 0; col < squaresWide; ++col) {
752 if (row * squaresWide + col >= totalSquares) {
756 const auto& room =
rooms_[row * squaresWide + col];
761 color.x = color.x / 255;
762 color.y = color.y / 255;
763 color.z = color.z / 255;
765 if (
rooms_[row * squaresWide + col].room_size() > 0xFFFF) {
766 color = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
768 if (
rooms_[row * squaresWide + col].room_size() == 0) {
769 color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
771 ImGui::PushStyleColor(ImGuiCol_Button, color);
773 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
781 ImGui::PushStyleColor(
783 ImVec4(1.0f, 0.5f, 0.0f, 1.0f));
785 if (Button(absl::StrFormat(
"%#x",
786 rooms_[row * squaresWide + col].room_size())
793 if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
795 absl::StrFormat(
"RoomContextMenu%d", row * squaresWide + col)
798 ImGui::PopStyleColor(2);
803 ImGui::PopStyleColor();
807 if (ImGui::IsItemHovered()) {
809 ImGui::BeginTooltip();
810 Text(
"Room ID: %d", row * squaresWide + col);
811 Text(
"Blockset: %#02x", room.blockset);
812 Text(
"Spriteset: %#02x", room.spriteset);
813 Text(
"Palette: %#02x", room.palette);
814 Text(
"Floor1: %#02x", room.floor1);
815 Text(
"Floor2: %#02x", room.floor2);
816 Text(
"Message ID: %#04x", room.message_id_);
817 Text(
"Size: %#016llx", room.room_size());
818 Text(
"Size Pointer: %#016llx", room.room_size_ptr());
static Renderer & GetInstance()
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to the screen.
void UpdateBitmap(gfx::Bitmap *bitmap, bool use_sdl_update=false)
Used to update a bitmap on the screen.
uint16_t current_room_id_
uint16_t selected_blockset_
std::unordered_map< int, int > room_size_addresses_
absl::flat_hash_map< uint16_t, int > blockset_usage_
void DrawDungeonTabView()
absl::Status Redo() override
uint64_t current_palette_group_id_
std::vector< zelda3::dungeon::Room > rooms_
uint16_t current_entrance_id_
void LoadDungeonRoomSize()
void DrawDungeonCanvas(int room_id)
std::array< gfx::Bitmap, kNumGfxSheets > graphics_bin_
gfx::SnesPalette current_palette_
absl::Status Undo() override
gui::Canvas object_canvas_
gui::Canvas room_gfx_canvas_
ImVector< int > active_rooms_
absl::flat_hash_map< uint16_t, int > palette_usage_
gfx::PaletteGroup current_palette_group_
std::vector< zelda3::dungeon::RoomEntrance > entrances_
std::vector< gfx::Bitmap * > room_gfx_sheets_
uint16_t selected_palette_
void CalculateUsageStats()
uint64_t total_room_size_
gfx::SnesPalette full_palette_
absl::Status Update() override
std::unordered_map< int, ImVec4 > room_palette_
absl::Status RefreshGraphics()
uint16_t selected_spriteset_
void DrawObjectRenderer()
zelda3::dungeon::DungeonObjectRenderer object_renderer_
uint64_t current_palette_id_
absl::Status UpdateDungeonRoomView()
absl::Status Initialize()
std::vector< int64_t > room_size_pointers_
absl::flat_hash_map< uint16_t, int > spriteset_usage_
void DrawEntranceSelector()
GfxGroupEditor gfx_group_editor_
void RenderSetUsage(const absl::flat_hash_map< uint16_t, int > &usage_map, uint16_t &selected_set, int spriteset_offset=0x00)
void SetSelectedBlockset(uint8_t blockset)
void DrawSpritesetViewer(bool sheet_only=false)
void DrawBlocksetViewer(bool sheet_only=false)
void SetSelectedSpriteset(uint8_t spriteset)
bool DrawTileSelector(int size)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0), bool drag=false)
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
void DrawBitmap(const Bitmap &bitmap, int border_offset=0, bool ready=true)
void DrawContextMenu(gfx::Bitmap *bitmap=nullptr)
void LoadObject(uint32_t routine_ptr, std::array< uint8_t, 16 > &sheet_ids)
#define PRINT_IF_ERROR(expression)
#define RETURN_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
#define ICON_MD_MORE_VERT
#define ICON_MD_FILTER_NONE
#define ICON_MD_SENSOR_DOOR
#define ICON_MD_PEST_CONTROL
std::string UppercaseHexByte(uint8_t byte, bool leading)
void RenderUnusedSets(const absl::flat_hash_map< T, int > &usage_map, int max_set, int spriteset_offset=0x00)
constexpr ImGuiTableFlags kDungeonTableFlags
constexpr ImGuiTableFlags kDungeonObjectTableFlags
constexpr ImGuiTabBarFlags kDungeonTabBarFlags
constexpr ImGuiTabItemFlags kDungeonTabFlags
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromLargePalette(SnesPalette &palette, int num_colors)
Take a SNESPalette, divide it into palettes of 8 colors.
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
bool InputHex(const char *label, uint64_t *data)
void SelectablePalettePipeline(uint64_t &palette_id, bool &refresh_graphics, gfx::SnesPalette &palette)
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
constexpr std::string_view kEntranceNames[]
constexpr std::string_view kRoomNames[]