Khaotic Engine Reborn
Loading...
Searching...
No Matches
imguiManager.cpp
1#include "imguiManager.h"
2#include "application_class.h"
3#include "stats.h"
4
5static fps_limiter fpsLimiter(60.0f);
6
8{
9 io = nullptr;
10 m_frameTimeHistoryIndex = 0;
11
12 current_fps_ = 0;
13 min_fps_ = 0;
14 max_fps_ = 0;
15 draw_calls_ = 0;
16 total_vertex_count_ = 0;
17 total_triangle_count_ = 0;
18 visible_triangle_count_ = 0;
19 current_frame_time_ = 0;
20
21 showObjectWindow = false;
22 showTerrainWindow = false;
23 showLightWindow = false;
24 showOldSceneWindow = false;
25 showEngineSettingsWindow = false;
26 showLogWindow = false;
27 showStatsWindow = false;
28
29 // Initialiser l'historique des frametimes à zéro
30 for (int i = 0; i < FRAME_HISTORY_COUNT; i++)
31 {
32 m_frameTimeHistory[i] = 0.0f;
33 }
34
35 widgets_ = {
36 {&showObjectWindow, [&](){WidgetObjectWindow();}},
37 {&showEngineSettingsWindow, [&](){WidgetEngineSettingsWindow();}},
38 {&showTerrainWindow, [&](){WidgetTerrainWindow();}},
39 {&showLightWindow, [&](){WidgetLightWindow();}},
40 {&showLogWindow, [&](){WidgetLogWindow();}},
41 {&showOldSceneWindow, [&](){WidgetRenderWindow(ImVec2(800, 600));}},
42 {&showStatsWindow, [&](){WidgetRenderStats();}}
43 };
44}
45
46imguiManager::~imguiManager()
47{
48}
49
50bool imguiManager::Initialize(HWND hwnd, ID3D11Device* device, ID3D11DeviceContext* deviceContext)
51{
52 Logger::Get().Log("Initializing imgui", __FILE__, __LINE__, Logger::LogLevel::Initialize);
53
54 m_device = device;
55 m_deviceContext = deviceContext;
56
57 IMGUI_CHECKVERSION();
58 ImGui::CreateContext();
59 io = &ImGui::GetIO();
60 io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
61 io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
62 io->FontGlobalScale = 1.0f;
63
64 ImGui_ImplWin32_Init(hwnd);
65 ImGui_ImplDX11_Init(m_device, m_deviceContext);
66
67 // Appliquer un thème sombre de base
68 ImGui::StyleColorsDark();
69
70 // Définir les couleurs pour une interface de type éditeur sobre
71 ImGuiStyle& style = ImGui::GetStyle();
72
73 // Palette de couleurs sobres inspirée des éditeurs modernes
74 ImVec4 background_dark = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); // Fond foncé
75 ImVec4 background = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); // Fond principal
76 ImVec4 background_light = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); // Fond clair
77 ImVec4 accent = ImVec4(0.14f, 0.44f, 0.80f, 0.50f); // Accent bleu
78 ImVec4 accent_light = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); // Accent bleu vif
79 ImVec4 text = ImVec4(1.0f, 1.0f, 1.0f, 1.00f); // Texte plus blanc
80 ImVec4 text_dim = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
81
82 // Ajustements de style généraux
83 style.WindowPadding = ImVec2(4.0f, 4.0f); // Moins de padding dans les fenêtres
84 style.FramePadding = ImVec2(4.0f, 3.0f); // Moins de padding dans les cadres
85 style.ItemSpacing = ImVec2(4.0f, 3.0f); // Moins d'espace entre les widgets
86 style.ItemInnerSpacing = ImVec2(3.0f, 3.0f); // Moins d'espace interne
87 style.DisplayWindowPadding = ImVec2(0.0f, 0.0f); // Pas de padding pour l'affichage
88 style.DisplaySafeAreaPadding = ImVec2(0.0f, 0.0f);
89 style.TouchExtraPadding = ImVec2(0.0f, 0.0f);
90 style.IndentSpacing = 20.0f;
91 style.ScrollbarSize = 14.0f;
92 style.GrabMinSize = 10.0f;
93
94 // Arrondis
95 style.WindowRounding = 4.0f;
96 style.ChildRounding = 4.0f;
97 style.FrameRounding = 3.0f;
98 style.PopupRounding = 4.0f;
99 style.ScrollbarRounding = 9.0f;
100 style.GrabRounding = 3.0f;
101 style.TabRounding = 4.0f;
102
103 // Couleurs principales
104 style.Colors[ImGuiCol_Text] = text;
105 style.Colors[ImGuiCol_TextDisabled] = text_dim;
106 style.Colors[ImGuiCol_WindowBg] = background;
107 style.Colors[ImGuiCol_ChildBg] = background_dark;
108 style.Colors[ImGuiCol_PopupBg] = background_dark;
109 style.Colors[ImGuiCol_Border] = ImVec4(0.25f, 0.25f, 0.27f, 1.00f);
110 style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
111
112 // Encadrements
113 style.Colors[ImGuiCol_FrameBg] = background_light;
114 style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
115 style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
116
117 // Titres
118 style.Colors[ImGuiCol_TitleBg] = background_dark;
119 style.Colors[ImGuiCol_TitleBgActive] = accent;
120 style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.12f, 0.12f, 0.12f, 0.90f);
121
122 // Éléments de menu
123 style.Colors[ImGuiCol_MenuBarBg] = background_dark;
124 style.Colors[ImGuiCol_ScrollbarBg] = background_dark;
125 style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
126 style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
127 style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
128
129 // Boutons et interactions
130 style.Colors[ImGuiCol_CheckMark] = accent_light;
131 style.Colors[ImGuiCol_SliderGrab] = accent;
132 style.Colors[ImGuiCol_SliderGrabActive] = accent_light;
133 style.Colors[ImGuiCol_Button] = background_light;
134 style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
135 style.Colors[ImGuiCol_ButtonActive] = accent;
136
137 // En-têtes et onglets
138 style.Colors[ImGuiCol_Header] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
139 style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
140 style.Colors[ImGuiCol_HeaderActive] = accent;
141
142 style.Colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.28f, 1.00f);
143 style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f);
144 style.Colors[ImGuiCol_SeparatorActive] = accent;
145
146 style.Colors[ImGuiCol_Tab] = background_dark;
147 style.Colors[ImGuiCol_TabHovered] = accent;
148 style.Colors[ImGuiCol_TabActive] = accent;
149 style.Colors[ImGuiCol_TabUnfocused] = background_dark;
150 style.Colors[ImGuiCol_TabUnfocusedActive] = background;
151
152 // Autres éléments
153 style.Colors[ImGuiCol_DockingPreview] = accent;
154 style.Colors[ImGuiCol_DockingEmptyBg] = background_light;
155
156 // Charger une police avec une meilleure netteté
157 ImFontConfig fontConfig;
158 fontConfig.OversampleH = 2; // Suréchantillonnage horizontal
159 fontConfig.OversampleV = 2; // Suréchantillonnage vertical
160 fontConfig.PixelSnapH = true; // Alignement sur la grille de pixels
161 fontConfig.RasterizerMultiply = 1.2f; // Légère augmentation de l'épaisseur
162 io->Fonts->AddFontDefault(&fontConfig);
163
164 io->Fonts->Build();
165
166 // OU charger une police personnalisée (décommenter si vous avez la police)
167 // io->Fonts->AddFontFromFileTTF("assets/fonts/roboto.ttf", 16.0f, &fontConfig);
168
169
170 unsigned char* pixels;
171 int width, height;
172 io->Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
173
174 // initialize the scene manager
175 scene_manager_ = new scene_manager;
176 if (!scene_manager_->initialize(app_.get())) {
177 Logger::Get().Log("Failed to initialize scene manager", __FILE__, __LINE__, Logger::LogLevel::Error);
178 return false;
179 }
180
181 stats_ = app_->get_stats();
182
183 total_triangle_count_ = stats_->get_triangle_count_ptr();
184 total_vertex_count_ = stats_->get_vertex_count_ptr();
185
186 Logger::Get().Log("imgui initialized", __FILE__, __LINE__, Logger::LogLevel::Initialize);
187
188 return true;
189}
190
192{
193 Logger::Get().Log("Shutting down imgui", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
194 ImGui_ImplDX11_Shutdown();
195 ImGui_ImplWin32_Shutdown();
196 ImGui::DestroyContext();
197 Logger::Get().Log("imgui shutdown", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
198}
199
201{
202 ImGui::Render();
203
204 //app->get_direct_3d()->turn_z_buffer_off();
205 //app->get_direct_3d()->enable_alpha_blending();
206
207 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
208
209 //app->get_direct_3d()->disable_alpha_blending();
210 //app->get_direct_3d()->turn_z_buffer_on();
211}
212
214{
215 ImGui_ImplDX11_NewFrame();
216 ImGui_ImplWin32_NewFrame();
217 ImGui::NewFrame();
218}
219
221 // Configuration du style pour supprimer l'espace autour des fenêtres dockées
222 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
223 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
224 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
225
226 // Configuration du style pour les nœuds de dock
227 ImGui::PushStyleVar(ImGuiStyleVar_DockingSeparatorSize, 1.0f); // Réduit l'épaisseur des séparateurs
228
229 // Configuration de la fenêtre principale
230 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
231 ImGuiViewport* viewport = ImGui::GetMainViewport();
232 ImGui::SetNextWindowPos(viewport->Pos);
233 ImGui::SetNextWindowSize(viewport->Size);
234 ImGui::SetNextWindowViewport(viewport->ID);
235 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
236 window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
237
238 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
239
240 ImGui::Begin("DockSpace", nullptr, window_flags);
241
242 // Pop des styles après avoir créé la fenêtre principale
243 ImGui::PopStyleVar(4); // 4 car nous avons poussé 4 variables de style
244 ImGui::PopStyleColor();
245
246 // Configuration du DockSpace
247 ImGuiID dockspace_id = ImGui::GetID("MainDockSpace");
248 ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
249 ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
250
251 if (ImGui::BeginMenuBar()) {
252 if (ImGui::BeginMenu("Windows")) {
253 ImGui::MenuItem("Object Window", NULL, &showObjectWindow);
254 ImGui::MenuItem("Terrain Window", NULL, &showTerrainWindow);
255 ImGui::MenuItem("Light Window", NULL, &showLightWindow);
256 ImGui::MenuItem("Engine Settings Window", NULL, &showEngineSettingsWindow);
257 ImGui::MenuItem("Log Window", NULL, &showLogWindow);
258 ImGui::MenuItem("render Stats", NULL, &showStatsWindow);
259 ImGui::EndMenu();
260 }
261
262 if (ImGui::BeginMenu("Scene")) {
263 if (ImGui::MenuItem("Save Scene")) {
264 scene_manager_->save_scene();
265 }
266 if (ImGui::MenuItem("Save Scene As...")) {
267 scene_manager_->save_scene_as();
268 }
269 if (ImGui::MenuItem("Load Scene")) {
270 scene_manager_->load_scene();
271 }
272 ImGui::EndMenu();
273 }
274
275 ImGui::EndMenuBar();
276 }
277
278 ImGui::End();
279}
280
282{
283 ImGui::SliderFloat("Speed", speed, 0.0f, 100.0f);
284}
285
287{
288 static int counter = 0;
289
290 if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
291 counter++;
292 ImGui::SameLine();
293 ImGui::Text("counter = %d", counter);
294}
295
297{
298 if (ImGui::CollapsingHeader("Objects"))
299 {
300 if (ImGui::Button("Add Cube"))
301 {
302 app_->add_cube();
303 }
304 ImGui::SameLine();
305 if (ImGui::Button("Import Object"))
306 {
307 // Open file dialog
308 OPENFILENAME ofn;
309 WCHAR szFile[260];
310 ZeroMemory(&ofn, sizeof(ofn));
311 ofn.lStructSize = sizeof(ofn);
312 ofn.hwndOwner = NULL;
313 ofn.lpstrFile = szFile;
314 ofn.lpstrFile[0] = '\0';
315 ofn.nMaxFile = sizeof(szFile);
316 ofn.lpstrFilter = L"OBJ\0*.obj\0KOBJ\0*.kobj\0TXT\0*.txt";
317 ofn.nFilterIndex = 1;
318 ofn.lpstrFileTitle = NULL;
319 ofn.nMaxFileTitle = 0;
320 ofn.lpstrInitialDir = NULL;
321 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
322
323 if (GetOpenFileName(&ofn))
324 {
325 std::wstring filepath = ofn.lpstrFile;
326
327 WCHAR exePath[MAX_PATH];
328 GetModuleFileName(NULL,exePath,MAX_PATH);
329 std::wstring exeDir = exePath;
330 size_t pos = exeDir.find_last_of(L"\\/");
331 if(pos != std::wstring::npos)
332 {
333 exeDir = exeDir.substr(0, pos);
334 }
335
336 std::wstring targetDir = exeDir + L"\\Content\\Assets\\Kobject";
337
338
339 DWORD ftyp = GetFileAttributesW(targetDir.c_str());
340 if( ftyp == INVALID_FILE_ATTRIBUTES)
341 {
342 std::wstring contentDir = exeDir + L"\\Content";
343 if (GetFileAttributes(contentDir.c_str()) == INVALID_FILE_ATTRIBUTES)
344 {
345 CreateDirectory(contentDir.c_str(), NULL);
346 }
347 std::wstring assetsDir = contentDir + L"\\Assets";
348 if (GetFileAttributes(assetsDir.c_str()) == INVALID_FILE_ATTRIBUTES)
349 {
350 CreateDirectory(assetsDir.c_str(), NULL);
351 }
352 std::wstring kobjectDir = assetsDir + L"\\Kobject";
353 if (GetFileAttributes(kobjectDir.c_str()) == INVALID_FILE_ATTRIBUTES)
354 {
355 CreateDirectory(kobjectDir.c_str(), NULL);
356 }
357 }
358
359 size_t posFile = filepath.find_last_of(L"\\/");
360 std::wstring filename = (posFile != std::wstring::npos) ? filepath.substr(posFile + 1) : filepath;
361
362 std::wstring targetPath = targetDir + L"\\" + filename;
363
364 if (!CopyFile(filepath.c_str(), targetPath.c_str(), FALSE))
365 {
366 // En cas d'erreur, vous pouvez gérer ici l'erreur (par exemple afficher un message)
367 MessageBox(NULL, L"Erreur lors de la copie du fichier.", L"Erreur", MB_OK);
368 }
369 else
370 {
371 // On récupère le chemin relatif par rapport à exeDir
372 std::wstring relativePath = targetPath.substr(exeDir.size());
373
374 // Suppression du premier caractère s'il s'agit d'un antislash
375 if (!relativePath.empty() && (relativePath[0] == L'\\' || relativePath[0] == L'/'))
376 {
377 relativePath.erase(0, 1);
378 }
379
380 // Remplacer les antislashs par des slashs
381 std::replace(relativePath.begin(), relativePath.end(), L'\\', L'/');
382 app_->add_kobject(relativePath);
383 }
384
385 }
386
387 }
388 ImGui::SameLine();
389 ImGui::Text("Number of cubes: %d", app_->get_entity_manager()->GetEntityCount());
390 }
391}
392
394{
395 ImGui::Begin("Objects", &showObjectWindow);
396
397 // Obtenir toutes les entités avec un composant d'identité et de transformation
398 auto entities = app_->get_entity_manager()->GetEntitiesWithComponent<ecs::IdentityComponent>();
399
400 int index = 0;
401 for (auto& entity : entities)
402 {
403 auto identity = entity->GetComponent<ecs::IdentityComponent>();
404 auto transform = entity->GetComponent<ecs::TransformComponent>();
405 auto render = entity->GetComponent<ecs::RenderComponent>();
406 auto shader = entity->GetComponent<ecs::ShaderComponent>();
407 auto physics = entity->GetComponent<ecs::PhysicsComponent>();
408
409 if (identity && transform)
410 {
411 std::string headerName = identity->GetName() + " " + std::to_string(identity->GetId());
412 if (ImGui::CollapsingHeader(headerName.c_str()))
413 {
414 // Position, Rotation, Scale
415 XMVECTOR position = transform->GetPosition();
416 XMVECTOR rotation = transform->GetRotation();
417 XMVECTOR scale = transform->GetScale();
418
419 float pos[3] = { XMVectorGetX(position), XMVectorGetY(position), XMVectorGetZ(position) };
420 std::string posLabel = "Position##" + std::to_string(identity->GetId());
421 if (ImGui::DragFloat3(posLabel.c_str(), pos))
422 {
423 transform->SetPosition(XMVectorSet(pos[0], pos[1], pos[2], 0.0f));
424 transform->UpdateWorldMatrix();
425 }
426
427 float rot[3] = { XMVectorGetX(rotation), XMVectorGetY(rotation), XMVectorGetZ(rotation) };
428 std::string rotLabel = "Rotation##" + std::to_string(identity->GetId());
429 if (ImGui::DragFloat3(rotLabel.c_str(), rot))
430 {
431 transform->SetRotation(XMVectorSet(rot[0], rot[1], rot[2], 0.0f));
432 transform->UpdateWorldMatrix();
433 }
434
435 float scl[3] = { XMVectorGetX(scale), XMVectorGetY(scale), XMVectorGetZ(scale) };
436 std::string sclLabel = "Scale##" + std::to_string(identity->GetId());
437 if (ImGui::DragFloat3(sclLabel.c_str(), scl))
438 {
439 transform->SetScale(XMVectorSet(scl[0], scl[1], scl[2], 0.0f));
440 transform->UpdateWorldMatrix();
441 }
442
443 ImGui::Separator();
444
445 // Textures - Seulement si le composant de rendu existe
446 if (render && render->GetModel())
447 {
448 // Définir les types de textures_
449 std::vector<std::string> textureCategories = {
450 "Diffuse", "Normal", "Specular", "Alpha"
451 };
452
453 std::vector<TextureType> textureTypes = {
454 TextureType::Diffuse, TextureType::Normal,
455 TextureType::Specular, TextureType::Alpha
456 };
457
458 // Créer un espace pour afficher les textures_ avec défilement
459 std::string textureChildId = "TextureChild##" + std::to_string(identity->GetId());
460 ImGui::BeginChild(textureChildId.c_str(), ImVec2(0, 200), true, ImGuiWindowFlags_HorizontalScrollbar);
461
462 // Pour chaque type de texture
463 for (int typeIndex = 0; typeIndex < textureCategories.size(); typeIndex++)
464 {
465 TextureType type = textureTypes[typeIndex];
466 std::string typeName = textureCategories[typeIndex];
467
468 // Afficher le titre de la catégorie
469 std::string categoryLabel = typeName + "##" + std::to_string(identity->GetId());
470 ImGui::Text("%s:", typeName.c_str());
471 ImGui::SameLine();
472
473 // Compter combien de textures_ de ce type existent
474 int textureCount = 0;
475 while (render->GetModel()->GetTexture(type, textureCount) != nullptr)
476 {
477 textureCount++;
478 }
479
480 // Afficher toutes les textures_ existantes
481 std::string groupId = "TextureGroup_" + std::to_string(identity->GetId()) + "_" + std::to_string(typeIndex);
482 ImGui::BeginGroup();
483 for (int texIndex = 0; texIndex < textureCount; texIndex++)
484 {
485 ID3D11ShaderResourceView* texture = render->GetModel()->GetTexture(type, texIndex);
486 if (texture)
487 {
488 // ID unique pour chaque bouton de texture
489 std::string buttonId = "tex##" + std::to_string(identity->GetId()) + "_" +
490 std::to_string(typeIndex) + "_" +
491 std::to_string(texIndex);
492
493 if (ImGui::ImageButton(buttonId.c_str(), (ImTextureID)texture, ImVec2(48, 48)))
494 {
495 // Ouvrir une boîte de dialogue pour changer la texture
496 OPENFILENAME ofn;
497 WCHAR szFile[260] = {0};
498 ZeroMemory(&ofn, sizeof(ofn));
499 ofn.lStructSize = sizeof(ofn);
500 ofn.hwndOwner = NULL;
501 ofn.lpstrFile = szFile;
502 ofn.nMaxFile = sizeof(szFile);
503 ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
504 ofn.nFilterIndex = 1;
505 ofn.lpstrInitialDir = NULL;
506 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
507
508 if (GetOpenFileName(&ofn))
509 {
510 // Changer la texture existante
511 render->GetModel()->ChangeTexture(m_device, m_deviceContext, ofn.lpstrFile, type, texIndex);
512 }
513 }
514
515 // Afficher l'indice de texture et prévisualisation au survol
516 if (ImGui::IsItemHovered())
517 {
518 ImGui::BeginTooltip();
519 ImGui::Text("%s %d", typeName.c_str(), texIndex);
520 ImGui::Image((ImTextureID)texture, ImVec2(192, 192));
521 ImGui::EndTooltip();
522 }
523
524 ImGui::SameLine();
525 }
526 }
527
528 // Bouton pour ajouter une nouvelle texture
529 std::string addButtonLabel = "+##" + std::to_string(identity->GetId()) + "_" + std::to_string(typeIndex);
530 if (ImGui::Button(addButtonLabel.c_str(), ImVec2(48, 48)))
531 {
532 // Ouvrir une boîte de dialogue pour ajouter une texture
533 OPENFILENAME ofn;
534 WCHAR szFile[260] = {0};
535 ZeroMemory(&ofn, sizeof(ofn));
536 ofn.lStructSize = sizeof(ofn);
537 ofn.hwndOwner = NULL;
538 ofn.lpstrFile = szFile;
539 ofn.nMaxFile = sizeof(szFile);
540 ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
541 ofn.nFilterIndex = 1;
542 ofn.lpstrInitialDir = NULL;
543 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
544
545 if (GetOpenFileName(&ofn))
546 {
547 // Ajouter une nouvelle texture
548 render->GetModel()->AddTexture(m_device, m_deviceContext, ofn.lpstrFile, type);
549 }
550 }
551
552 ImGui::EndGroup();
553 ImGui::Separator();
554 }
555
556 ImGui::EndChild();
557 }
558
559 ImGui::Separator();
560
561 // Delete button
562 std::string deleteLabel = "Delete##" + std::to_string(identity->GetId());
563 if (ImGui::Button(deleteLabel.c_str()))
564 {
565 app_->delete_entity_by_id(identity->GetId());
566 // Sortir du boucle après suppression pour éviter des accès invalides
567 break;
568 }
569
570 ImGui::Separator();
571
572 // Shader options
573 if (shader)
574 {
575 // Liste des options de shader
576 const char* shaderOptions[] = {
577 "Enable Global Lighting",
578 "Enable Lighting",
579 "Enable Cel Shading",
580 "Enable Normal Mapping",
581 "Enable Specular Mapping",
582 "Enable Alpha Mapping"
583 };
584
585 std::vector<ecs::ShaderType> shaderTypes = {
586 ecs::ShaderType::SUNLIGHT,
587 ecs::ShaderType::LIGHTING,
588 ecs::ShaderType::CEL_SHADING,
589 ecs::ShaderType::NORMAL_MAPPING,
590 ecs::ShaderType::SPECULAR_MAPPING,
591 ecs::ShaderType::ALPHA_MAPPING
592 };
593
594 // Trouver l'index actuel du shader pour cette entité spécifique
595 int currentShader = 0;
596 ecs::ShaderType activeShader = shader->GetActiveShader();
597 for (size_t i = 0; i < shaderTypes.size(); i++)
598 {
599 if (shaderTypes[i] == activeShader)
600 {
601 currentShader = static_cast<int>(i);
602 break;
603 }
604 }
605
606 // Création du menu déroulant avec un ID unique pour chaque entité
607 std::string shaderComboId = "Shader Options##" + std::to_string(identity->GetId());
608 if (ImGui::BeginCombo(shaderComboId.c_str(), shaderOptions[currentShader]))
609 {
610 for (int i = 0; i < IM_ARRAYSIZE(shaderOptions); i++)
611 {
612 // Crée une option sélectionnable pour chaque shader avec ID unique
613 std::string shaderSelectableId = std::to_string(i) + "##shader_" + std::to_string(identity->GetId());
614 bool isSelected = (currentShader == i);
615 if (ImGui::Selectable(shaderOptions[i], isSelected))
616 {
617 // Met à jour l'option sélectionnée uniquement pour cette entité
618 currentShader = i;
619 shader->SetActiveShader(shaderTypes[i]);
620 }
621
622 // Si l'option sélectionnée est active, nous mettons en surbrillance
623 if (isSelected)
624 ImGui::SetItemDefaultFocus();
625 }
626 ImGui::EndCombo();
627 }
628 }
629
630 ImGui::Separator();
631
632 // Physics
633 bool isPhysicsEnabled = (physics != nullptr);
634 std::string physicsLabel = "Physics##" + std::to_string(identity->GetId());
635
636 if (ImGui::Checkbox(physicsLabel.c_str(), &isPhysicsEnabled))
637 {
638 if (isPhysicsEnabled && !physics)
639 {
640 // Ajouter un composant de physique
641 physics = entity->AddComponent<ecs::PhysicsComponent>();
642 physics->Initialize();
643 }
644 else if (!isPhysicsEnabled && physics)
645 {
646 // Retirer le composant de physique
647 entity->RemoveComponent<ecs::PhysicsComponent>();
648 physics = nullptr;
649 }
650 }
651
652 if (physics)
653 {
654 // Gravity Enabled checkbox
655 bool gravityEnabled = physics->IsGravityEnabled();
656 std::string gravityLabel = "Gravity##" + std::to_string(identity->GetId());
657 if (ImGui::Checkbox(gravityLabel.c_str(), &gravityEnabled))
658 {
659 physics->SetGravityEnabled(gravityEnabled);
660 }
661
662 // 3 radio buttons pour le type d'objet physique avec IDs uniques
663 std::string typeLabel = "Type##" + std::to_string(identity->GetId());
664 ecs::ObjectType type = identity->GetType();
665
666 if (ImGui::RadioButton(("None##" + std::to_string(identity->GetId())).c_str(),
667 type == ecs::ObjectType::Unknown))
668 {
669 identity->SetType(ecs::ObjectType::Unknown);
670 }
671 ImGui::SameLine();
672 if (ImGui::RadioButton(("Cube##" + std::to_string(identity->GetId())).c_str(),
673 type == ecs::ObjectType::Cube))
674 {
675 identity->SetType(ecs::ObjectType::Cube);
676 }
677 ImGui::SameLine();
678 if (ImGui::RadioButton(("Sphere##" + std::to_string(identity->GetId())).c_str(),
679 type == ecs::ObjectType::Sphere))
680 {
681 identity->SetType(ecs::ObjectType::Sphere);
682 }
683 ImGui::SameLine();
684 if (ImGui::RadioButton(("Terrain##" + std::to_string(identity->GetId())).c_str(),
685 type == ecs::ObjectType::Terrain))
686 {
687 identity->SetType(ecs::ObjectType::Terrain);
688 }
689
690 }
691
692 ImGui::Separator();
693 }
694 index++;
695 }
696 }
697
698 ImGui::End();
699}
700
702{
703 ImGui::Begin("Terrain", &showTerrainWindow);
704
705 ImGui::Text("Number of terrain cubes: %d", app_->get_terrain_entity_count());
706
707 ImGui::Separator();
708
709 if (ImGui::Button("Generate Flat Terrain"))
710 {
711 app_->generate_terrain();
712 }
713
714 ImGui::Separator();
715
716 // Input for the number of cubes on each side
717 ImGui::Text("Number of cubes on each side: ");
718 ImGui::SameLine();
719 ImGui::InputInt("##SideCount", &m_SideCount);
720 if (m_SideCount < 1)
721 {
722 m_SideCount = 1;
723 }
724
725 ImGui::Separator();
726
727 if (ImGui::Button("Generate BigCube Terrain"))
728 {
729 app_->create_big_cube(m_SideCount);
730 }
731
732 ImGui::Separator();
733
734 if (ImGui::Button("Delete All Terrain Cubes"))
735 {
736 app_->delete_terrain();
737 }
738
739
740
741 ImGui::End();
742}
743
745{
746 // Start the Dear ImGui frame
747 NewFrame();
748
749 // Setup the dockspace
751
752 //ImGui Widget
753 ImGui::Begin("Khaotic Engine", NULL);
754
755 float speed = app_->get_speed();
756
757 WidgetSpeedSlider(&speed);
758 app_->set_speed(speed);
759 WidgetButton();
761
762 ImGui::End();
763
764 // Read the widget list and call the function if the show variable is true
765 for (const auto& entry : widgets_)
766 {
767 if (*entry.show == true) {entry.func();}
768 }
769
770 //render imgui
771 Render();
772
773 return true;
774}
775
777{
778 ImGui::Begin("Light", &showLightWindow);
779
780
781 // Sun light settings
782 light_class* sunLight = app_->get_sun_light();
783 // Direction input
784 XMFLOAT3 direction = sunLight->GetDirection();
785 float dir[3] = { direction.x, direction.y, direction.z };
786 if (ImGui::DragFloat3("Sun Direction", dir))
787 {
788 sunLight->SetDirection(dir[0], dir[1], dir[2]);
789 }
790 // Color input
791 XMFLOAT4 color = sunLight->GetDiffuseColor();
792 float col[3] = { color.x, color.y, color.z };
793 if (ImGui::ColorEdit3("Sun Color", col))
794 {
795 sunLight->SetDiffuseColor(col[0], col[1], col[2], 1.0f);
796 }
797 // Intensity input
798 float intensity = sunLight->GetIntensity();
799 if (ImGui::DragFloat("Sun Intensity", &intensity, 0.1f, 0.0f, 100.0f))
800 {
801 sunLight->SetIntensity(intensity);
802 }
803
804
805 ImGui::Separator();
806
807 int index = 0;
808
809 // Area light settings
810
811 for(auto& light : app_->get_lights())
812 {
813 std::string headerName = "Light " + std::to_string(index);
814 if (ImGui::CollapsingHeader(headerName.c_str()))
815 {
816 XMVECTOR position = app_->get_light_position(index);
817 XMVECTOR color = app_->get_light_color(index);
818 float pos[3] = { XMVectorGetX(position), XMVectorGetY(position), XMVectorGetZ(position) };
819 float col[3] = { XMVectorGetX(color), XMVectorGetY(color), XMVectorGetZ(color) };
820
821 std::string posLabel = "Position##" + std::to_string(index);
822 std::string colLabel = "Color##" + std::to_string(index);
823
824 if (ImGui::DragFloat3(posLabel.c_str(), pos))
825 {
826 app_->set_light_position(index, XMVectorSet(pos[0], pos[1], pos[2], 0.0f));
827 }
828
829 if (ImGui::ColorEdit3(colLabel.c_str(), col))
830 {
831 app_->set_light_color(index, XMVectorSet(col[0], col[1], col[2], 0.0f));
832 }
833
834 }
835 index++;
836 };
837
838 ImGui::End();
839}
840
842{
843 ImGui::Begin("Engine Settings", &showEngineSettingsWindow);
844
845 // Begining Of General Setting
846 ImGui::Text("General");
847
848 // Checkbox for toggling vsync globally in the application class by calling the set_vsync function in the application class when the checkbox state changes
849 bool vsync = app_->get_vsync();
850 if (ImGui::Checkbox("Vsync", &vsync))
851 {
852 app_->set_vsync(vsync);
853 }
854
855 // End Of General Setting
856 ImGui::Separator();
857 // culling section
858 ImGui::Text("Culling");
859
860 // float input for frustum tolerance
861 float frustumTolerance = app_->get_frustum_tolerance();
862 if (ImGui::DragFloat("Frustum Tolerance", &frustumTolerance, 0.1f, 0.0f, 100.0f))
863 {
864 app_->set_frustum_tolerance(frustumTolerance);
865 }
866
867 // End Of Culling Setting
868 ImGui::Separator();
869
870 // physics section
871 ImGui::Text("physics");
872
873 // Input To set the Fixed Update Interval
874 int physicsInterval = app_->get_physics_tick_rate();
875 if (ImGui::InputInt("physics Tick Rate", &physicsInterval))
876 {
877 app_->set_physics_tick_rate(physicsInterval);
878 }
879
880 // Input to change the gravity on same line
881 XMVECTOR gravity = app_->get_physics()->GetGravity();
882 float gravityValues[3] = { XMVectorGetX(gravity), XMVectorGetY(gravity), XMVectorGetZ(gravity) };
883 if (ImGui::DragFloat3("Gravity", gravityValues))
884 {
885 app_->get_physics()->SetGravity(XMVectorSet(gravityValues[0], gravityValues[1], gravityValues[2], 0.0f));
886 }
887
888 ImGui::End();
889}
890
892{
893 ImGui::Begin("Log Window" , &showLogWindow);
894
895 // Filtre de recherche
896 static ImGuiTextFilter filter;
897 filter.Draw("Filter ", 180);
898
899 ImGui::SameLine();
900
901 // Bouton pour ouvrir le fichier de log
902 if (ImGui::Button("Open Log File"))
903 {
904 ShellExecuteA(NULL, "open", Logger::Get().m_logFilePath.c_str(), NULL, NULL, SW_SHOWNORMAL);
905 }
906
907 // Place the menu on the same line as the filter
908 ImGui::SameLine();
909
910 // Menu déroulant pour les niveaux de log
911 if (ImGui::BeginMenu("Log Levels"))
912 {
913 for (size_t i = 0; i < Logger::LogLevelCount; ++i)
914 {
915 bool isVisible = !Logger::Get().m_disabledLogLevels[i];
916 if (ImGui::Checkbox(Logger::Get().GetLogLevelInfo(static_cast<Logger::LogLevel>(i)).name, &isVisible))
917 {
918 Logger::Get().m_disabledLogLevels[i] = !isVisible;
919 }
920 }
921 ImGui::EndMenu();
922 }
923
924 const auto& logBuffer = Logger::Get().GetLogBuffer();
925 std::vector<Logger::LogEntry> logfiltered;
926 int logCount = logBuffer.size();
927
928 // Affichage des logs filtrés
929 ImGui::BeginChild("Log");
930
931 for (const auto& log : logBuffer)
932 {
933 if (filter.PassFilter(log.message.c_str()) && !Logger::Get().m_disabledLogLevels[static_cast<size_t>(log.level)])
934 {
935 logfiltered.push_back(log);
936 }
937 }
938
939 if (logfiltered.size() == 0)
940 {
941 ImGui::Text("No logs to display.");
942 }
943 else
944 {
945 ImGuiListClipper clipper;
946 clipper.Begin(logCount);
947 while (clipper.Step())
948 {
949 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
950 {
951 if (i < logfiltered.size()) {
952 const auto& log = logfiltered[i];
953 ImGui::TextColored(Logger::Get().GetLogLevelInfo(log.level).color, log.message.c_str());
954 }
955
956 }
957 }
958 clipper.End();
959 }
960
961 // Scroll to the bottom
962 if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
963 {
964 ImGui::SetScrollHereY(1.0f);
965 }
966
967 ImGui::EndChild();
968
969 ImGui::End();
970}
971
972void imguiManager::WidgetRenderWindow(ImVec2 availableSize)
973{
974 ImGui::Begin("render Window");
975
976 ImVec2 oldWindowSize = windowSize;
977 windowSize = ImGui::GetContentRegionAvail();
978
979 // Si la taille de la fenêtre a changé, ajustez la taille de la fenêtre de l'application
980 if (oldWindowSize.x != windowSize.x || oldWindowSize.y != windowSize.y)
981 {
982 app_->set_window_size(windowSize);
983 }
984
985
986 // Get the aspect ratio of the scene in app
987 float aspectRatio = app_->get_aspect_ratio();
988 // calculate the size of the window
989 if (windowSize.x / windowSize.y > aspectRatio)
990 {
991 windowSize.x = windowSize.y * aspectRatio;
992 }
993 else
994 {
995 windowSize.y = windowSize.x / aspectRatio;
996 }
997
998 ID3D11ShaderResourceView* texture = app_->get_scene_texture()->GetShaderResourceView();
999 if (texture)
1000 {
1001
1002 // Affichez la scenne projeté sur texture dans une fenêtre ImGui
1003 // alpha blend is not enable to render the texture
1004
1005 app_->get_direct_3d()->turn_z_buffer_off();
1006 app_->get_direct_3d()->enable_alpha_blending();
1007
1008 ImGui::Image((ImTextureID)texture, windowSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(1, 1, 1, 1));
1009 }
1010 else
1011 {
1012 ImGui::Text("render texture is not available.");
1013 }
1014
1015 ImGui::End();
1016}
1017
1019{
1020 ImGui::Begin("render Stats");
1021
1022 current_fps_ = stats_->get_current_fps();
1023 min_fps_ = stats_->get_min_fps();
1024 max_fps_ = stats_->get_max_fps();
1025 draw_calls_ = stats_->get_draw_calls();
1026
1027
1028 // total_vertex_count_ = stats_->get_total_vertex_count();
1029 // total_triangle_count_ = stats_->get_total_triangle_count();
1030
1031 visible_triangle_count_ = stats_->get_visible_triangle_count();
1032 current_frame_time_ = stats_->get_frame_time();
1033
1034 m_frameTimeHistory[m_frameTimeHistoryIndex] = current_frame_time_;
1035 m_frameTimeHistoryIndex = (m_frameTimeHistoryIndex + 1) % FRAME_HISTORY_COUNT;
1036
1037 ImGui::Text("FPS: %d", current_fps_);
1038 ImGui::SameLine();
1039 ImGui::Text("Min Fps: %d", min_fps_);
1040 ImGui::SameLine();
1041 ImGui::Text("Max Fps: %d", max_fps_);
1042
1043 ImGui::Separator();
1044
1045 // Trouver les valeurs min/max pour l'échelle du graphique
1046 float frameTimeMin = FLT_MAX;
1047 float frameTimeMax = 0.0f;
1048 for (int i = 0; i < FRAME_HISTORY_COUNT; i++) {
1049 if (m_frameTimeHistory[i] > 0.0f) {
1050 frameTimeMin = min(frameTimeMin, m_frameTimeHistory[i]);
1051 frameTimeMax = max(frameTimeMax, m_frameTimeHistory[i]);
1052 }
1053 }
1054 // S'assurer d'avoir au moins une petite plage
1055 if (frameTimeMax == 0.0f) frameTimeMax = 0.033f; // ~30 FPS
1056 if (frameTimeMin == FLT_MAX) frameTimeMin = 0.0f;
1057
1058 // Ajouter 10% de marge pour la lisibilité
1059 float margin = (frameTimeMax - frameTimeMin) * 0.1f;
1060 frameTimeMin = max(0.0f, frameTimeMin - margin);
1061 frameTimeMax += margin;
1062
1063 // Afficher le graphique
1064 ImGui::Text("Frame Time: %.3f ms", current_frame_time_ * 1000.0f);
1065 ImGui::PlotLines("FrameTimeGraph", // Au lieu de chaîne vide ""
1066 m_frameTimeHistory,
1067 FRAME_HISTORY_COUNT,
1068 m_frameTimeHistoryIndex,
1069 "",
1070 frameTimeMin,
1071 frameTimeMax,
1072 ImVec2(0, 80));
1073
1074 ImGui::Text("Draw Calls: %d", draw_calls_);
1075
1076 ImGui::Separator();
1077
1078 ImGui::Text("Statistiques de rendu:");
1079 ImGui::Text("Vertices total: %d", *total_vertex_count_);
1080
1081 ImGui::Text("Triangles total: %d", *total_triangle_count_);
1082 ImGui::SameLine();
1083 ImGui::Text("Triangles visibles: %d", visible_triangle_count_);
1084
1085 app_->get_direct_3d()->get_video_card_info(card_name_, video_memory_);
1086 cpu_name_ = stats_->get_cpu_name();
1087 version_driver_ = stats_->get_gpu_driver_version(app_->get_direct_3d()->get_device());
1088
1089 ImGui::Columns(3, "GPUCPURAMColumns", false);
1090 ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.33f);
1091 ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.33f);
1092
1093 // Premier collapsing header pour les informations GPU
1094 if (ImGui::CollapsingHeader("Informations GPU"))
1095 {
1096 ImGui::Text("Carte graphique: %s", card_name_);
1097 ImGui::Text("Memoire video: %d Mo", video_memory_);
1098 ImGui::Text("Pilote: %s", version_driver_.c_str());
1099 }
1100
1101 ImGui::NextColumn();
1102
1103 // Second collapsing header pour les informations CPU
1104 if (ImGui::CollapsingHeader("Informations CPU"))
1105 {
1106 SYSTEM_INFO sysInfo;
1107 GetSystemInfo(&sysInfo);
1108 ImGui::Text("Processeur: %s", cpu_name_.c_str());
1109 ImGui::Text("Nombre de coeurs: %u", sysInfo.dwNumberOfProcessors);
1110 ImGui::Text("Architecture: %s", (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ? "x64" : "x86");
1111 ImGui::Text("Taille de la page: %u octets", sysInfo.dwPageSize);
1112 ImGui::Text("Taille du cache: %u octets", sysInfo.dwAllocationGranularity);
1113 ImGui::Text("Type de processeur: %u", sysInfo.wProcessorLevel);
1114 ImGui::Text("Version du processeur: %u", sysInfo.wProcessorRevision);
1115 }
1116
1117 ImGui::NextColumn();
1118
1119 if (ImGui::CollapsingHeader("Informations RAM"))
1120 {
1121 MEMORYSTATUSEX mem_info;
1122 mem_info.dwLength = sizeof(MEMORYSTATUSEX);
1123 GlobalMemoryStatusEx(&mem_info);
1124 ImGui::Text("Memoire totale: %llu Mo", mem_info.ullTotalPhys / (1024 * 1024));
1125 ImGui::Text("Memoire disponible: %llu Mo", mem_info.ullAvailPhys / (1024 * 1024));
1126 ImGui::Text("Memoire utilisee: %llu Mo", (mem_info.ullTotalPhys - mem_info.ullAvailPhys) / (1024 * 1024));
1127 }
1128
1129 ImGui::Columns(1);
1130
1131 ImGui::End();
1132}
1133
static Logger & Get()
Definition Logger.h:20
const std::deque< LogEntry > & GetLogBuffer() const
Definition Logger.h:220
void Log(const std::string &message, const std::string &fileName, int lineNumber, LogLevel level=LogLevel::Info)
Definition Logger.h:158
LogLevel
Definition Logger.h:38
void WidgetObjectWindow()
void SetupDockspace()
void WidgetLightWindow()
bool Initialize(HWND hwnd, ID3D11Device *device, ID3D11DeviceContext *deviceContext)
void WidgetEngineSettingsWindow()
void WidgetAddObject()
void WidgetTerrainWindow()
void WidgetRenderWindow(ImVec2 availableSize)
void WidgetLogWindow()
bool ImGuiWidgetRenderer()
void WidgetRenderStats()
void WidgetSpeedSlider(float *speed)
bool initialize(application_class *app)