yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_room_matrix_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_PANELS_DUNGEON_ROOM_MATRIX_PANEL_H_
2#define YAZE_APP_EDITOR_DUNGEON_PANELS_DUNGEON_ROOM_MATRIX_PANEL_H_
3
4#include <array>
5#include <cmath>
6#include <functional>
7#include <string>
8
11#include "app/gui/core/icons.h"
12#include "imgui/imgui.h"
13#include "zelda3/dungeon/room.h"
15
16namespace yaze {
17namespace editor {
18
34 public:
42 DungeonRoomMatrixPanel(int* current_room_id, ImVector<int>* active_rooms,
43 std::function<void(int)> on_room_selected,
44 std::array<zelda3::Room, 0x128>* rooms = nullptr)
45 : current_room_id_(current_room_id),
46 active_rooms_(active_rooms),
47 rooms_(rooms),
48 on_room_selected_(std::move(on_room_selected)) {}
49
50 // ==========================================================================
51 // EditorPanel Identity
52 // ==========================================================================
53
54 std::string GetId() const override { return "dungeon.room_matrix"; }
55 std::string GetDisplayName() const override { return "Room Matrix"; }
56 std::string GetIcon() const override { return ICON_MD_GRID_VIEW; }
57 std::string GetEditorCategory() const override { return "Dungeon"; }
58 int GetPriority() const override { return 30; }
59
60 // ==========================================================================
61 // EditorPanel Drawing
62 // ==========================================================================
63
64 void Draw(bool* p_open) override {
65 if (!current_room_id_ || !active_rooms_) return;
66
67 const auto& theme = AgentUI::GetTheme();
68
69 // 16 wide x 19 tall = 304 cells (296 rooms + 8 empty)
70 constexpr int kRoomsPerRow = 16;
71 constexpr int kRoomsPerCol = 19;
72 constexpr int kTotalRooms = 0x128; // 296 rooms (0x00-0x127)
73 constexpr float kCellSpacing = 1.0f;
74
75 // Responsive cell size based on available panel width
76 float panel_width = ImGui::GetContentRegionAvail().x;
77 // Calculate cell size to fit 16 cells with spacing in available width
78 float cell_size = std::max(12.0f, std::min(24.0f,
79 (panel_width - kCellSpacing * (kRoomsPerRow - 1)) / kRoomsPerRow));
80
81 ImDrawList* draw_list = ImGui::GetWindowDrawList();
82 ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
83
84 int room_index = 0;
85 for (int row = 0; row < kRoomsPerCol; row++) {
86 for (int col = 0; col < kRoomsPerRow; col++) {
87 int room_id = room_index;
88 bool is_valid_room = (room_id < kTotalRooms);
89
90 ImVec2 cell_min =
91 ImVec2(canvas_pos.x + col * (cell_size + kCellSpacing),
92 canvas_pos.y + row * (cell_size + kCellSpacing));
93 ImVec2 cell_max =
94 ImVec2(cell_min.x + cell_size, cell_min.y + cell_size);
95
96 if (is_valid_room) {
97 // Get color based on room palette if available, else use algorithmic
98 ImU32 bg_color = GetRoomColor(room_id, theme);
99
100 bool is_current = (*current_room_id_ == room_id);
101 bool is_open = false;
102 for (int i = 0; i < active_rooms_->Size; i++) {
103 if ((*active_rooms_)[i] == room_id) {
104 is_open = true;
105 break;
106 }
107 }
108
109 // Draw cell background
110 draw_list->AddRectFilled(cell_min, cell_max, bg_color);
111
112 // Draw outline based on state using theme colors
113 if (is_current) {
114 ImU32 sel_color = ImGui::ColorConvertFloat4ToU32(
115 theme.dungeon_selection_primary);
116 draw_list->AddRect(cell_min, cell_max, sel_color, 0.0f, 0, 2.5f);
117 } else if (is_open) {
118 ImU32 open_color = ImGui::ColorConvertFloat4ToU32(
119 theme.dungeon_grid_cell_selected);
120 draw_list->AddRect(cell_min, cell_max, open_color, 0.0f, 0, 2.0f);
121 } else {
122 ImU32 border_color = ImGui::ColorConvertFloat4ToU32(
123 theme.dungeon_grid_cell_border);
124 draw_list->AddRect(cell_min, cell_max, border_color, 0.0f, 0, 1.0f);
125 }
126
127 // Draw room ID (only if cell is large enough)
128 if (cell_size >= 18.0f) {
129 char label[8];
130 snprintf(label, sizeof(label), "%02X", room_id);
131 ImVec2 text_size = ImGui::CalcTextSize(label);
132 ImVec2 text_pos =
133 ImVec2(cell_min.x + (cell_size - text_size.x) * 0.5f,
134 cell_min.y + (cell_size - text_size.y) * 0.5f);
135 ImU32 text_color = ImGui::ColorConvertFloat4ToU32(
136 theme.dungeon_grid_text);
137 draw_list->AddText(text_pos, text_color, label);
138 }
139
140 // Handle clicks
141 ImGui::SetCursorScreenPos(cell_min);
142 char btn_id[32];
143 snprintf(btn_id, sizeof(btn_id), "##room%d", room_id);
144 ImGui::InvisibleButton(btn_id, ImVec2(cell_size, cell_size));
145
146 if (ImGui::IsItemClicked() && on_room_selected_) {
147 on_room_selected_(room_id);
148 }
149
150 // Tooltip with more info
151 if (ImGui::IsItemHovered()) {
152 ImGui::BeginTooltip();
153 // Use unified ResourceLabelProvider for room names
154 ImGui::Text("%s", zelda3::GetRoomLabel(room_id).c_str());
155 // Show palette info if room is loaded
156 if (rooms_ && (*rooms_)[room_id].IsLoaded()) {
157 ImGui::TextDisabled("Palette: %d", (*rooms_)[room_id].palette);
158 }
159 ImGui::Text("Click to %s", is_open ? "focus" : "open");
160 ImGui::EndTooltip();
161 }
162 } else {
163 // Empty cell
164 draw_list->AddRectFilled(cell_min, cell_max, IM_COL32(40, 40, 40, 255));
165 }
166
167 room_index++;
168 }
169 }
170
171 // Advance cursor past the grid
172 ImGui::Dummy(ImVec2(kRoomsPerRow * (cell_size + kCellSpacing),
173 kRoomsPerCol * (cell_size + kCellSpacing)));
174 }
175
176 void SetRooms(std::array<zelda3::Room, 0x128>* rooms) { rooms_ = rooms; }
177
178 private:
186 ImU32 GetRoomColor(int room_id, const AgentUITheme& theme) {
187 // If rooms data is available and this room is loaded, use palette-based color
188 if (rooms_ && (*rooms_)[room_id].IsLoaded()) {
189 int palette = (*rooms_)[room_id].palette;
190 // Map palette to distinct hues (there are ~24 dungeon palettes)
191 // Group similar palettes together for visual coherence
192 float hue = (palette * 15.0f); // Spread across 360 degrees
193 float saturation = 0.4f + (palette % 3) * 0.1f; // 40-60%
194 float value = 0.5f + (palette % 5) * 0.08f; // 50-82%
195
196 // HSV to RGB conversion
197 float h = fmodf(hue, 360.0f) / 60.0f;
198 int i = static_cast<int>(h);
199 float f = h - i;
200 float p = value * (1 - saturation);
201 float q = value * (1 - saturation * f);
202 float t = value * (1 - saturation * (1 - f));
203
204 float r, g, b;
205 switch (i % 6) {
206 case 0: r = value; g = t; b = p; break;
207 case 1: r = q; g = value; b = p; break;
208 case 2: r = p; g = value; b = t; break;
209 case 3: r = p; g = q; b = value; break;
210 case 4: r = t; g = p; b = value; break;
211 case 5: r = value; g = p; b = q; break;
212 default: r = g = b = 0.3f; break;
213 }
214 return IM_COL32(static_cast<int>(r * 255),
215 static_cast<int>(g * 255),
216 static_cast<int>(b * 255), 255);
217 }
218
219 // Fallback: Algorithmic coloring based on room ID
220 // Group rooms by their approximate dungeon (rooms are organized in blocks)
221 int dungeon_group = room_id / 0x20; // 32 rooms per rough dungeon block
222 float hue = (dungeon_group * 45.0f) + (room_id % 8) * 5.0f;
223 float saturation = 0.35f + (room_id % 3) * 0.1f;
224 float value = 0.45f + (room_id % 5) * 0.08f;
225
226 float h = fmodf(hue, 360.0f) / 60.0f;
227 int i = static_cast<int>(h);
228 float f = h - i;
229 float p = value * (1 - saturation);
230 float q = value * (1 - saturation * f);
231 float t = value * (1 - saturation * (1 - f));
232
233 float r, g, b;
234 switch (i % 6) {
235 case 0: r = value; g = t; b = p; break;
236 case 1: r = q; g = value; b = p; break;
237 case 2: r = p; g = value; b = t; break;
238 case 3: r = p; g = q; b = value; break;
239 case 4: r = t; g = p; b = value; break;
240 case 5: r = value; g = p; b = q; break;
241 default: r = g = b = 0.3f; break;
242 }
243 return IM_COL32(static_cast<int>(r * 255),
244 static_cast<int>(g * 255),
245 static_cast<int>(b * 255), 255);
246 }
247
248 int* current_room_id_ = nullptr;
249 ImVector<int>* active_rooms_ = nullptr;
250 std::array<zelda3::Room, 0x128>* rooms_ = nullptr;
251 std::function<void(int)> on_room_selected_;
252};
253
254} // namespace editor
255} // namespace yaze
256
257#endif // YAZE_APP_EDITOR_DUNGEON_PANELS_DUNGEON_ROOM_MATRIX_PANEL_H_
EditorPanel for displaying a visual 16x19 grid of all dungeon rooms.
std::string GetEditorCategory() const override
Editor category this panel belongs to.
int GetPriority() const override
Get display priority for menu ordering.
DungeonRoomMatrixPanel(int *current_room_id, ImVector< int > *active_rooms, std::function< void(int)> on_room_selected, std::array< zelda3::Room, 0x128 > *rooms=nullptr)
Construct a room matrix panel.
ImU32 GetRoomColor(int room_id, const AgentUITheme &theme)
Get color for a room based on palette or algorithmic fallback.
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
std::string GetId() const override
Unique identifier for this panel.
std::array< zelda3::Room, 0x128 > * rooms_
void Draw(bool *p_open) override
Draw the panel content.
void SetRooms(std::array< zelda3::Room, 0x128 > *rooms)
std::string GetIcon() const override
Material Design icon for this panel.
Base interface for all logical panel components.
#define ICON_MD_GRID_VIEW
Definition icons.h:897
const AgentUITheme & GetTheme()
std::string GetRoomLabel(int id)
Convenience function to get a room label.
Centralized theme colors for Agent UI components.