1134 lines
35 KiB
C++

#include "imguiManager.h"
#include "application_class.h"
#include "stats.h"
static fps_limiter fpsLimiter(60.0f);
imguiManager::imguiManager()
{
io = nullptr;
m_frameTimeHistoryIndex = 0;
current_fps_ = 0;
min_fps_ = 0;
max_fps_ = 0;
draw_calls_ = 0;
total_vertex_count_ = 0;
total_triangle_count_ = 0;
visible_triangle_count_ = 0;
current_frame_time_ = 0;
showObjectWindow = false;
showTerrainWindow = false;
showLightWindow = false;
showOldSceneWindow = false;
showEngineSettingsWindow = false;
showLogWindow = false;
showStatsWindow = false;
// Initialiser l'historique des frametimes à zéro
for (int i = 0; i < FRAME_HISTORY_COUNT; i++)
{
m_frameTimeHistory[i] = 0.0f;
}
widgets_ = {
{&showObjectWindow, [&](){WidgetObjectWindow();}},
{&showEngineSettingsWindow, [&](){WidgetEngineSettingsWindow();}},
{&showTerrainWindow, [&](){WidgetTerrainWindow();}},
{&showLightWindow, [&](){WidgetLightWindow();}},
{&showLogWindow, [&](){WidgetLogWindow();}},
{&showOldSceneWindow, [&](){WidgetRenderWindow(ImVec2(800, 600));}},
{&showStatsWindow, [&](){WidgetRenderStats();}}
};
}
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;
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io->FontGlobalScale = 1.0f;
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX11_Init(m_device, m_deviceContext);
// Appliquer un thème sombre de base
ImGui::StyleColorsDark();
// Définir les couleurs pour une interface de type éditeur sobre
ImGuiStyle& style = ImGui::GetStyle();
// Palette de couleurs sobres inspirée des éditeurs modernes
ImVec4 background_dark = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); // Fond foncé
ImVec4 background = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); // Fond principal
ImVec4 background_light = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); // Fond clair
ImVec4 accent = ImVec4(0.14f, 0.44f, 0.80f, 0.50f); // Accent bleu
ImVec4 accent_light = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); // Accent bleu vif
ImVec4 text = ImVec4(1.0f, 1.0f, 1.0f, 1.00f); // Texte plus blanc
ImVec4 text_dim = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
// Ajustements de style généraux
style.WindowPadding = ImVec2(4.0f, 4.0f); // Moins de padding dans les fenêtres
style.FramePadding = ImVec2(4.0f, 3.0f); // Moins de padding dans les cadres
style.ItemSpacing = ImVec2(4.0f, 3.0f); // Moins d'espace entre les widgets
style.ItemInnerSpacing = ImVec2(3.0f, 3.0f); // Moins d'espace interne
style.DisplayWindowPadding = ImVec2(0.0f, 0.0f); // Pas de padding pour l'affichage
style.DisplaySafeAreaPadding = ImVec2(0.0f, 0.0f);
style.TouchExtraPadding = ImVec2(0.0f, 0.0f);
style.IndentSpacing = 20.0f;
style.ScrollbarSize = 14.0f;
style.GrabMinSize = 10.0f;
// Arrondis
style.WindowRounding = 4.0f;
style.ChildRounding = 4.0f;
style.FrameRounding = 3.0f;
style.PopupRounding = 4.0f;
style.ScrollbarRounding = 9.0f;
style.GrabRounding = 3.0f;
style.TabRounding = 4.0f;
// Couleurs principales
style.Colors[ImGuiCol_Text] = text;
style.Colors[ImGuiCol_TextDisabled] = text_dim;
style.Colors[ImGuiCol_WindowBg] = background;
style.Colors[ImGuiCol_ChildBg] = background_dark;
style.Colors[ImGuiCol_PopupBg] = background_dark;
style.Colors[ImGuiCol_Border] = ImVec4(0.25f, 0.25f, 0.27f, 1.00f);
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
// Encadrements
style.Colors[ImGuiCol_FrameBg] = background_light;
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
// Titres
style.Colors[ImGuiCol_TitleBg] = background_dark;
style.Colors[ImGuiCol_TitleBgActive] = accent;
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.12f, 0.12f, 0.12f, 0.90f);
// Éléments de menu
style.Colors[ImGuiCol_MenuBarBg] = background_dark;
style.Colors[ImGuiCol_ScrollbarBg] = background_dark;
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
// Boutons et interactions
style.Colors[ImGuiCol_CheckMark] = accent_light;
style.Colors[ImGuiCol_SliderGrab] = accent;
style.Colors[ImGuiCol_SliderGrabActive] = accent_light;
style.Colors[ImGuiCol_Button] = background_light;
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
style.Colors[ImGuiCol_ButtonActive] = accent;
// En-têtes et onglets
style.Colors[ImGuiCol_Header] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_HeaderActive] = accent;
style.Colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.28f, 1.00f);
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f);
style.Colors[ImGuiCol_SeparatorActive] = accent;
style.Colors[ImGuiCol_Tab] = background_dark;
style.Colors[ImGuiCol_TabHovered] = accent;
style.Colors[ImGuiCol_TabActive] = accent;
style.Colors[ImGuiCol_TabUnfocused] = background_dark;
style.Colors[ImGuiCol_TabUnfocusedActive] = background;
// Autres éléments
style.Colors[ImGuiCol_DockingPreview] = accent;
style.Colors[ImGuiCol_DockingEmptyBg] = background_light;
// Charger une police avec une meilleure netteté
ImFontConfig fontConfig;
fontConfig.OversampleH = 2; // Suréchantillonnage horizontal
fontConfig.OversampleV = 2; // Suréchantillonnage vertical
fontConfig.PixelSnapH = true; // Alignement sur la grille de pixels
fontConfig.RasterizerMultiply = 1.2f; // Légère augmentation de l'épaisseur
io->Fonts->AddFontDefault(&fontConfig);
io->Fonts->Build();
// OU charger une police personnalisée (décommenter si vous avez la police)
// io->Fonts->AddFontFromFileTTF("assets/fonts/roboto.ttf", 16.0f, &fontConfig);
unsigned char* pixels;
int width, height;
io->Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// initialize the scene manager
scene_manager_ = new scene_manager;
if (!scene_manager_->initialize(app_.get())) {
Logger::Get().Log("Failed to initialize scene manager", __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
stats_ = app_->get_stats();
total_triangle_count_ = stats_->get_triangle_count_ptr();
total_vertex_count_ = stats_->get_vertex_count_ptr();
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();
//app->get_direct_3d()->turn_z_buffer_off();
//app->get_direct_3d()->enable_alpha_blending();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
//app->get_direct_3d()->disable_alpha_blending();
//app->get_direct_3d()->turn_z_buffer_on();
}
void imguiManager::NewFrame()
{
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
}
void imguiManager::SetupDockspace() {
// Configuration du style pour supprimer l'espace autour des fenêtres dockées
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
// Configuration du style pour les nœuds de dock
ImGui::PushStyleVar(ImGuiStyleVar_DockingSeparatorSize, 1.0f); // Réduit l'épaisseur des séparateurs
// Configuration de la fenêtre principale
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
ImGui::Begin("DockSpace", nullptr, window_flags);
// Pop des styles après avoir créé la fenêtre principale
ImGui::PopStyleVar(4); // 4 car nous avons poussé 4 variables de style
ImGui::PopStyleColor();
// Configuration du DockSpace
ImGuiID dockspace_id = ImGui::GetID("MainDockSpace");
ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Windows")) {
ImGui::MenuItem("Object Window", NULL, &showObjectWindow);
ImGui::MenuItem("Terrain Window", NULL, &showTerrainWindow);
ImGui::MenuItem("Light Window", NULL, &showLightWindow);
ImGui::MenuItem("Engine Settings Window", NULL, &showEngineSettingsWindow);
ImGui::MenuItem("Log Window", NULL, &showLogWindow);
ImGui::MenuItem("render Stats", NULL, &showStatsWindow);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Scene")) {
if (ImGui::MenuItem("Save Scene")) {
scene_manager_->save_scene();
}
if (ImGui::MenuItem("Save Scene As...")) {
scene_manager_->save_scene_as();
}
if (ImGui::MenuItem("Load Scene")) {
scene_manager_->load_scene();
}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
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::WidgetAddObject()
{
if (ImGui::CollapsingHeader("Objects"))
{
if (ImGui::Button("Add Cube"))
{
app_->add_cube();
}
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))
{
std::wstring filepath = ofn.lpstrFile;
WCHAR exePath[MAX_PATH];
GetModuleFileName(NULL,exePath,MAX_PATH);
std::wstring exeDir = exePath;
size_t pos = exeDir.find_last_of(L"\\/");
if(pos != std::wstring::npos)
{
exeDir = exeDir.substr(0, pos);
}
std::wstring targetDir = exeDir + L"\\Content\\Assets\\Kobject";
DWORD ftyp = GetFileAttributesW(targetDir.c_str());
if( ftyp == INVALID_FILE_ATTRIBUTES)
{
std::wstring contentDir = exeDir + L"\\Content";
if (GetFileAttributes(contentDir.c_str()) == INVALID_FILE_ATTRIBUTES)
{
CreateDirectory(contentDir.c_str(), NULL);
}
std::wstring assetsDir = contentDir + L"\\Assets";
if (GetFileAttributes(assetsDir.c_str()) == INVALID_FILE_ATTRIBUTES)
{
CreateDirectory(assetsDir.c_str(), NULL);
}
std::wstring kobjectDir = assetsDir + L"\\Kobject";
if (GetFileAttributes(kobjectDir.c_str()) == INVALID_FILE_ATTRIBUTES)
{
CreateDirectory(kobjectDir.c_str(), NULL);
}
}
size_t posFile = filepath.find_last_of(L"\\/");
std::wstring filename = (posFile != std::wstring::npos) ? filepath.substr(posFile + 1) : filepath;
std::wstring targetPath = targetDir + L"\\" + filename;
if (!CopyFile(filepath.c_str(), targetPath.c_str(), FALSE))
{
// En cas d'erreur, vous pouvez gérer ici l'erreur (par exemple afficher un message)
MessageBox(NULL, L"Erreur lors de la copie du fichier.", L"Erreur", MB_OK);
}
else
{
// On récupère le chemin relatif par rapport à exeDir
std::wstring relativePath = targetPath.substr(exeDir.size());
// Suppression du premier caractère s'il s'agit d'un antislash
if (!relativePath.empty() && (relativePath[0] == L'\\' || relativePath[0] == L'/'))
{
relativePath.erase(0, 1);
}
// Remplacer les antislashs par des slashs
std::replace(relativePath.begin(), relativePath.end(), L'\\', L'/');
app_->add_kobject(relativePath);
}
}
}
ImGui::SameLine();
ImGui::Text("Number of cubes: %d", 1);
}
}
void imguiManager::WidgetObjectWindow()
{
ImGui::Begin("Objects", &showObjectWindow);
// Obtenir toutes les entités avec un composant d'identité et de transformation
auto entities = app_->get_entity_manager()->GetEntitiesWithComponent<ecs::IdentityComponent>();
int index = 0;
for (auto& entity : entities)
{
auto identity = entity->GetComponent<ecs::IdentityComponent>();
auto transform = entity->GetComponent<ecs::TransformComponent>();
auto render = entity->GetComponent<ecs::RenderComponent>();
auto shader = entity->GetComponent<ecs::ShaderComponent>();
auto physics = entity->GetComponent<ecs::PhysicsComponent>();
if (identity && transform)
{
std::string headerName = identity->GetName() + " " + std::to_string(identity->GetId());
if (ImGui::CollapsingHeader(headerName.c_str()))
{
// Position, Rotation, Scale
XMVECTOR position = transform->GetPosition();
XMVECTOR rotation = transform->GetRotation();
XMVECTOR scale = transform->GetScale();
float pos[3] = { XMVectorGetX(position), XMVectorGetY(position), XMVectorGetZ(position) };
std::string posLabel = "Position##" + std::to_string(identity->GetId());
if (ImGui::DragFloat3(posLabel.c_str(), pos))
{
transform->SetPosition(XMVectorSet(pos[0], pos[1], pos[2], 0.0f));
transform->UpdateWorldMatrix();
}
float rot[3] = { XMVectorGetX(rotation), XMVectorGetY(rotation), XMVectorGetZ(rotation) };
std::string rotLabel = "Rotation##" + std::to_string(identity->GetId());
if (ImGui::DragFloat3(rotLabel.c_str(), rot))
{
transform->SetRotation(XMVectorSet(rot[0], rot[1], rot[2], 0.0f));
transform->UpdateWorldMatrix();
}
float scl[3] = { XMVectorGetX(scale), XMVectorGetY(scale), XMVectorGetZ(scale) };
std::string sclLabel = "Scale##" + std::to_string(identity->GetId());
if (ImGui::DragFloat3(sclLabel.c_str(), scl))
{
transform->SetScale(XMVectorSet(scl[0], scl[1], scl[2], 0.0f));
transform->UpdateWorldMatrix();
}
ImGui::Separator();
// Textures - Seulement si le composant de rendu existe
if (render && render->GetModel())
{
// Définir les types de textures_
std::vector<std::string> textureCategories = {
"Diffuse", "Normal", "Specular", "Alpha"
};
std::vector<TextureType> textureTypes = {
TextureType::Diffuse, TextureType::Normal,
TextureType::Specular, TextureType::Alpha
};
// Créer un espace pour afficher les textures_ avec défilement
std::string textureChildId = "TextureChild##" + std::to_string(identity->GetId());
ImGui::BeginChild(textureChildId.c_str(), ImVec2(0, 200), true, ImGuiWindowFlags_HorizontalScrollbar);
// Pour chaque type de texture
for (int typeIndex = 0; typeIndex < textureCategories.size(); typeIndex++)
{
TextureType type = textureTypes[typeIndex];
std::string typeName = textureCategories[typeIndex];
// Afficher le titre de la catégorie
std::string categoryLabel = typeName + "##" + std::to_string(identity->GetId());
ImGui::Text("%s:", typeName.c_str());
ImGui::SameLine();
// Compter combien de textures_ de ce type existent
int textureCount = 0;
while (render->GetModel()->GetTexture(type, textureCount) != nullptr)
{
textureCount++;
}
// Afficher toutes les textures_ existantes
std::string groupId = "TextureGroup_" + std::to_string(identity->GetId()) + "_" + std::to_string(typeIndex);
ImGui::BeginGroup();
for (int texIndex = 0; texIndex < textureCount; texIndex++)
{
ID3D11ShaderResourceView* texture = render->GetModel()->GetTexture(type, texIndex);
if (texture)
{
// ID unique pour chaque bouton de texture
std::string buttonId = "tex##" + std::to_string(identity->GetId()) + "_" +
std::to_string(typeIndex) + "_" +
std::to_string(texIndex);
if (ImGui::ImageButton(buttonId.c_str(), (ImTextureID)texture, ImVec2(48, 48)))
{
// Ouvrir une boîte de dialogue pour changer la texture
OPENFILENAME ofn;
WCHAR szFile[260] = {0};
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
// Changer la texture existante
render->GetModel()->ChangeTexture(m_device, m_deviceContext, ofn.lpstrFile, type, texIndex);
}
}
// Afficher l'indice de texture et prévisualisation au survol
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("%s %d", typeName.c_str(), texIndex);
ImGui::Image((ImTextureID)texture, ImVec2(192, 192));
ImGui::EndTooltip();
}
ImGui::SameLine();
}
}
// Bouton pour ajouter une nouvelle texture
std::string addButtonLabel = "+##" + std::to_string(identity->GetId()) + "_" + std::to_string(typeIndex);
if (ImGui::Button(addButtonLabel.c_str(), ImVec2(48, 48)))
{
// Ouvrir une boîte de dialogue pour ajouter une texture
OPENFILENAME ofn;
WCHAR szFile[260] = {0};
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
// Ajouter une nouvelle texture
render->GetModel()->AddTexture(m_device, m_deviceContext, ofn.lpstrFile, type);
}
}
ImGui::EndGroup();
ImGui::Separator();
}
ImGui::EndChild();
}
ImGui::Separator();
// Delete button
std::string deleteLabel = "Delete##" + std::to_string(identity->GetId());
if (ImGui::Button(deleteLabel.c_str()))
{
app_->delete_entity_by_id(identity->GetId());
// Sortir du boucle après suppression pour éviter des accès invalides
break;
}
ImGui::Separator();
// Shader options
if (shader)
{
// Liste des options de shader
const char* shaderOptions[] = {
"Enable Global Lighting",
"Enable Lighting",
"Enable Cel Shading",
"Enable Normal Mapping",
"Enable Specular Mapping",
"Enable Alpha Mapping"
};
std::vector<ecs::ShaderType> shaderTypes = {
ecs::ShaderType::SUNLIGHT,
ecs::ShaderType::LIGHTING,
ecs::ShaderType::CEL_SHADING,
ecs::ShaderType::NORMAL_MAPPING,
ecs::ShaderType::SPECULAR_MAPPING,
ecs::ShaderType::ALPHA_MAPPING
};
// Trouver l'index actuel du shader pour cette entité spécifique
int currentShader = 0;
ecs::ShaderType activeShader = shader->GetActiveShader();
for (size_t i = 0; i < shaderTypes.size(); i++)
{
if (shaderTypes[i] == activeShader)
{
currentShader = static_cast<int>(i);
break;
}
}
// Création du menu déroulant avec un ID unique pour chaque entité
std::string shaderComboId = "Shader Options##" + std::to_string(identity->GetId());
if (ImGui::BeginCombo(shaderComboId.c_str(), shaderOptions[currentShader]))
{
for (int i = 0; i < IM_ARRAYSIZE(shaderOptions); i++)
{
// Crée une option sélectionnable pour chaque shader avec ID unique
std::string shaderSelectableId = std::to_string(i) + "##shader_" + std::to_string(identity->GetId());
bool isSelected = (currentShader == i);
if (ImGui::Selectable(shaderOptions[i], isSelected))
{
// Met à jour l'option sélectionnée uniquement pour cette entité
currentShader = i;
shader->SetActiveShader(shaderTypes[i]);
}
// Si l'option sélectionnée est active, nous mettons en surbrillance
if (isSelected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::Separator();
// Physics
bool isPhysicsEnabled = (physics != nullptr);
std::string physicsLabel = "Physics##" + std::to_string(identity->GetId());
if (ImGui::Checkbox(physicsLabel.c_str(), &isPhysicsEnabled))
{
if (isPhysicsEnabled && !physics)
{
// Ajouter un composant de physique
physics = entity->AddComponent<ecs::PhysicsComponent>();
physics->Initialize();
}
else if (!isPhysicsEnabled && physics)
{
// Retirer le composant de physique
entity->RemoveComponent<ecs::PhysicsComponent>();
physics = nullptr;
}
}
if (physics)
{
// Gravity Enabled checkbox
bool gravityEnabled = physics->IsGravityEnabled();
std::string gravityLabel = "Gravity##" + std::to_string(identity->GetId());
if (ImGui::Checkbox(gravityLabel.c_str(), &gravityEnabled))
{
physics->SetGravityEnabled(gravityEnabled);
}
// 3 radio buttons pour le type d'objet physique avec IDs uniques
std::string typeLabel = "Type##" + std::to_string(identity->GetId());
ecs::ObjectType type = identity->GetType();
if (ImGui::RadioButton(("None##" + std::to_string(identity->GetId())).c_str(),
type == ecs::ObjectType::Unknown))
{
identity->SetType(ecs::ObjectType::Unknown);
}
ImGui::SameLine();
if (ImGui::RadioButton(("Cube##" + std::to_string(identity->GetId())).c_str(),
type == ecs::ObjectType::Cube))
{
identity->SetType(ecs::ObjectType::Cube);
}
ImGui::SameLine();
if (ImGui::RadioButton(("Sphere##" + std::to_string(identity->GetId())).c_str(),
type == ecs::ObjectType::Sphere))
{
identity->SetType(ecs::ObjectType::Sphere);
}
ImGui::SameLine();
if (ImGui::RadioButton(("Terrain##" + std::to_string(identity->GetId())).c_str(),
type == ecs::ObjectType::Terrain))
{
identity->SetType(ecs::ObjectType::Terrain);
}
}
ImGui::Separator();
}
index++;
}
}
ImGui::End();
}
void imguiManager::WidgetTerrainWindow()
{
ImGui::Begin("Terrain", &showTerrainWindow);
ImGui::Text("Number of terrain cubes: %d", 1);
ImGui::Separator();
if (ImGui::Button("Generate Flat Terrain"))
{
app_->generate_terrain();
}
ImGui::Separator();
// Input for the number of cubes on each side
ImGui::Text("Number of cubes on each side: ");
ImGui::SameLine();
ImGui::InputInt("##SideCount", &m_SideCount);
if (m_SideCount < 1)
{
m_SideCount = 1;
}
ImGui::Separator();
if (ImGui::Button("Generate BigCube Terrain"))
{
app_->create_big_cube(m_SideCount);
}
ImGui::Separator();
if (ImGui::Button("Delete All Terrain Cubes"))
{
app_->delete_terrain();
}
ImGui::End();
}
bool imguiManager::ImGuiWidgetRenderer()
{
// Start the Dear ImGui frame
NewFrame();
// Setup the dockspace
SetupDockspace();
//ImGui Widget
ImGui::Begin("Khaotic Engine", NULL);
float speed = app_->get_speed();
WidgetSpeedSlider(&speed);
app_->set_speed(speed);
WidgetButton();
WidgetAddObject();
ImGui::End();
// Read the widget list and call the function if the show variable is true
for (const auto& entry : widgets_)
{
if (*entry.show == true) {entry.func();}
}
//render imgui
Render();
return true;
}
void imguiManager::WidgetLightWindow()
{
ImGui::Begin("Light", &showLightWindow);
// Sun light settings
light_class* sunLight = app_->get_sun_light();
// 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_->get_lights())
{
std::string headerName = "Light " + std::to_string(index);
if (ImGui::CollapsingHeader(headerName.c_str()))
{
XMVECTOR position = app_->get_light_position(index);
XMVECTOR color = app_->get_light_color(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_->set_light_position(index, XMVectorSet(pos[0], pos[1], pos[2], 0.0f));
}
if (ImGui::ColorEdit3(colLabel.c_str(), col))
{
app_->set_light_color(index, XMVectorSet(col[0], col[1], col[2], 0.0f));
}
}
index++;
};
ImGui::End();
}
void imguiManager::WidgetEngineSettingsWindow()
{
ImGui::Begin("Engine Settings", &showEngineSettingsWindow);
// Begining Of General Setting
ImGui::Text("General");
// Checkbox for toggling vsync globally in the application class by calling the set_vsync function in the application class when the checkbox state changes
bool vsync = app_->get_vsync();
if (ImGui::Checkbox("Vsync", &vsync))
{
app_->set_vsync(vsync);
}
// End Of General Setting
ImGui::Separator();
// culling section
ImGui::Text("Culling");
// float input for frustum tolerance
float frustumTolerance = app_->get_frustum_tolerance();
if (ImGui::DragFloat("Frustum Tolerance", &frustumTolerance, 0.1f, 0.0f, 100.0f))
{
app_->set_frustum_tolerance(frustumTolerance);
}
// End Of Culling Setting
ImGui::Separator();
// physics section
ImGui::Text("physics");
// Input To set the Fixed Update Interval
int physicsInterval = app_->get_physics_tick_rate();
if (ImGui::InputInt("physics Tick Rate", &physicsInterval))
{
app_->set_physics_tick_rate(physicsInterval);
}
// Input to change the gravity on same line
XMVECTOR gravity = app_->get_physics()->GetGravity();
float gravityValues[3] = { XMVectorGetX(gravity), XMVectorGetY(gravity), XMVectorGetZ(gravity) };
if (ImGui::DragFloat3("Gravity", gravityValues))
{
app_->get_physics()->SetGravity(XMVectorSet(gravityValues[0], gravityValues[1], gravityValues[2], 0.0f));
}
ImGui::End();
}
void imguiManager::WidgetLogWindow()
{
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<Logger::LogLevel>(i)).name, &isVisible))
{
Logger::Get().m_disabledLogLevels[i] = !isVisible;
}
}
ImGui::EndMenu();
}
const auto& logBuffer = Logger::Get().GetLogBuffer();
std::vector<Logger::LogEntry> 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<size_t>(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(ImVec2 availableSize)
{
ImGui::Begin("render Window");
ImVec2 oldWindowSize = windowSize;
windowSize = ImGui::GetContentRegionAvail();
// Si la taille de la fenêtre a changé, ajustez la taille de la fenêtre de l'application
if (oldWindowSize.x != windowSize.x || oldWindowSize.y != windowSize.y)
{
app_->set_window_size(windowSize);
}
// Get the aspect ratio of the scene in app
float aspectRatio = app_->get_aspect_ratio();
// calculate the size of the window
if (windowSize.x / windowSize.y > aspectRatio)
{
windowSize.x = windowSize.y * aspectRatio;
}
else
{
windowSize.y = windowSize.x / aspectRatio;
}
ID3D11ShaderResourceView* texture = app_->get_scene_texture()->GetShaderResourceView();
if (texture)
{
// Affichez la scenne projeté sur texture dans une fenêtre ImGui
// alpha blend is not enable to render the texture
app_->get_direct_3d()->turn_z_buffer_off();
app_->get_direct_3d()->enable_alpha_blending();
ImGui::Image((ImTextureID)texture, windowSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(1, 1, 1, 1));
}
else
{
ImGui::Text("render texture is not available.");
}
ImGui::End();
}
void imguiManager::WidgetRenderStats()
{
ImGui::Begin("render Stats");
current_fps_ = stats_->get_current_fps();
min_fps_ = stats_->get_min_fps();
max_fps_ = stats_->get_max_fps();
draw_calls_ = stats_->get_draw_calls();
// total_vertex_count_ = stats_->get_total_vertex_count();
// total_triangle_count_ = stats_->get_total_triangle_count();
visible_triangle_count_ = stats_->get_visible_triangle_count();
current_frame_time_ = stats_->get_frame_time();
m_frameTimeHistory[m_frameTimeHistoryIndex] = current_frame_time_;
m_frameTimeHistoryIndex = (m_frameTimeHistoryIndex + 1) % FRAME_HISTORY_COUNT;
ImGui::Text("FPS: %d", current_fps_);
ImGui::SameLine();
ImGui::Text("Min Fps: %d", min_fps_);
ImGui::SameLine();
ImGui::Text("Max Fps: %d", max_fps_);
ImGui::Separator();
// Trouver les valeurs min/max pour l'échelle du graphique
float frameTimeMin = FLT_MAX;
float frameTimeMax = 0.0f;
for (int i = 0; i < FRAME_HISTORY_COUNT; i++) {
if (m_frameTimeHistory[i] > 0.0f) {
frameTimeMin = min(frameTimeMin, m_frameTimeHistory[i]);
frameTimeMax = max(frameTimeMax, m_frameTimeHistory[i]);
}
}
// S'assurer d'avoir au moins une petite plage
if (frameTimeMax == 0.0f) frameTimeMax = 0.033f; // ~30 FPS
if (frameTimeMin == FLT_MAX) frameTimeMin = 0.0f;
// Ajouter 10% de marge pour la lisibilité
float margin = (frameTimeMax - frameTimeMin) * 0.1f;
frameTimeMin = max(0.0f, frameTimeMin - margin);
frameTimeMax += margin;
// Afficher le graphique
ImGui::Text("Frame Time: %.3f ms", current_frame_time_ * 1000.0f);
ImGui::PlotLines("FrameTimeGraph", // Au lieu de chaîne vide ""
m_frameTimeHistory,
FRAME_HISTORY_COUNT,
m_frameTimeHistoryIndex,
"",
frameTimeMin,
frameTimeMax,
ImVec2(0, 80));
ImGui::Text("Draw Calls: %d", draw_calls_);
ImGui::Separator();
ImGui::Text("Statistiques de rendu:");
ImGui::Text("Vertices total: %d", *total_vertex_count_);
ImGui::Text("Triangles total: %d", *total_triangle_count_);
ImGui::SameLine();
ImGui::Text("Triangles visibles: %d", visible_triangle_count_);
app_->get_direct_3d()->get_video_card_info(card_name_, video_memory_);
cpu_name_ = stats_->get_cpu_name();
version_driver_ = stats_->get_gpu_driver_version(app_->get_direct_3d()->get_device());
ImGui::Columns(3, "GPUCPURAMColumns", false);
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.33f);
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.33f);
// Premier collapsing header pour les informations GPU
if (ImGui::CollapsingHeader("Informations GPU"))
{
ImGui::Text("Carte graphique: %s", card_name_);
ImGui::Text("Memoire video: %d Mo", video_memory_);
ImGui::Text("Pilote: %s", version_driver_.c_str());
}
ImGui::NextColumn();
// Second collapsing header pour les informations CPU
if (ImGui::CollapsingHeader("Informations CPU"))
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
ImGui::Text("Processeur: %s", cpu_name_.c_str());
ImGui::Text("Nombre de coeurs: %u", sysInfo.dwNumberOfProcessors);
ImGui::Text("Architecture: %s", (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ? "x64" : "x86");
ImGui::Text("Taille de la page: %u octets", sysInfo.dwPageSize);
ImGui::Text("Taille du cache: %u octets", sysInfo.dwAllocationGranularity);
ImGui::Text("Type de processeur: %u", sysInfo.wProcessorLevel);
ImGui::Text("Version du processeur: %u", sysInfo.wProcessorRevision);
}
ImGui::NextColumn();
if (ImGui::CollapsingHeader("Informations RAM"))
{
MEMORYSTATUSEX mem_info;
mem_info.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&mem_info);
ImGui::Text("Memoire totale: %llu Mo", mem_info.ullTotalPhys / (1024 * 1024));
ImGui::Text("Memoire disponible: %llu Mo", mem_info.ullAvailPhys / (1024 * 1024));
ImGui::Text("Memoire utilisee: %llu Mo", (mem_info.ullTotalPhys - mem_info.ullAvailPhys) / (1024 * 1024));
}
ImGui::Columns(1);
ImGui::End();
}