#include "imguiManager.h" #include "applicationclass.h" #include imguiManager::imguiManager() { io = nullptr; } imguiManager::~imguiManager() { } bool imguiManager::Initialize(HWND hwnd, ID3D11Device* device, ID3D11DeviceContext* deviceContext) { Logger::Get().Log("Initializing imgui", __FILE__, __LINE__, Logger::LogLevel::Initialize); m_device = device; m_deviceContext = deviceContext; IMGUI_CHECKVERSION(); ImGui::CreateContext(); io = &ImGui::GetIO(); io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(m_device, m_deviceContext); ImGui::StyleColorsDark(); Logger::Get().Log("imgui initialized", __FILE__, __LINE__, Logger::LogLevel::Initialize); return true; } void imguiManager::Shutdown() { Logger::Get().Log("Shutting down imgui", __FILE__, __LINE__, Logger::LogLevel::Shutdown); ImGui_ImplDX11_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); Logger::Get().Log("imgui shutdown", __FILE__, __LINE__, Logger::LogLevel::Shutdown); } void imguiManager::Render() { ImGui::Render(); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); } void imguiManager::NewFrame() { ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); } void imguiManager::SetupDockspace() { ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->Pos); ImGui::SetNextWindowSize(viewport->Size); ImGui::SetNextWindowViewport(viewport->ID); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; ImGui::Begin("DockSpace", nullptr, window_flags); ImGui::PopStyleVar(2); ImGuiID dockspace_id = ImGui::GetID("MainDockSpace"); ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_PassthruCentralNode); ImGui::End(); } void imguiManager::WidgetSpeedSlider(float* speed) { ImGui::SliderFloat("Speed", speed, 0.0f, 100.0f); } void imguiManager::WidgetButton() { static int counter = 0; if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) counter++; ImGui::SameLine(); ImGui::Text("counter = %d", counter); } void imguiManager::WidgetFPS() { ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io->Framerate, io->Framerate); } void imguiManager::WidgetAddObject(ApplicationClass* app) { if (ImGui::CollapsingHeader("Objects")) { if (ImGui::Button("Add Cube")) { app->AddCube(); } ImGui::SameLine(); if (ImGui::Button("Import Object")) { // Open file dialog OPENFILENAME ofn; WCHAR szFile[260]; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = szFile; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = L"OBJ\0*.obj\0KOBJ\0*.kobj\0TXT\0*.txt"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)) { app->AddKobject(ofn.lpstrFile); } } ImGui::SameLine(); ImGui::Text("Number of cubes: %d", app->GetCubeCount()); } } void imguiManager::WidgetShaderWindow(ApplicationClass* app) { ImGui::Begin("Shader Manager"); // Checkbox for toggling cel shading globally in the application class by calling the SetCelShading function in the application class when the checkbox state changes ImGui::Checkbox("Enable Cel Shading", &m_EnableCelShading); app->SetCelShading(m_EnableCelShading); ImGui::End(); } void imguiManager::WidgetObjectWindow(ApplicationClass* app) { ImGui::Begin("Objects", &showObjectWindow); int index = 0; for (auto& object : app->GetKobjects()) { std::string headerName = object->GetName() + " " + std::to_string(index); if (ImGui::CollapsingHeader(headerName.c_str())) { XMVECTOR position = object->GetPosition(); XMVECTOR rotation = object->GetRotation(); XMVECTOR scale = object->GetScale(); float pos[3] = { XMVectorGetX(position), XMVectorGetY(position), XMVectorGetZ(position) }; std::string posLabel = "Position##" + std::to_string(index); if (ImGui::DragFloat3(posLabel.c_str(), pos)) { object->SetPosition(XMVectorSet(pos[0], pos[1], pos[2], 0.0f)); } float rot[3] = { XMVectorGetX(rotation), XMVectorGetY(rotation), XMVectorGetZ(rotation) }; std::string rotLabel = "Rotation##" + std::to_string(index); if (ImGui::DragFloat3(rotLabel.c_str(), rot)) { object->SetRotation(XMVectorSet(rot[0], rot[1], rot[2], 0.0f)); } float scl[3] = { XMVectorGetX(scale), XMVectorGetY(scale), XMVectorGetZ(scale) }; std::string sclLabel = "Scale##" + std::to_string(index); if (ImGui::DragFloat3(sclLabel.c_str(), scl)) { object->SetScale(XMVectorSet(scl[0], scl[1], scl[2], 0.0f)); } ImGui::Separator(); // Texture // add all texture category names to a vector std::vector textureCategories = { "Diffuse", "Normal", "Specular", "Reflection", "Refraction" }; // Display all images for (int count = 0; count < textureCategories.size(); count++) { std::string textureLabel = "Texture##" + std::to_string(index) + "##" + std::to_string(count); ID3D11ShaderResourceView* texture = object->GetTexture(count); if (texture != nullptr) { ImGui::Text(textureCategories[count].c_str()); ImGui::SameLine(); std::string buttonLabel = "button " + std::to_string(count); if (ImGui::ImageButton(buttonLabel.c_str(), (ImTextureID)texture, ImVec2(64, 64))) { // Open file dialog OPENFILENAME ofn; WCHAR szFile[260]; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = szFile; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = L"Texture\0*.png\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)) { // Load the selected texture object->ChangeTexture(m_device, m_deviceContext, ofn.lpstrFile, count); } } if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Image((ImTextureID)texture, ImVec2(256, 256)); ImGui::EndTooltip(); } if (count < textureCategories.size() - 1) { ImGui::SameLine(); } } } ImGui::Separator(); // Delete button std::string deleteLabel = "Delete##" + std::to_string(index); if (ImGui::Button(deleteLabel.c_str())) { app->DeleteKobject(index); } ImGui::Separator(); // Liste des options const char* shaderOptions[] = { "Enable Global Lighting", "Enable Lighting", "Enable Cel Shading", "Enable Normal Mapping", "Enable Specular Mapping" }; Object::ShaderType shaderTypes[] = { Object::SUNLIGHT,Object::LIGHTING, Object::CEL_SHADING, Object::NORMAL_MAPPING, Object::SPECULAR_MAPPING }; // Variable pour stocker l'option sélectionnée static int currentShader = 0; // Index de l'option actuellement sélectionnée // Création du menu déroulant if (ImGui::BeginCombo("Shader Options", shaderOptions[currentShader])) { for (int i = 0; i < IM_ARRAYSIZE(shaderOptions); i++) { // Crée une option sélectionnable pour chaque shader bool isSelected = (currentShader == i); if (ImGui::Selectable(shaderOptions[i], isSelected)) { // Met à jour l'option sélectionnée currentShader = i; object->SetActiveShader(shaderTypes[i]); } // Si l'option sélectionnée est active, nous mettons en surbrillance if (isSelected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } ImGui::Separator(); // Physics std::string physicsLabel = "Physics##" + std::to_string(index); if (ImGui::Checkbox(physicsLabel.c_str(), &m_isPhyiscsEnabled)) { object->SetPhysicsEnabled(m_isPhyiscsEnabled); } // 3 radio button on the same line to set the ObjectType std::string typeLabel = "Type##" + std::to_string(index); ObjectType type = object->GetType(); if (ImGui::RadioButton("None", type == ObjectType::Unknown)) { object->SetType(ObjectType::Unknown); } ImGui::SameLine(); if (ImGui::RadioButton("Cube", type == ObjectType::Cube)) { object->SetType(ObjectType::Cube); } ImGui::SameLine(); if (ImGui::RadioButton("Sphere", type == ObjectType::Sphere)) { object->SetType(ObjectType::Sphere); } ImGui::Separator(); // Demo spinning std::string demoLabel = "Demo spinning##" + std::to_string(index); ImGui::Checkbox(demoLabel.c_str(), &object->m_demoSpinning); } index++; } ImGui::End(); } void imguiManager::WidgetTerrainWindow(ApplicationClass* app) { ImGui::Begin("Terrain", &showTerrainWindow); ImGui::Text("Number of terrain cubes: %d", app->GetTerrainCubeCount()); ImGui::Separator(); if (ImGui::Button("Generate Terrain")) { app->GenerateTerrain(); } ImGui::SameLine(); if (ImGui::Button("Delete All Terrain Cubes")) { app->DeleteTerrain(); } ImGui::End(); } bool imguiManager::ImGuiWidgetRenderer(ApplicationClass* app) { // Start the Dear ImGui frame NewFrame(); // Setup the dockspace SetupDockspace(); //ImGui Widget ImGui::Begin("Khaotic Engine", NULL); float speed = app->GetSpeed(); WidgetSpeedSlider(&speed); app->SetSpeed(speed); WidgetButton(); WidgetFPS(); WidgetAddObject(app); ImGui::Separator(); // Add buttons for opening windows if (ImGui::Button("Open Object Window")) { showObjectWindow = true; } if (ImGui::Button("Open Terrain Window")) { showTerrainWindow = true; } if (ImGui::Button("Open Light Window")) { showLightWindow = true; } if (ImGui::Button("Open Shader Window")) { showShaderWindow = true; } if (ImGui::Button("Open Engine Settings Window")) { showEngineSettingsWindow = true; } if (ImGui::Button("Open Log Window")) { showLogWindow = true; } ImGui::End(); // Show windows if their corresponding variables are true if (showObjectWindow) { WidgetObjectWindow(app); } if (showTerrainWindow) { WidgetTerrainWindow(app); } if (showLightWindow) { WidgetLightWindow(app); } if (showShaderWindow) { WidgetShaderWindow(app); } if (showEngineSettingsWindow) { WidgetEngineSettingsWindow(app); } if (showLogWindow) { WidgetLogWindow(app); } WidgetRenderWindow(app, ImVec2(800, 600)); //render imgui Render(); return true; } void imguiManager::WidgetLightWindow(ApplicationClass* app) { ImGui::Begin("Light", &showLightWindow); // Sun light settings LightClass* sunLight = app->GetSunLight(); // Direction input XMFLOAT3 direction = sunLight->GetDirection(); float dir[3] = { direction.x, direction.y, direction.z }; if (ImGui::DragFloat3("Sun Direction", dir)) { sunLight->SetDirection(dir[0], dir[1], dir[2]); } // Color input XMFLOAT4 color = sunLight->GetDiffuseColor(); float col[3] = { color.x, color.y, color.z }; if (ImGui::ColorEdit3("Sun Color", col)) { sunLight->SetDiffuseColor(col[0], col[1], col[2], 1.0f); } // Intensity input float intensity = sunLight->GetIntensity(); if (ImGui::DragFloat("Sun Intensity", &intensity, 0.1f, 0.0f, 100.0f)) { sunLight->SetIntensity(intensity); } ImGui::Separator(); int index = 0; // Area light settings for(auto& light : app->GetLights()) { std::string headerName = "Light " + std::to_string(index); if (ImGui::CollapsingHeader(headerName.c_str())) { XMVECTOR position = app->GetLightPosition(index); XMVECTOR color = app->GetLightColor(index); float pos[3] = { XMVectorGetX(position), XMVectorGetY(position), XMVectorGetZ(position) }; float col[3] = { XMVectorGetX(color), XMVectorGetY(color), XMVectorGetZ(color) }; std::string posLabel = "Position##" + std::to_string(index); std::string colLabel = "Color##" + std::to_string(index); if (ImGui::DragFloat3(posLabel.c_str(), pos)) { app->SetLightPosition(index, XMVectorSet(pos[0], pos[1], pos[2], 0.0f)); } if (ImGui::ColorEdit3(colLabel.c_str(), col)) { app->SetLightColor(index, XMVectorSet(col[0], col[1], col[2], 0.0f)); } } index++; }; ImGui::End(); } void imguiManager::WidgetEngineSettingsWindow(ApplicationClass* app) { ImGui::Begin("Engine Settings", &showEngineSettingsWindow); // Begining Of General Setting ImGui::Text("General"); // Checkbox for toggling vsync globally in the application class by calling the SetVsync function in the application class when the checkbox state changes bool vsync = app->GetVsync(); if (ImGui::Checkbox("Vsync", &vsync)) { app->SetVsync(vsync); } // End Of General Setting ImGui::Separator(); // culling section ImGui::Text("Culling"); // float input for frustum tolerance float frustumTolerance = app->GetFrustumTolerance(); if (ImGui::DragFloat("Frustum Tolerance", &frustumTolerance, 0.1f, 0.0f, 100.0f)) { app->SetFrustumTolerance(frustumTolerance); } // End Of Culling Setting ImGui::Separator(); // Physics section ImGui::Text("Physics"); // Input To set the Fixed Update Interval int physicsInterval = app->GetPhysicsTickRate(); if (ImGui::InputInt("Physics Tick Rate", &physicsInterval)) { app->SetPhysicsTickRate(physicsInterval); } // Input to change the gravity on same line XMVECTOR gravity = app->GetPhysics()->GetGravity(); float gravityValues[3] = { XMVectorGetX(gravity), XMVectorGetY(gravity), XMVectorGetZ(gravity) }; if (ImGui::DragFloat3("Gravity", gravityValues)) { app->GetPhysics()->SetGravity(XMVectorSet(gravityValues[0], gravityValues[1], gravityValues[2], 0.0f)); } ImGui::End(); } void imguiManager::WidgetLogWindow(ApplicationClass* app) { ImGui::Begin("Log Window" , &showLogWindow); // Filtre de recherche static ImGuiTextFilter filter; filter.Draw("Filter ", 180); ImGui::SameLine(); // Bouton pour ouvrir le fichier de log if (ImGui::Button("Open Log File")) { ShellExecuteA(NULL, "open", Logger::Get().m_logFilePath.c_str(), NULL, NULL, SW_SHOWNORMAL); } // Place the menu on the same line as the filter ImGui::SameLine(); // Menu déroulant pour les niveaux de log if (ImGui::BeginMenu("Log Levels")) { for (size_t i = 0; i < Logger::LogLevelCount; ++i) { bool isVisible = !Logger::Get().m_disabledLogLevels[i]; if (ImGui::Checkbox(Logger::Get().GetLogLevelInfo(static_cast(i)).name, &isVisible)) { Logger::Get().m_disabledLogLevels[i] = !isVisible; } } ImGui::EndMenu(); } const auto& logBuffer = Logger::Get().GetLogBuffer(); std::vector logfiltered; int logCount = logBuffer.size(); // Affichage des logs filtrés ImGui::BeginChild("Log"); for (const auto& log : logBuffer) { if (filter.PassFilter(log.message.c_str()) && !Logger::Get().m_disabledLogLevels[static_cast(log.level)]) { logfiltered.push_back(log); } } if (logfiltered.size() == 0) { ImGui::Text("No logs to display."); } else { ImGuiListClipper clipper; clipper.Begin(logCount); while (clipper.Step()) { for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { if (i < logfiltered.size()) { const auto& log = logfiltered[i]; ImGui::TextColored(Logger::Get().GetLogLevelInfo(log.level).color, log.message.c_str()); } } } clipper.End(); } // Scroll to the bottom if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { ImGui::SetScrollHereY(1.0f); } ImGui::EndChild(); ImGui::End(); } void imguiManager::WidgetRenderWindow(ApplicationClass* app, ImVec2 availableSize) { ImGui::Begin("Render Window"); windowSize = ImGui::GetContentRegionAvail(); app->SetWindowSize(windowSize); // Assurez-vous que la texture est valide RenderTextureClass* renderTexture = app->GetRenderTexture(); if (renderTexture) { // Obtenez la vue de la ressource shader de la texture rendue ID3D11ShaderResourceView* texture = renderTexture->GetShaderResourceView(); // Affichez la texture dans une fenêtre ImGui ImGui::Image((ImTextureID)texture, windowSize); } else { ImGui::Text("Render texture is not available."); } ImGui::End(); }