Wildvine Engine
Referencia Doxygen del codigo propio de Wildvine Engine.
Cargando...
Buscando...
Nada coincide
GUI.cpp
Ir a la documentación de este archivo.
1
7#include "Viewport.h"
8#include "Window.h"
9#include "Device.h"
10#include "DeviceContext.h"
11#include "MeshComponent.h"
12#include "ECS\Actor.h"
13#include "ECS\LightComponent.h"
15#include "Rendering\Mesh.h"
16#include "Rendering\Material.h"
19//#include "imgui_internal.h"
20static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE);
21static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL);
22
23namespace {
24const char* GetLightTypeLabel(LightType type);
25
26ImU32 AccentU32(const ImVec4& color) {
27 return ImGui::ColorConvertFloat4ToU32(color);
28}
29
30float RadToDeg(float radians) {
31 return XMConvertToDegrees(radians);
32}
33
34float DegToRad(float degrees) {
35 return XMConvertToRadians(degrees);
36}
37
38void DrawInspectorPill(const char* text, const ImVec4& color) {
39 ImGui::PushStyleColor(ImGuiCol_Button, color);
40 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color);
41 ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
42 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.0f);
43 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 4.0f));
44 ImGui::Button(text);
45 ImGui::PopStyleVar(2);
46 ImGui::PopStyleColor(3);
47}
48
49bool BeginInspectorSection(const char* label, bool defaultOpen = true) {
50 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_SpanAvailWidth;
51 if (defaultOpen) {
52 flags |= ImGuiTreeNodeFlags_DefaultOpen;
53 }
54
55 ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.16f, 0.18f, 0.22f, 0.95f));
56 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.20f, 0.23f, 0.28f, 1.0f));
57 ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.22f, 0.26f, 0.32f, 1.0f));
58 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
59 const bool open = ImGui::CollapsingHeader(label, flags);
60 ImGui::PopStyleVar();
61 ImGui::PopStyleColor(3);
62 return open;
63}
64
65bool BeginInspectorPropertyTable(const char* id, float firstColumnWidth = 132.0f) {
66 if (!ImGui::BeginTable(id, 2, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_BordersInnerV)) {
67 return false;
68 }
69
70 ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthFixed, firstColumnWidth);
71 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
72 return true;
73}
74
75void DrawPropertyLabel(const char* label) {
76 ImGui::TableNextRow();
77 ImGui::TableSetColumnIndex(0);
78 ImGui::AlignTextToFramePadding();
79 ImGui::TextDisabled("%s", label);
80 ImGui::TableSetColumnIndex(1);
81 ImGui::SetNextItemWidth(-FLT_MIN);
82}
83
84void DrawPropertyValueText(const char* label, const char* value) {
85 ImGui::TableNextRow();
86 ImGui::TableSetColumnIndex(0);
87 ImGui::AlignTextToFramePadding();
88 ImGui::TextDisabled("%s", label);
89 ImGui::TableSetColumnIndex(1);
90 ImGui::TextUnformatted(value);
91}
92
93void DrawPropertyValueBool(const char* label, bool value) {
94 DrawPropertyValueText(label, value ? "Yes" : "No");
95}
96
97void DrawPropertyToggle(const char* label, const char* id, bool* value) {
98 ImGui::TableNextRow();
99 ImGui::TableSetColumnIndex(0);
100 ImGui::AlignTextToFramePadding();
101 ImGui::TextDisabled("%s", label);
102 ImGui::TableSetColumnIndex(1);
103 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 6.0f);
104 ImGui::Checkbox(id, value);
105 ImGui::PopStyleVar();
106}
107
109 if (actor.isNull()) {
110 return "Actor";
111 }
112
113 auto lightComponent = actor->getComponent<LightComponent>();
114 if (!lightComponent.isNull()) {
115 return GetLightTypeLabel(lightComponent->getLightData().type);
116 }
117
118 if (!actor->getComponent<MeshRendererComponent>().isNull()) {
119 return "Static Mesh Actor";
120 }
121
122 if (!actor->getComponent<Transform>().isNull()) {
123 return "Empty Actor";
124 }
125
126 return "Actor";
127}
128
130 if (actor.isNull()) {
131 return ImVec4(0.45f, 0.47f, 0.52f, 1.0f);
132 }
133
134 auto lightComponent = actor->getComponent<LightComponent>();
135 if (!lightComponent.isNull()) {
136 return ImVec4(0.92f, 0.68f, 0.22f, 1.0f);
137 }
138
139 if (!actor->getComponent<MeshRendererComponent>().isNull()) {
140 return ImVec4(0.24f, 0.50f, 0.92f, 1.0f);
141 }
142
143 return ImVec4(0.36f, 0.72f, 0.46f, 1.0f);
144}
145
146void DrawInspectorComponentChips(bool hasTransform, bool hasMeshRenderer, bool hasLight) {
147 if (hasTransform) {
148 DrawInspectorPill("Transform", ImVec4(0.18f, 0.50f, 0.28f, 1.0f));
149 }
150 if (hasMeshRenderer) {
151 if (hasTransform) {
152 ImGui::SameLine();
153 }
154 DrawInspectorPill("Renderer", ImVec4(0.22f, 0.42f, 0.76f, 1.0f));
155 }
156 if (hasLight) {
157 if (hasTransform || hasMeshRenderer) {
158 ImGui::SameLine();
159 }
160 DrawInspectorPill("Light", ImVec4(0.62f, 0.46f, 0.14f, 1.0f));
161 }
162}
163
164const char* GetLightTypeLabel(LightType type) {
165 switch (type) {
166 case LightType::Directional: return "Directional";
167 case LightType::Point: return "Point";
168 case LightType::Spot: return "Spot";
169 default: return "Unknown";
170 }
171}
172
174 switch (domain) {
175 case MaterialDomain::Opaque: return "Opaque";
176 case MaterialDomain::Masked: return "Masked";
177 case MaterialDomain::Transparent: return "Transparent";
178 default: return "Unknown";
179 }
180}
181
182const char* GetBlendModeLabel(BlendMode blendMode) {
183 switch (blendMode) {
184 case BlendMode::Opaque: return "Opaque";
185 case BlendMode::Alpha: return "Alpha";
186 case BlendMode::Additive: return "Additive";
187 case BlendMode::PremultipliedAlpha: return "Premultiplied";
188 default: return "Unknown";
189 }
190}
191}
192void
193GUI::init(Window& window, Device& device, DeviceContext& deviceContext) {
194 // Setup Dear ImGui context
195 IMGUI_CHECKVERSION();
196 ImGui::CreateContext();
197 ImGuiIO& io = ImGui::GetIO();
198 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
199 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
200 // Setup Dear ImGui style
201 ImGui::StyleColorsDark();
202
203 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
204 ImGuiStyle& style = ImGui::GetStyle();
205 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
206 {
207 style.WindowRounding = 0.0f;
208 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
209 }
210
211 appleLiquidStyle(0.72f, ImVec4(0.0f, 0.515f, 1.0f, 1.0f));
212
213 // Setup Platform/Renderer backends
214 ImGui_ImplWin32_Init(window.m_hWnd);
215 ImGui_ImplDX11_Init(device.m_device, deviceContext.m_deviceContext);
216
217 // Init ToolTips
218 toolTipData();
219
221}
222
223void
224GUI::update(Viewport& viewport, Window& window) {
225 // Start the Dear ImGui frame
226 ImGui_ImplDX11_NewFrame();
227 ImGui_ImplWin32_NewFrame();
228 ImGui::NewFrame();
229
230 ImGuizmo::BeginFrame();
231 ImGuiIO& io = ImGui::GetIO();
232 if (io.KeyCtrl && ImGui::IsKeyPressed('S', false)) {
233 m_requestSaveScene = true;
234 }
235 ImGuizmo::SetOrthographic(false);
236 //ImGuizmo::SetRect(0, 0, (float)window.m_width, (float)window.m_height);
237
238 // In Program always
241 closeApp();
243}
244
245void
247 ImGui::Render();
248 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
249 ImGuiIO& io = ImGui::GetIO();
250 // Update and Render additional Platform Windows
251 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
252 {
253 ImGui::UpdatePlatformWindows();
254 ImGui::RenderPlatformWindowsDefault();
255 }
256}
257
258void
260 // Cleanup
261 ImGui_ImplDX11_Shutdown();
262 ImGui_ImplWin32_Shutdown();
263 ImGui::DestroyContext();
264}
265
266void
267GUI::vec3Control(const std::string& label, float* values, float resetValue, float columnWidth, bool displayAsDegrees) {
268 ImGuiIO& io = ImGui::GetIO();
269 auto boldFont = io.Fonts->Fonts[0];
270 float displayValues[3] = { values[0], values[1], values[2] };
271 if (displayAsDegrees) {
272 displayValues[0] = RadToDeg(values[0]);
273 displayValues[1] = RadToDeg(values[1]);
274 displayValues[2] = RadToDeg(values[2]);
275 }
276
277 ImGui::PushID(label.c_str());
278 if (!ImGui::BeginTable(("##Vec3Table" + label).c_str(), 2, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_BordersInnerV)) {
279 ImGui::PopID();
280 return;
281 }
282
283 ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
284 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
285 ImGui::TableNextRow();
286 ImGui::TableSetColumnIndex(0);
287 ImGui::AlignTextToFramePadding();
288 ImGui::TextDisabled("%s", label.c_str());
289 ImGui::TableSetColumnIndex(1);
290 ImGui::PushItemWidth(-1.0f);
291
292 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 3.0f, 4.0f });
293 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
294 float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
295 ImVec2 buttonSize = { lineHeight, lineHeight };
296 const float spacing = ImGui::GetStyle().ItemSpacing.x;
297 const float availableWidth = ImGui::GetContentRegionAvail().x;
298 const float dragWidth = (availableWidth - (buttonSize.x * 3.0f) - (spacing * 5.0f)) / 3.0f;
299 const float safeDragWidth = dragWidth > 24.0f ? dragWidth : 24.0f;
300 const float dragSpeed = displayAsDegrees ? 1.0f : 0.1f;
301 const char* dragFormat = displayAsDegrees ? "%.1f deg" : "%.2f";
302
303 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
304 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 0.2f, 0.2f, 1.0f });
305 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
306 ImGui::PushFont(boldFont);
307 if (ImGui::Button("X", buttonSize)) {
308 values[0] = resetValue;
309 displayValues[0] = displayAsDegrees ? RadToDeg(resetValue) : resetValue;
310 }
311 ImGui::PopFont();
312 ImGui::PopStyleColor(3);
313
314 ImGui::SameLine();
315 ImGui::SetNextItemWidth(safeDragWidth);
316 if (ImGui::DragFloat("##X", &displayValues[0], dragSpeed, 0.0f, 0.0f, dragFormat)) {
317 values[0] = displayAsDegrees ? DegToRad(displayValues[0]) : displayValues[0];
318 }
319 ImGui::SameLine();
320
321 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
322 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.3f, 0.8f, 0.3f, 1.0f });
323 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
324 ImGui::PushFont(boldFont);
325 if (ImGui::Button("Y", buttonSize)) {
326 values[1] = resetValue;
327 displayValues[1] = displayAsDegrees ? RadToDeg(resetValue) : resetValue;
328 }
329 ImGui::PopFont();
330 ImGui::PopStyleColor(3);
331
332 ImGui::SameLine();
333 ImGui::SetNextItemWidth(safeDragWidth);
334 if (ImGui::DragFloat("##Y", &displayValues[1], dragSpeed, 0.0f, 0.0f, dragFormat)) {
335 values[1] = displayAsDegrees ? DegToRad(displayValues[1]) : displayValues[1];
336 }
337 ImGui::SameLine();
338
339 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
340 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.2f, 0.35f, 0.9f, 1.0f });
341 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
342 ImGui::PushFont(boldFont);
343 if (ImGui::Button("Z", buttonSize)) {
344 values[2] = resetValue;
345 displayValues[2] = displayAsDegrees ? RadToDeg(resetValue) : resetValue;
346 }
347 ImGui::PopFont();
348 ImGui::PopStyleColor(3);
349
350 ImGui::SameLine();
351 ImGui::SetNextItemWidth(safeDragWidth);
352 if (ImGui::DragFloat("##Z", &displayValues[2], dragSpeed, 0.0f, 0.0f, dragFormat)) {
353 values[2] = displayAsDegrees ? DegToRad(displayValues[2]) : displayValues[2];
354 }
355
356 ImGui::PopStyleVar(2);
357 ImGui::PopItemWidth();
358 ImGui::EndTable();
359
360 ImGui::PopID();
361}
362
363void
366
367void
368GUI::appleLiquidStyle(float opacity, ImVec4 accent) {
369 ImGuiStyle& style = ImGui::GetStyle();
370 ImVec4* colors = style.Colors;
371
372 // Geometría suave tipo macOS
373 style.WindowRounding = 14.0f;
374 style.ChildRounding = 14.0f;
375 style.PopupRounding = 14.0f;
376 style.FrameRounding = 10.0f;
377 style.GrabRounding = 10.0f;
378 style.ScrollbarRounding = 12.0f;
379 style.TabRounding = 10.0f;
380
381 style.WindowBorderSize = 1.0f;
382 style.FrameBorderSize = 0.0f;
383 style.PopupBorderSize = 1.0f;
384 style.TabBorderSize = 0.0f;
385
386 style.WindowPadding = ImVec2(14, 12);
387 style.FramePadding = ImVec2(12, 8);
388 style.ItemSpacing = ImVec2(8, 8);
389 style.ItemInnerSpacing = ImVec2(8, 6);
390
391 const float o = opacity; // opacidad del “cristal”
392 const ImVec4 txt = ImVec4(1, 1, 1, 0.95f); // texto claro
393 const ImVec4 pane = ImVec4(0.16f, 0.16f, 0.18f, o); // panel “vidrioso” oscuro
394 const ImVec4 paneHi = ImVec4(0.20f, 0.20f, 0.22f, o);
395 const ImVec4 paneLo = ImVec4(0.13f, 0.13f, 0.15f, o * 0.85f);
396
397 // Colores base “glass”
398 colors[ImGuiCol_Text] = txt;
399 colors[ImGuiCol_TextDisabled] = ImVec4(1, 1, 1, 0.45f);
400 colors[ImGuiCol_WindowBg] = pane; // importante: con alpha
401 colors[ImGuiCol_ChildBg] = paneLo;
402 colors[ImGuiCol_PopupBg] = paneHi;
403 colors[ImGuiCol_Border] = ImVec4(1, 1, 1, 0.10f);
404 colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0.0f);
405
406 colors[ImGuiCol_FrameBg] = paneLo;
407 colors[ImGuiCol_FrameBgHovered] = pane;
408 colors[ImGuiCol_FrameBgActive] = paneHi;
409
410 colors[ImGuiCol_TitleBg] = pane;
411 colors[ImGuiCol_TitleBgActive] = paneHi;
412 colors[ImGuiCol_TitleBgCollapsed] = paneLo;
413
414 colors[ImGuiCol_MenuBarBg] = pane;
415
416 colors[ImGuiCol_ScrollbarBg] = ImVec4(0, 0, 0, 0.0f);
417 colors[ImGuiCol_ScrollbarGrab] = ImVec4(1, 1, 1, 0.10f);
418 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1, 1, 1, 0.18f);
419 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(1, 1, 1, 0.26f);
420
421 // Acento tipo macOS (azul #0A84FF por defecto)
422 colors[ImGuiCol_CheckMark] = accent;
423 colors[ImGuiCol_SliderGrab] = accent;
424 colors[ImGuiCol_SliderGrabActive] = ImVec4(accent.x, accent.y, accent.z, 1.0f);
425
426 colors[ImGuiCol_Button] = paneLo;
427 colors[ImGuiCol_ButtonHovered] = pane;
428 colors[ImGuiCol_ButtonActive] = paneHi;
429
430 colors[ImGuiCol_Header] = paneLo;
431 colors[ImGuiCol_HeaderHovered] = pane;
432 colors[ImGuiCol_HeaderActive] = paneHi;
433
434 colors[ImGuiCol_Separator] = ImVec4(1, 1, 1, 0.10f);
435 colors[ImGuiCol_SeparatorHovered] = ImVec4(1, 1, 1, 0.18f);
436 colors[ImGuiCol_SeparatorActive] = ImVec4(1, 1, 1, 0.30f);
437
438 colors[ImGuiCol_Tab] = paneLo;
439 colors[ImGuiCol_TabHovered] = pane;
440 colors[ImGuiCol_TabActive] = paneHi;
441 colors[ImGuiCol_TabUnfocused] = paneLo;
442 colors[ImGuiCol_TabUnfocusedActive] = pane;
443
444 colors[ImGuiCol_DockingPreview] = ImVec4(accent.x, accent.y, accent.z, 0.35f);
445 colors[ImGuiCol_DockingEmptyBg] = ImVec4(0, 0, 0, 0.0f);
446
447 colors[ImGuiCol_TableHeaderBg] = pane;
448 colors[ImGuiCol_TableBorderStrong] = ImVec4(1, 1, 1, 0.08f);
449 colors[ImGuiCol_TableBorderLight] = ImVec4(1, 1, 1, 0.04f);
450 colors[ImGuiCol_TableRowBg] = ImVec4(1, 1, 1, 0.03f);
451 colors[ImGuiCol_TableRowBgAlt] = ImVec4(1, 1, 1, 0.06f);
452
453 colors[ImGuiCol_TextSelectedBg] = ImVec4(accent.x, accent.y, accent.z, 0.35f);
454 colors[ImGuiCol_NavHighlight] = ImVec4(accent.x, accent.y, accent.z, 0.50f);
455 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1, 1, 1, 0.30f);
456 colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0, 0, 0, 0.20f);
457 colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0, 0, 0, 0.35f);
458}
459
460
461void
463 if (ImGui::BeginMainMenuBar()) {
464 if (ImGui::BeginMenu("File")) {
465 if (ImGui::MenuItem("New")) {
466 // Acción para "New"
467 }
468 if (ImGui::MenuItem("Open")) {
469 // Acción para "Open"
470 }
471 if (ImGui::MenuItem("Save")) {
472 // Acción para "Save"
473 }
474 if (ImGui::MenuItem("Exit")) {
475 // Acción para "Exit"
476 show_exit_popup = true;
477 ImGui::OpenPopup("Exit?");
478 //closeApp();
479 }
480 ImGui::EndMenu();
481 }
482 if (ImGui::BeginMenu("Edit")) {
483 if (ImGui::MenuItem("Undo")) {
484 // Acción para "Undo"
485 }
486 if (ImGui::MenuItem("Redo")) {
487 // Acción para "Redo"
488 }
489 if (ImGui::MenuItem("Cut")) {
490 // Acción para "Cut"
491 }
492 if (ImGui::MenuItem("Copy")) {
493 // Acción para "Copy"
494 }
495 if (ImGui::MenuItem("Paste")) {
496 // Acción para "Paste"
497 }
498 ImGui::EndMenu();
499 }
500 if (ImGui::BeginMenu("Tools")) {
501 if (ImGui::MenuItem("Options")) {
502 // Acción para "Options"
503 }
504 if (ImGui::MenuItem("Settings")) {
505 // Acción para "Settings"
506 }
507 ImGui::EndMenu();
508 }
509 ImGui::EndMainMenuBar();
510 }
511}
512
513void
515 if (show_exit_popup) {
516 ImGui::OpenPopup("Exit?");
517 show_exit_popup = false; // Reset the flag
518 }
519 // Centrar el popup en la pantalla
520 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
521 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
522
523 if (ImGui::BeginPopupModal("Exit?", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
524 ImGui::Text("Estas a punto de salir de la aplicacion.\nEstas seguro?\n\n");
525 ImGui::Separator();
526
527 if (ImGui::Button("OK", ImVec2(120, 0))) {
528 exit(0); // Salir de la aplicación
529 ImGui::CloseCurrentPopup();
530 }
531 ImGui::SetItemDefaultFocus();
532 ImGui::SameLine();
533 if (ImGui::Button("Cancel", ImVec2(120, 0))) {
534 ImGui::CloseCurrentPopup();
535 }
536 ImGui::EndPopup();
537 }
538}
539
540void
542 ImGui::Begin("Inspector");
543 if (actor.isNull()) {
544 ImGui::Dummy(ImVec2(0.0f, 12.0f));
545 ImGui::TextDisabled("No actor selected");
546 ImGui::TextWrapped("Select an actor in the Hierarchy to inspect transforms, materials, lights and renderer data.");
547 ImGui::End();
548 return;
549 }
550
551 static char objectName[128] = {};
552 static Actor* cachedActor = nullptr;
553 if (cachedActor != actor.get()) {
554 cachedActor = actor.get();
555 strncpy_s(objectName, actor->getName().c_str(), _TRUNCATE);
556 }
557
558 auto meshRenderer = actor->getComponent<MeshRendererComponent>();
559 auto lightComponent = actor->getComponent<LightComponent>();
560 auto transform = actor->getComponent<Transform>();
561 const bool hasMeshRenderer = !meshRenderer.isNull();
562 const bool hasLightComponent = !lightComponent.isNull();
563 const bool hasTransform = !transform.isNull();
564 const ImVec4 accentColor = GetActorTypeColor(actor);
565 const char* actorTypeLabel = GetActorTypeLabel(actor);
566
567 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 6.0f);
568 ImGui::BeginChild("##InspectorHeader", ImVec2(0.0f, 104.0f), true);
569 ImDrawList* drawList = ImGui::GetWindowDrawList();
570 ImVec2 headerMin = ImGui::GetWindowPos();
571 ImVec2 headerMax = ImVec2(headerMin.x + ImGui::GetWindowSize().x, headerMin.y + ImGui::GetWindowSize().y);
572 drawList->AddRectFilled(headerMin, ImVec2(headerMax.x, headerMin.y + 4.0f), AccentU32(accentColor), 6.0f, ImDrawFlags_RoundCornersTop);
573
574 ImGui::TextDisabled("Details");
575 ImGui::Text("Selected Actor");
576 ImGui::SameLine();
577 ImGui::TextDisabled("| %s", actorTypeLabel);
578 ImGui::SetNextItemWidth(-1.0f);
579 if (ImGui::InputText("##ObjectName", objectName, IM_ARRAYSIZE(objectName))) {
580 actor->setName(objectName);
581 }
582 ImGui::Spacing();
583 DrawInspectorComponentChips(hasTransform, hasMeshRenderer, hasLightComponent);
584 ImGui::Spacing();
585 ImGui::TextDisabled("Component details, rendering data and editable properties");
586 ImGui::EndChild();
587 ImGui::PopStyleVar();
588
589 ImGui::Spacing();
590 if (BeginInspectorSection("Identity")) {
591 if (BeginInspectorPropertyTable("##IdentityProperties")) {
592 DrawPropertyValueText("Name", actor->getName().c_str());
593 DrawPropertyValueText("Type", actorTypeLabel);
594 DrawPropertyValueBool("Transform", hasTransform);
595 DrawPropertyValueBool("Renderer", hasMeshRenderer);
596 DrawPropertyValueBool("Light", hasLightComponent);
597 ImGui::EndTable();
598 }
599 }
600
601 ImGui::Spacing();
602 if (hasTransform && BeginInspectorSection("Transform")) {
603 inspectorContainer(actor);
604 }
605
606 if (hasMeshRenderer) {
607 const std::vector<MaterialInstance*>& materialInstances = meshRenderer->getMaterialInstances();
608 Mesh* mesh = meshRenderer->getMesh();
609
610 if (BeginInspectorSection("Renderer")) {
611 const int submeshCount = mesh ? static_cast<int>(mesh->getSubmeshes().size()) : 0;
612 const int materialCount = static_cast<int>(materialInstances.size());
613 if (BeginInspectorPropertyTable("##RendererProperties")) {
614 bool isVisible = meshRenderer->isVisible();
615 DrawPropertyToggle("Visible", "##RendererVisible", &isVisible);
616 meshRenderer->setVisible(isVisible);
617
618 bool castShadow = meshRenderer->canCastShadow();
619 DrawPropertyToggle("Cast Shadow", "##RendererCastShadow", &castShadow);
620 meshRenderer->setCastShadow(castShadow);
621
622 char countBuffer[32] = {};
623 sprintf_s(countBuffer, "%d", submeshCount);
624 DrawPropertyValueText("Submeshes", countBuffer);
625
626 sprintf_s(countBuffer, "%d", materialCount);
627 DrawPropertyValueText("Material Slots", countBuffer);
628 ImGui::EndTable();
629 }
630 }
631
632 if (!materialInstances.empty() && BeginInspectorSection("Materials")) {
633 for (size_t i = 0; i < materialInstances.size(); ++i) {
634 MaterialInstance* materialInstance = materialInstances[i];
635 if (!materialInstance) {
636 continue;
637 }
638
639 MaterialParams& params = materialInstance->getParams();
640 Material* material = materialInstance->getMaterial();
641 std::string header = "Material Slot " + std::to_string(i);
642 if (ImGui::TreeNodeEx(header.c_str(), ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth)) {
643 if (material) {
644 if (BeginInspectorPropertyTable(("##MaterialMeta" + std::to_string(i)).c_str())) {
645 DrawPropertyValueText("Domain", GetMaterialDomainLabel(material->getDomain()));
646 if (material->getDomain() == MaterialDomain::Transparent) {
647 DrawPropertyValueText("Blend", GetBlendModeLabel(material->getBlendMode()));
648 }
649 ImGui::EndTable();
650 }
651
652 static const char* kMaterialDomains[] = { "Opaque", "Masked", "Transparent" };
653 int currentDomain = static_cast<int>(material->getDomain());
654 if (BeginInspectorPropertyTable(("##MaterialEditor" + std::to_string(i)).c_str())) {
655 DrawPropertyLabel("Domain");
656 if (ImGui::Combo(("##Domain" + std::to_string(i)).c_str(), &currentDomain, kMaterialDomains, IM_ARRAYSIZE(kMaterialDomains))) {
657 material->setDomain(static_cast<MaterialDomain>(currentDomain));
658 }
659
660 if (material->getDomain() == MaterialDomain::Transparent) {
661 static const char* kBlendModes[] = { "Opaque", "Alpha", "Additive", "Premultiplied" };
662 int currentBlendMode = static_cast<int>(material->getBlendMode());
663 DrawPropertyLabel("Blend Mode");
664 if (ImGui::Combo(("##BlendMode" + std::to_string(i)).c_str(), &currentBlendMode, kBlendModes, IM_ARRAYSIZE(kBlendModes))) {
665 material->setBlendMode(static_cast<BlendMode>(currentBlendMode));
666 }
667 }
668
669 DrawPropertyLabel("Base Color");
670 ImGui::ColorEdit4(("##BaseColor" + std::to_string(i)).c_str(), &params.baseColor.x);
671 DrawPropertyLabel("Metallic");
672 ImGui::SliderFloat(("##Metallic" + std::to_string(i)).c_str(), &params.metallic, 0.0f, 1.0f);
673 DrawPropertyLabel("Roughness");
674 ImGui::SliderFloat(("##Roughness" + std::to_string(i)).c_str(), &params.roughness, 0.0f, 1.0f);
675 DrawPropertyLabel("Ambient Occlusion");
676 ImGui::SliderFloat(("##AO" + std::to_string(i)).c_str(), &params.ao, 0.0f, 1.0f);
677 DrawPropertyLabel("Normal Scale");
678 ImGui::SliderFloat(("##NormalScale" + std::to_string(i)).c_str(), &params.normalScale, 0.0f, 2.0f);
679 if (materialInstance->getEmissive()) {
680 DrawPropertyLabel("Emissive Strength");
681 ImGui::SliderFloat(("##EmissiveStrength" + std::to_string(i)).c_str(), &params.emissiveStrength, 0.0f, 8.0f);
682 }
683 if (material->getDomain() == MaterialDomain::Masked) {
684 DrawPropertyLabel("Alpha Cutoff");
685 ImGui::SliderFloat(("##AlphaCutoff" + std::to_string(i)).c_str(), &params.alphaCutoff, 0.0f, 1.0f);
686 }
687 ImGui::EndTable();
688 }
689 }
690 ImGui::TreePop();
691 }
692 }
693 }
694 }
695
696 if (hasLightComponent && BeginInspectorSection("Light")) {
697 LightData& light = lightComponent->getLightData();
698 if (BeginInspectorPropertyTable("##LightProperties")) {
699 DrawPropertyValueText("Type", GetLightTypeLabel(light.type));
700 bool castShadow = lightComponent->canCastShadow();
701 DrawPropertyToggle("Cast Shadow", "##LightCastShadow", &castShadow);
702 lightComponent->setCastShadow(castShadow);
703 DrawPropertyLabel("Color");
704 ImGui::ColorEdit3("##LightColor", &light.color.x);
705 DrawPropertyLabel("Intensity");
706 ImGui::SliderFloat("##LightIntensity", &light.intensity, 0.0f, 10.0f);
707 if (light.type == LightType::Directional || light.type == LightType::Spot) {
708 DrawPropertyLabel("Direction");
709 ImGui::SliderFloat3("##LightDirection", &light.direction.x, -1.0f, 1.0f);
710 }
711 if (light.type == LightType::Point || light.type == LightType::Spot) {
712 DrawPropertyLabel("Range");
713 ImGui::SliderFloat("##LightRange", &light.range, 0.0f, 100.0f);
714 }
715 ImGui::EndTable();
716 }
717 }
718 ImGui::End();
719}
720
721void
723 //ImGui::Begin("Transform");
724 // Draw the structure
725 vec3Control("Position", const_cast<float*>(actor->getComponent<Transform>()->getPosition().data()), 0.0f, 78.0f, false);
726 vec3Control("Rotation", const_cast<float*>(actor->getComponent<Transform>()->getRotation().data()), 0.0f, 78.0f, true);
727 vec3Control("Scale", const_cast<float*>(actor->getComponent<Transform>()->getScale().data()), 1.0f, 78.0f, false);
728
729 //ImGui::End();
730}
731
732void
733GUI::outliner(const std::vector<EU::TSharedPointer<Actor>>& actors) {
734 ImGui::Begin("Hierarchy");
735
736 ImGui::TextDisabled("Scene");
737 static ImGuiTextFilter filter;
738 filter.Draw("Search...", -1.0f);
739
740 ImGui::Separator();
741
742 if (selectedActorIndex >= static_cast<int>(actors.size())) {
743 selectedActorIndex = actors.empty() ? -1 : static_cast<int>(actors.size()) - 1;
744 }
745
746 for (int i = 0; i < static_cast<int>(actors.size()); ++i) {
747 const auto& actor = actors[i];
748 std::string actorName = actor ? actor->getName() : "Actor";
749 const char* actorTypeLabel = GetActorTypeLabel(actor);
750 ImVec4 actorTypeColor = GetActorTypeColor(actor);
751 std::string filterLabel = actorName + " " + actorTypeLabel;
752 if (!filter.PassFilter(filterLabel.c_str())) {
753 continue;
754 }
755
756 auto meshRenderer = actor ? actor->getComponent<MeshRendererComponent>() : EU::TSharedPointer<MeshRendererComponent>();
757 auto lightComponent = actor ? actor->getComponent<LightComponent>() : EU::TSharedPointer<LightComponent>();
758 const bool hasMeshRenderer = !meshRenderer.isNull();
759 const bool hasLightComponent = !lightComponent.isNull();
760
761 ImGui::PushID(i);
762 const bool isSelected = (selectedActorIndex == i);
763 if (isSelected) {
764 ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.18f, 0.32f, 0.58f, 0.70f));
765 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.22f, 0.38f, 0.66f, 0.85f));
766 ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.24f, 0.42f, 0.72f, 0.95f));
767 }
768
769 ImVec2 rowSize(ImGui::GetContentRegionAvail().x, 42.0f);
770 if (ImGui::Selectable("##actorRow", isSelected, ImGuiSelectableFlags_SpanAvailWidth, rowSize)) {
772 }
773
774 ImVec2 min = ImGui::GetItemRectMin();
775 ImVec2 max = ImGui::GetItemRectMax();
776 ImDrawList* drawList = ImGui::GetWindowDrawList();
777 drawList->AddText(ImVec2(min.x + 12.0f, min.y + 6.0f), ImGui::GetColorU32(ImGuiCol_Text), actorName.c_str());
778 drawList->AddText(ImVec2(min.x + 12.0f, min.y + 23.0f), AccentU32(actorTypeColor), actorTypeLabel);
779
780 float badgeX = max.x - 84.0f;
781 if (hasMeshRenderer) {
782 drawList->AddRectFilled(ImVec2(badgeX, min.y + 12.0f), ImVec2(badgeX + 28.0f, min.y + 30.0f), IM_COL32(68, 118, 180, 180), 6.0f);
783 drawList->AddText(ImVec2(badgeX + 9.0f, min.y + 14.0f), IM_COL32(240, 244, 255, 255), "M");
784 badgeX += 40.0f;
785 }
786 if (hasLightComponent) {
787 drawList->AddRectFilled(ImVec2(badgeX, min.y + 12.0f), ImVec2(badgeX + 28.0f, min.y + 30.0f), IM_COL32(180, 142, 52, 180), 6.0f);
788 drawList->AddText(ImVec2(badgeX + 9.0f, min.y + 14.0f), IM_COL32(255, 248, 232, 255), "L");
789 }
790
791 if (isSelected) {
792 ImGui::PopStyleColor(3);
793 }
794 ImGui::PopID();
795 }
796
797 ImGui::End();
798}
799
801{
802 if (actor.isNull()) return;
803 auto transform = actor->getComponent<Transform>();
804 if (transform.isNull()) return;
805
806 float rectX = m_viewportPos.x;
807 float rectY = m_viewportPos.y;
808 float rectW = m_viewportSize.x;
809 float rectH = m_viewportSize.y;
810
811 if (rectW < 64.0f || rectH < 64.0f)
812 {
813 m_isUsingGizmo = false;
814 return;
815 }
816
817 float* pos = const_cast<float*>(transform->getPosition().data());
818 float* rot = const_cast<float*>(transform->getRotation().data());
819 float* sca = const_cast<float*>(transform->getScale().data());
820 float gizmoRotation[3] = {
821 RadToDeg(rot[0]),
822 RadToDeg(rot[1]),
823 RadToDeg(rot[2])
824 };
825
826 float mArr[16];
827 ImGuizmo::RecomposeMatrixFromComponents(pos, gizmoRotation, sca, mArr);
828
829 float vArr[16], pArr[16];
830 ToFloatArray(cam.getView(), vArr);
831 ToFloatArray(cam.getProj(), pArr);
832
833 ImGuizmo::SetOrthographic(false);
834
835 // MUY IMPORTANTE: usar el drawlist del viewport, no el actual
837 ImGuizmo::SetDrawlist(m_viewportDrawList);
838 else
839 ImGuizmo::SetDrawlist(ImGui::GetForegroundDrawList());
840
841 ImGuizmo::SetID(0);
842 ImGuizmo::SetGizmoSizeClipSpace(0.12f);
843 ImGuizmo::AllowAxisFlip(true);
844 ImGuizmo::SetRect(rectX, rectY, rectW, rectH);
845
846 float snapValue = 25.0f;
847 if (mCurrentGizmoOperation == ImGuizmo::ROTATE) snapValue = 1.0f;
848 if (mCurrentGizmoOperation == ImGuizmo::TRANSLATE) snapValue = 0.5f;
849
850 float snap[3] = { snapValue, snapValue, snapValue };
851 bool useSnap = ImGui::GetIO().KeyCtrl;
852 ImGuizmo::MODE activeGizmoMode = mCurrentGizmoMode;
853 if (mCurrentGizmoOperation == ImGuizmo::SCALE) {
854 activeGizmoMode = ImGuizmo::LOCAL;
855 }
856
857 ImGuizmo::Manipulate(
858 vArr,
859 pArr,
861 activeGizmoMode,
862 mArr,
863 nullptr,
864 useSnap ? snap : nullptr
865 );
866
867 m_isUsingGizmo = ImGuizmo::IsUsing();
868
869 if (m_isUsingGizmo)
870 {
871 float newPos[3], newRot[3], newSca[3];
872 ImGuizmo::DecomposeMatrixToComponents(mArr, newPos, newRot, newSca);
873
874 transform->setPosition(EU::Vector3(newPos[0], newPos[1], newPos[2]));
875 transform->setRotation(EU::Vector3(DegToRad(newRot[0]), DegToRad(newRot[1]), DegToRad(newRot[2])));
876 transform->setScale(EU::Vector3(newSca[0], newSca[1], newSca[2]));
877 }
878}
879
881{
882 //ImGui::SetNextWindowPos(ImVec2(300, 150), ImGuiCond_Always);
883 ImGui::SetNextWindowBgAlpha(0.0f); // 0 = transparente total
884
885 ImGuiWindowFlags window_flags =
886 ImGuiWindowFlags_NoDecoration |
887 ImGuiWindowFlags_AlwaysAutoResize |/*
888 ImGuiWindowFlags_NoMove |
889 ImGuiWindowFlags_NoSavedSettings |*/
890 ImGuiWindowFlags_NoFocusOnAppearing |
891 ImGuiWindowFlags_NoNav;
892
893 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
894
895 if (ImGui::Begin("GizmoToolBar", nullptr, window_flags))
896 {
897 auto buttonMode = [&](const char* label, ImGuizmo::OPERATION op, const char* shortcut)
898 {
899 bool isActive = (mCurrentGizmoOperation == op);
900 if (isActive)
901 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.4f, 0.8f, 1.0f));
902
903 if (ImGui::Button(label))
905
906 if (ImGui::IsItemHovered())
907 ImGui::SetTooltip("%s (%s)", label, shortcut);
908
909 if (isActive) ImGui::PopStyleColor();
910 ImGui::SameLine();
911 };
912
913 buttonMode("T", ImGuizmo::TRANSLATE, "W");
914 buttonMode("R", ImGuizmo::ROTATE, "E");
915 buttonMode("S", ImGuizmo::SCALE, "R");
916
917 const bool worldLocalSupported = (mCurrentGizmoOperation != ImGuizmo::SCALE);
918 if (!worldLocalSupported) {
919 ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
920 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
921 }
922 if (ImGui::Button(mCurrentGizmoMode == ImGuizmo::WORLD ? "Global" : "Local"))
923 mCurrentGizmoMode = (mCurrentGizmoMode == ImGuizmo::WORLD) ? ImGuizmo::LOCAL : ImGuizmo::WORLD;
924 if (!worldLocalSupported) {
925 ImGui::PopStyleVar();
926 ImGui::PopItemFlag();
927 if (ImGui::IsItemHovered()) {
928 ImGui::SetTooltip("Scale uses local orientation. World/Local affects Move and Rotate.");
929 }
930 }
931 }
932 ImGui::End();
933
934 ImGui::PopStyleVar();
935}
936
938{
939 // =========================================================
940 // CONFIGURACION GENERAL DE LA BARRA SUPERIOR TIPO STUDIO
941 // =========================================================
942 ImGuiViewport* viewport = ImGui::GetMainViewport();
943
944 const float menuBarHeight = 24.0f;
945 const float ribbonHeight = 72.0f;
946 const float totalHeight = menuBarHeight + ribbonHeight;
947
948 // -----------------------------
949 // 1) MENU SUPERIOR
950 // -----------------------------
951 ImGui::SetNextWindowPos(viewport->Pos, ImGuiCond_Always);
952 ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, menuBarHeight), ImGuiCond_Always);
953
954 ImGuiWindowFlags menuFlags =
955 ImGuiWindowFlags_NoDecoration |
956 ImGuiWindowFlags_NoMove |
957 ImGuiWindowFlags_NoSavedSettings |
958 ImGuiWindowFlags_NoScrollWithMouse |
959 ImGuiWindowFlags_NoScrollbar |
960 ImGuiWindowFlags_MenuBar;
961
962 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
963 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f, 4.0f));
964 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.10f, 0.11f, 0.14f, 1.0f));
965
966 if (ImGui::Begin("##StudioMenuBar", nullptr, menuFlags))
967 {
968 if (ImGui::BeginMenuBar())
969 {
970 if (ImGui::BeginMenu("File"))
971 {
972 ImGui::MenuItem("New Place");
973 ImGui::MenuItem("Open Place");
974 if (ImGui::MenuItem("Save", "Ctrl+S"))
975 {
976 m_requestSaveScene = true;
977 }
978 ImGui::Separator();
979 if (ImGui::MenuItem("Exit"))
980 {
981 show_exit_popup = true;
982 }
983 ImGui::EndMenu();
984 }
985
986 if (ImGui::BeginMenu("Edit"))
987 {
988 ImGui::MenuItem("Undo");
989 ImGui::MenuItem("Redo");
990 ImGui::Separator();
991 ImGui::MenuItem("Cut");
992 ImGui::MenuItem("Copy");
993 ImGui::MenuItem("Paste");
994 ImGui::EndMenu();
995 }
996
997 if (ImGui::BeginMenu("View"))
998 {
999 ImGui::MenuItem("Explorer");
1000 ImGui::MenuItem("Properties");
1001 ImGui::MenuItem("Toolbox");
1002 ImGui::EndMenu();
1003 }
1004
1005 if (ImGui::BeginMenu("Plugins"))
1006 {
1007 ImGui::MenuItem("Manage Plugins");
1008 ImGui::MenuItem("Plugin Folder");
1009 ImGui::EndMenu();
1010 }
1011
1012 if (ImGui::BeginMenu("Test"))
1013 {
1014 ImGui::MenuItem("Play");
1015 ImGui::MenuItem("Pause");
1016 ImGui::MenuItem("Stop");
1017 ImGui::EndMenu();
1018 }
1019
1020 if (ImGui::BeginMenu("Window"))
1021 {
1022 ImGui::MenuItem("Reset Layout");
1023 ImGui::EndMenu();
1024 }
1025
1026 if (ImGui::BeginMenu("Help"))
1027 {
1028 ImGui::MenuItem("Documentation");
1029 ImGui::MenuItem("About");
1030 ImGui::EndMenu();
1031 }
1032
1033 ImGui::EndMenuBar();
1034 }
1035 }
1036 ImGui::End();
1037
1038 ImGui::PopStyleColor();
1039 ImGui::PopStyleVar(2);
1040
1041 // -----------------------------
1042 // 2) RIBBON PRINCIPAL
1043 // -----------------------------
1044 ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x, viewport->Pos.y + menuBarHeight), ImGuiCond_Always);
1045 ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, ribbonHeight), ImGuiCond_Always);
1046
1047 ImGuiWindowFlags ribbonFlags =
1048 ImGuiWindowFlags_NoDecoration |
1049 ImGuiWindowFlags_NoMove |
1050 ImGuiWindowFlags_NoSavedSettings |
1051 ImGuiWindowFlags_NoScrollWithMouse |
1052 ImGuiWindowFlags_NoScrollbar;
1053
1054 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
1055 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f));
1056 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 6.0f));
1057 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.08f, 0.09f, 0.12f, 1.0f));
1058 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.14f, 0.15f, 0.19f, 1.0f));
1059 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.20f, 0.22f, 0.28f, 1.0f));
1060 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.24f, 0.26f, 0.34f, 1.0f));
1061
1062 if (ImGui::Begin("##StudioRibbon", nullptr, ribbonFlags))
1063 {
1064 auto ribbonButton = [&](const char* id, const char* topText, const char* bottomText, ImVec2 size, bool active = false) -> bool
1065 {
1066 if (active)
1067 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.24f, 0.34f, 0.58f, 1.0f));
1068
1069 bool pressed = ImGui::Button(id, size);
1070
1071 ImVec2 min = ImGui::GetItemRectMin();
1072 ImVec2 max = ImGui::GetItemRectMax();
1073
1074 // Texto centrado manualmente dentro del boton
1075 ImDrawList* drawList = ImGui::GetWindowDrawList();
1076
1077 ImVec2 topSize = ImGui::CalcTextSize(topText);
1078 ImVec2 bottomSize = ImGui::CalcTextSize(bottomText);
1079
1080 float centerX = (min.x + max.x) * 0.5f;
1081
1082 drawList->AddText(
1083 ImVec2(centerX - topSize.x * 0.5f, min.y + 10.0f),
1084 ImGui::GetColorU32(ImGuiCol_Text),
1085 topText
1086 );
1087
1088 drawList->AddText(
1089 ImVec2(centerX - bottomSize.x * 0.5f, min.y + 34.0f),
1090 ImGui::GetColorU32(ImGuiCol_TextDisabled),
1091 bottomText
1092 );
1093
1094 if (active)
1095 ImGui::PopStyleColor();
1096
1097 return pressed;
1098 };
1099
1100 auto separatorGroup = [&]()
1101 {
1102 ImGui::SameLine();
1103 ImGui::Dummy(ImVec2(6.0f, 1.0f));
1104 ImGui::SameLine();
1105
1106 ImVec2 p = ImGui::GetCursorScreenPos();
1107 ImDrawList* draw = ImGui::GetWindowDrawList();
1108 draw->AddLine(
1109 ImVec2(p.x, p.y),
1110 ImVec2(p.x, p.y + 48.0f),
1111 IM_COL32(80, 80, 90, 255),
1112 1.0f
1113 );
1114
1115 ImGui::Dummy(ImVec2(8.0f, 48.0f));
1116 ImGui::SameLine();
1117 };
1118
1119 const ImVec2 btnSize(72.0f, 52.0f);
1120
1121 // Herramientas de transformacion
1122 if (ribbonButton("##Select", "Select", "Cursor", btnSize, false))
1123 {
1124 // modo seleccion
1125 }
1126 ImGui::SameLine();
1127
1128 if (ribbonButton("##Move", "Move", "W", btnSize, mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
1129 {
1130 mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
1131 }
1132 ImGui::SameLine();
1133
1134 if (ribbonButton("##Scale", "Scale", "R", btnSize, mCurrentGizmoOperation == ImGuizmo::SCALE))
1135 {
1136 mCurrentGizmoOperation = ImGuizmo::SCALE;
1137 }
1138 ImGui::SameLine();
1139
1140 if (ribbonButton("##Rotate", "Rotate", "E", btnSize, mCurrentGizmoOperation == ImGuizmo::ROTATE))
1141 {
1142 mCurrentGizmoOperation = ImGuizmo::ROTATE;
1143 }
1144 ImGui::SameLine();
1145
1146 if (ribbonButton("##Transform", "Transform", "Tool", btnSize, false))
1147 {
1148 // herramienta extra
1149 }
1150
1151 separatorGroup();
1152
1153 // Creacion / escena
1154 if (ribbonButton("##Part", "Part", "Mesh", btnSize, false))
1155 {
1156 // crear parte
1157 }
1158 ImGui::SameLine();
1159
1160 if (ribbonButton("##Terrain", "Terrain", "Edit", btnSize, false))
1161 {
1162 // abrir terrain tools
1163 }
1164 ImGui::SameLine();
1165
1166 if (ribbonButton("##Material", "Material", "Editor", btnSize, false))
1167 {
1168 // material editor
1169 }
1170 ImGui::SameLine();
1171
1172 if (ribbonButton("##Color", "Color", "Picker", btnSize, false))
1173 {
1174 // color picker
1175 }
1176
1177 separatorGroup();
1178
1179 // Ventanas / paneles
1180 if (ribbonButton("##Explorer", "Explorer", "Panel", btnSize, false))
1181 {
1182 // toggle explorer
1183 }
1184 ImGui::SameLine();
1185
1186 if (ribbonButton("##Properties", "Properties", "Panel", btnSize, false))
1187 {
1188 // toggle properties
1189 }
1190 ImGui::SameLine();
1191
1192 if (ribbonButton("##Toolbox", "Toolbox", "Assets", btnSize, false))
1193 {
1194 // toggle toolbox
1195 }
1196 }
1197 ImGui::End();
1198
1199 ImGui::PopStyleColor(4);
1200 ImGui::PopStyleVar(3);
1201}
1202
1203void GUI::drawViewportPanel(ID3D11ShaderResourceView* viewportSRV)
1204{
1205 ImGuiWindowFlags flags =
1206 ImGuiWindowFlags_NoScrollbar |
1207 ImGuiWindowFlags_NoScrollWithMouse |
1208
1209 ImGuiWindowFlags_NoCollapse;
1210
1211 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
1212
1213 if (ImGui::Begin("Viewport", nullptr, flags))
1214 {
1215 m_viewportDrawList = ImGui::GetWindowDrawList();
1216
1217 ImVec2 panelMin = ImGui::GetCursorScreenPos();
1218 ImVec2 panelSize = ImGui::GetContentRegionAvail();
1219
1220 if (panelSize.x < 1.0f) panelSize.x = 1.0f;
1221 if (panelSize.y < 1.0f) panelSize.y = 1.0f;
1222
1223 if (viewportSRV)
1224 {
1225 ImGui::Image((ImTextureID)viewportSRV, panelSize);
1226 }
1227 else
1228 {
1229 ImGui::InvisibleButton("##ViewportSurface", panelSize);
1230 ImVec2 itemMin = ImGui::GetItemRectMin();
1231 ImVec2 itemMax = ImGui::GetItemRectMax();
1232 ImDrawList* drawList = ImGui::GetWindowDrawList();
1233
1234 drawList->AddRectFilled(itemMin, itemMax, IM_COL32(20, 20, 25, 255));
1235 drawList->AddText(
1236 ImVec2(itemMin.x + 12.0f, itemMin.y + 12.0f),
1237 IM_COL32(220, 220, 220, 255),
1238 "Viewport sin textura"
1239 );
1240 }
1241
1242 ImVec2 itemMin = ImGui::GetItemRectMin();
1243 ImVec2 itemMax = ImGui::GetItemRectMax();
1244 m_viewportPos = itemMin;
1245 m_viewportSize = ImVec2(itemMax.x - itemMin.x, itemMax.y - itemMin.y);
1246
1247 // IMPORTANTE: el hover/active del item imagen
1248 m_viewportHovered = ImGui::IsItemHovered();
1249 m_viewportActive = ImGui::IsItemActive();
1250 m_viewportFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
1251 }
1252 ImGui::End();
1253
1254 ImGui::PopStyleVar();
1255}
1256
1257void GUI::drawRenderDebugPanel(ID3D11ShaderResourceView* preShadowSRV,
1258 ID3D11ShaderResourceView* finalViewportSRV,
1259 ID3D11ShaderResourceView* shadowMapSRV)
1260{
1261 ImGui::Begin("Render Debug");
1262
1263 struct DebugViewItem {
1264 const char* label;
1265 ID3D11ShaderResourceView* srv;
1266 };
1267
1268 DebugViewItem items[] = {
1269 { "Pre-Shadow", preShadowSRV },
1270 { "Scene Final", finalViewportSRV },
1271 { "Shadow Map", shadowMapSRV }
1272 };
1273
1274 static int selectedView = 0;
1275 const float thumbnailHeight = 120.0f;
1276
1277 ImGui::TextDisabled("Generated pass textures");
1278 ImGui::Separator();
1279
1280 for (int i = 0; i < IM_ARRAYSIZE(items); ++i) {
1281 ImGui::PushID(i);
1282 if (ImGui::Selectable(items[i].label, selectedView == i, 0, ImVec2(0.0f, 20.0f))) {
1283 selectedView = i;
1284 }
1285
1286 if (items[i].srv) {
1287 const float thumbnailWidth = thumbnailHeight * 1.6f;
1288 ImGui::Image((ImTextureID)items[i].srv, ImVec2(thumbnailWidth, thumbnailHeight));
1289 }
1290 else {
1291 ImGui::Dummy(ImVec2(thumbnailHeight * 1.6f, thumbnailHeight));
1292 ImGui::SameLine(0.0f, 0.0f);
1293 ImGui::TextDisabled("Unavailable");
1294 }
1295
1296 if (i + 1 < IM_ARRAYSIZE(items)) {
1297 ImGui::Separator();
1298 }
1299 ImGui::PopID();
1300 }
1301
1302 ImGui::Separator();
1303 ImGui::Text("Focused View: %s", items[selectedView].label);
1304
1305 ImVec2 available = ImGui::GetContentRegionAvail();
1306 if (items[selectedView].srv && available.x > 16.0f && available.y > 16.0f) {
1307 ImGui::Image((ImTextureID)items[selectedView].srv, available);
1308 }
1309 else {
1310 ImGui::Dummy(available);
1311 ImGui::SameLine(0.0f, 0.0f);
1312 ImGui::TextDisabled("No texture bound for this view");
1313 }
1314
1315 ImGui::End();
1316}
1317
1319{
1320 ImGuiViewport* mainViewport = ImGui::GetMainViewport();
1321
1322 // Debe coincidir con la altura total que ocupa tu ribbon superior
1323 const float topOffset = 96.0f; // 24 menu + 72 ribbon
1324
1325 ImVec2 dockPos = ImVec2(mainViewport->Pos.x, mainViewport->Pos.y + topOffset);
1326 ImVec2 dockSize = ImVec2(mainViewport->Size.x, mainViewport->Size.y - topOffset);
1327
1328 ImGuiWindowFlags window_flags =
1329 ImGuiWindowFlags_NoTitleBar |
1330 ImGuiWindowFlags_NoCollapse |
1331 ImGuiWindowFlags_NoResize |
1332 ImGuiWindowFlags_NoMove |
1333 ImGuiWindowFlags_NoBringToFrontOnFocus |
1334 ImGuiWindowFlags_NoNavFocus |
1335 ImGuiWindowFlags_NoBackground |
1336 ImGuiWindowFlags_NoDecoration |
1337 ImGuiWindowFlags_NoSavedSettings |
1338 ImGuiWindowFlags_MenuBar;
1339
1340 ImGui::SetNextWindowPos(dockPos, ImGuiCond_Always);
1341 ImGui::SetNextWindowSize(dockSize, ImGuiCond_Always);
1342 ImGui::SetNextWindowViewport(mainViewport->ID);
1343
1344 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
1345 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
1346 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
1347
1348 ImGui::Begin("##MainEditorDockspace", nullptr, window_flags);
1349
1350 ImGuiID dockspace_id = ImGui::GetID("##EditorDockspace");
1351 ImGuiDockNodeFlags dockspace_flags =
1352 ImGuiDockNodeFlags_None |
1353 ImGuiDockNodeFlags_PassthruCentralNode;
1354
1355 ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
1356
1357 ImGui::End();
1358
1359 ImGui::PopStyleVar(3);
1360}
1361
Declara la API de Actor dentro del subsistema ECS.
Declara la API de Camera dentro del subsistema Utilities.
Declara la API de DeviceContext dentro del subsistema Core.
Declara la API de Device dentro del subsistema Core.
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL)
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE)
Declara la API de GUI dentro del subsistema GUI.
Declara la API de LightComponent dentro del subsistema ECS.
Declara la API de MaterialInstance dentro del subsistema Rendering.
Declara la API de Material dentro del subsistema Rendering.
Declara la API de MeshComponent dentro del subsistema Core.
Declara la API de MeshRendererComponent dentro del subsistema ECS.
Declara la API de Mesh dentro del subsistema Rendering.
BlendMode
Definition RenderTypes.h:20
@ PremultipliedAlpha
MaterialDomain
Definition RenderTypes.h:13
LightType
Definition RenderTypes.h:37
Declara la API de Viewport dentro del subsistema Core.
Declara la API de Window dentro del subsistema Core.
Representa una entidad gráfica con mallas, texturas y estados de renderizado.
Definition Actor.h:32
XMMATRIX getView() const
Matriz View (mundo->vista).
Definition Camera.h:113
XMMATRIX getProj() const
Matriz Projection (vista->clip).
Definition Camera.h:119
ID3D11DeviceContext * m_deviceContext
Puntero al contexto inmediato de Direct3D 11.
Encapsula un ID3D11Device y facilita la creación de recursos gráficos en Direct3D 11.
Definition Device.h:21
ID3D11Device * m_device
Puntero al dispositivo Direct3D 11.
Definition Device.h:146
Clase TSharedPointer para manejar la gestión de memoria compartida.
bool isNull() const
Comprobar si el puntero es nulo.
T * get() const
Obtener el puntero crudo.
A 3D vector class.
Definition Vector3.h:45
float x
The x-coordinate of the vector.
Definition Vector3.h:47
float * data()
Definition Vector3.h:153
void toolTipData()
Definition GUI.cpp:364
void editTransform(Camera &cam, Window &window, EU::TSharedPointer< Actor > actor)
Definition GUI.cpp:800
void inspectorGeneral(EU::TSharedPointer< Actor > actor)
Definition GUI.cpp:541
bool m_requestSaveScene
Definition GUI.h:133
void destroy()
Definition GUI.cpp:259
int selectedActorIndex
Indice del actor seleccionado en el outliner.
Definition GUI.h:139
void drawEditorDockspace()
Definition GUI.cpp:1318
void init(Window &window, Device &device, DeviceContext &deviceContext)
Configura los backends de ImGui para Win32 y Direct3D 11.
Definition GUI.cpp:193
void drawRenderDebugPanel(ID3D11ShaderResourceView *preShadowSRV, ID3D11ShaderResourceView *finalViewportSRV, ID3D11ShaderResourceView *shadowMapSRV)
Definition GUI.cpp:1257
ImDrawList * m_viewportDrawList
Definition GUI.h:134
void update(Viewport &viewport, Window &window)
Actualiza el frame de ImGui y el estado de la ventana del editor.
Definition GUI.cpp:224
bool m_viewportFocused
Indica si el viewport tiene foco de entrada.
Definition GUI.h:143
void drawStudioTopRibbon()
Definition GUI.cpp:937
ImVec2 m_viewportPos
Posicion del panel de viewport en pantalla.
Definition GUI.h:140
bool m_viewportHovered
Indica si el cursor esta sobre el viewport.
Definition GUI.h:142
void drawViewportPanel(ID3D11ShaderResourceView *viewportSRV)
Definition GUI.cpp:1203
void vec3Control(const std::string &label, float *values, float resetValues=0.0f, float columnWidth=100.0f, bool displayAsDegrees=false)
Definition GUI.cpp:267
bool show_exit_popup
Definition GUI.h:132
bool m_viewportActive
Definition GUI.h:135
bool m_isUsingGizmo
Indica si el gizmo esta capturando entrada del usuario.
Definition GUI.h:138
void ToolBar()
Definition GUI.cpp:462
void inspectorContainer(EU::TSharedPointer< Actor > actor)
Definition GUI.cpp:722
ImVec2 m_viewportSize
Tamano actual del viewport del editor.
Definition GUI.h:141
void ToFloatArray(const XMMATRIX &mat, float *dest)
Definition GUI.h:97
void closeApp()
Definition GUI.cpp:514
void outliner(const std::vector< EU::TSharedPointer< Actor > > &actors)
Definition GUI.cpp:733
void drawGizmoToolbar()
Definition GUI.cpp:880
void render()
Renderiza todos los paneles activos del editor.
Definition GUI.cpp:246
void appleLiquidStyle(float opacity, ImVec4 accent)
Definition GUI.cpp:368
Agrupa un material base con sus texturas y parametros concretos.
Material * getMaterial() const
MaterialParams & getParams()
Texture * getEmissive() const
Describe el estado fijo compartido por una o mas instancias de material.
Definition Material.h:23
void setDomain(MaterialDomain domain)
Definition Material.h:29
BlendMode getBlendMode() const
Definition Material.h:37
void setBlendMode(BlendMode blendMode)
Definition Material.h:30
MaterialDomain getDomain() const
Definition Material.h:36
Agrupa una coleccion de submallas listas para ser renderizadas.
Definition Mesh.h:28
std::vector< Submesh > & getSubmeshes()
Definition Mesh.h:30
const EU::Vector3 & getRotation() const
Definition Transform.h:68
const EU::Vector3 & getPosition() const
Definition Transform.h:59
const EU::Vector3 & getScale() const
Definition Transform.h:77
Encapsula un D3D11_VIEWPORT para definir la región de renderizado en la pantalla.
Definition Viewport.h:24
Encapsula la creacion y administracion de la ventana principal de Win32.
Definition Window.h:20
HWND m_hWnd
Handle de la ventana nativa.
Definition Window.h:46
void DrawPropertyLabel(const char *label)
Definition GUI.cpp:75
const char * GetLightTypeLabel(LightType type)
Definition GUI.cpp:164
float RadToDeg(float radians)
Definition GUI.cpp:30
bool BeginInspectorSection(const char *label, bool defaultOpen=true)
Definition GUI.cpp:49
void DrawPropertyValueBool(const char *label, bool value)
Definition GUI.cpp:93
bool BeginInspectorPropertyTable(const char *id, float firstColumnWidth=132.0f)
Definition GUI.cpp:65
void DrawPropertyToggle(const char *label, const char *id, bool *value)
Definition GUI.cpp:97
void DrawInspectorPill(const char *text, const ImVec4 &color)
Definition GUI.cpp:38
const char * GetActorTypeLabel(EU::TSharedPointer< Actor > actor)
Definition GUI.cpp:108
const char * GetMaterialDomainLabel(MaterialDomain domain)
Definition GUI.cpp:173
ImVec4 GetActorTypeColor(EU::TSharedPointer< Actor > actor)
Definition GUI.cpp:129
void DrawInspectorComponentChips(bool hasTransform, bool hasMeshRenderer, bool hasLight)
Definition GUI.cpp:146
void DrawPropertyValueText(const char *label, const char *value)
Definition GUI.cpp:84
ImU32 AccentU32(const ImVec4 &color)
Definition GUI.cpp:26
float DegToRad(float degrees)
Definition GUI.cpp:34
const char * GetBlendModeLabel(BlendMode blendMode)
Definition GUI.cpp:182
EU::Vector3 color
Definition RenderTypes.h:46
LightType type
Definition RenderTypes.h:45
float range
Definition RenderTypes.h:50
EU::Vector3 direction
Definition RenderTypes.h:49
float intensity
Definition RenderTypes.h:47
float emissiveStrength
Definition RenderTypes.h:63
XMFLOAT4 baseColor
Definition RenderTypes.h:58