#include "imgui.h" #include "open_engine/renderer/renderer3d.hpp" #include "open_engine/scene/components.hpp" #include #include #include #include #include #include namespace OpenEngine { void DrawVec3Control(const char* label, glm::vec3& values, float reset_value, float column_width, const std::array labels) { ImGuiIO& io = ImGui::GetIO(); auto bold_font = io.Fonts->Fonts[0]; ImGui::PushID(label); ImVec2 item_spacing = { 15.0f, 0.0f }; ImGui::Columns(2); ImGui::SetColumnWidth(0, column_width); ImGui::Text("%s", label); if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered()) values = glm::vec3(reset_value); ImGui::NextColumn(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0, 0 }); float line_height = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2.0f; ImVec2 button_size = { line_height + 3.0f, line_height }; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.953f, 0.545f, 0.659f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 1.0f, 0.8f, 0.9f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.953f, 0.545f, 0.659f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 0.0f, 0.0f, 0.0f, 1.0f }); ImGui::PushFont(bold_font); if (ImGui::Button(labels[0], button_size)) values.x = reset_value; ImGui::PopFont(); ImGui::PopStyleColor(4); ImGui::SameLine(); ImGui::DragFloat("##X", &values.x, 0.1f, 0.0f, 0.0f, "%.2f"); ImGui::PopItemWidth(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, item_spacing); ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.650f, 0.890f, 0.631f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 1.0f, 0.9f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.650f, 0.890f, 0.631f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 0.0f, 0.0f, 0.0f, 1.0f }); ImGui::PushFont(bold_font); if (ImGui::Button(labels[1], button_size)) values.y = reset_value; ImGui::PopFont(); ImGui::PopStyleColor(4); ImGui::PopStyleVar(); ImGui::SameLine(); ImGui::DragFloat("##Y", &values.y, 0.1f, 0.0f, 0.0f, "%.2f"); ImGui::PopItemWidth(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, item_spacing); ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.533f, 0.698f, 0.976f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.7f, 0.9f, 1.0f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.533f, 0.698f, 0.976f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 0.0f, 0.0f, 0.0f, 1.0f }); ImGui::PushFont(bold_font); if (ImGui::Button(labels[2], button_size)) values.z = reset_value; ImGui::PopFont(); ImGui::PopStyleColor(4); ImGui::PopStyleVar(1); ImGui::SameLine(); ImGui::DragFloat("##Z", &values.z, 0.1f, 0.0f, 0.0f, "%.2f"); ImGui::PopItemWidth(); ImGui::PopStyleVar(); ImGui::Columns(1); ImGui::PopID(); } void TagOnImGuiRender(entt::registry& registry, entt::entity entity) { char buffer[256]; auto& tag = registry.get(entity).tag; std::memset(buffer, 0, sizeof(buffer)); std::strncpy(buffer, tag.c_str(), sizeof(buffer)); if (ImGui::InputText("##tagEditor", buffer, sizeof(buffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll) || (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0))) tag = buffer; ImGui::Spacing(); }; void TransformOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& transform = registry.get(entity); DrawVec3Control("Position", transform.translation); glm::vec3 rotation_comp = glm::degrees(transform.rotation); DrawVec3Control("Rotation", rotation_comp); transform.rotation = glm::radians(rotation_comp); DrawVec3Control("Scale", transform.scale); ImGui::Spacing(); }; void SpriteOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& sprite = registry.get(entity); ImGui::ColorEdit4("color", glm::value_ptr(sprite.color)); ImGui::Button("Texture", { 100, 0 }); if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROWSER_PAYLOAD")) sprite.texture = Texture2D::Create(((const char*)payload->Data)); ImGui::EndDragDropTarget(); } ImGui::DragFloat("Tiling factor", &sprite.tiling_factor); }; void CameraOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& camera_comp = registry.get(entity); auto& camera = camera_comp.camera; ImGui::Checkbox("Is primary", &camera_comp.primary); const char* projection_type_strings[] = {"Perspective", "Orthographic"}; const char* current_projection_type = projection_type_strings[(int)camera.GetProjectionType()]; if (ImGui::BeginCombo("Projection", current_projection_type)) { for (int i = 0; i < 2; i++) { bool is_selected = current_projection_type == projection_type_strings[i]; if (ImGui::Selectable(projection_type_strings[i], is_selected)) { current_projection_type = projection_type_strings[i]; camera.SetProjectionType((SceneCamera::ProjectionType)i); } if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } if (camera.GetProjectionType() == SceneCamera::ProjectionType::Perspective) { float fov = camera.GetVerticalFov(); if (ImGui::DragFloat("Fov", &fov, 0.1f)) camera.SetVerticalFov(fov); float near_clip = camera.GetPerspectiveNearClip(); if (ImGui::DragFloat("Near clip", &near_clip, 0.1f)) camera.SetPerspectiveNearClip(near_clip); float far_clip = camera.GetPerspectiveFarClip(); if (ImGui::DragFloat("Far clip", &far_clip, 0.1f)) camera.SetPerspectiveFarClip(far_clip); } else if (camera.GetProjectionType() == SceneCamera::ProjectionType::Orthographic) { ImGui::Checkbox("Has fixed aspect ratio", &camera_comp.fixed_aspect_ratio); float ortho_size = camera.GetOrthographicSize(); if (ImGui::DragFloat("Orthographic size", &ortho_size, 0.1f)) camera.SetOrthographicSize(ortho_size); float near_clip = camera.GetOrthographicNearClip(); if (ImGui::DragFloat("Near clip", &near_clip, 0.1f)) camera.SetOrthographicNearClip(near_clip); float far_clip = camera.GetOrthographicFarClip(); if (ImGui::DragFloat("Far clip", &far_clip, 0.1f)) camera.SetOrthographicFarClip(far_clip); } }; void MeshOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& mesh_component = registry.get(entity); const char* items[] = { "None", "Quad", "Cube" }; int item_selected_idx = (int)mesh_component.primitive_type; if (ImGui::BeginCombo("Mesh", items[item_selected_idx])) { for (int n = 0; n < 3; n++) { const bool is_selected = (item_selected_idx == n); if (ImGui::Selectable(items[n], is_selected)) item_selected_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } if ((int)mesh_component.primitive_type == (item_selected_idx)) return; mesh_component.primitive_type = (PrimitiveType)(item_selected_idx); switch (mesh_component.primitive_type) { case OpenEngine::PrimitiveType::Quad: { mesh_component.mesh = CreateQuad((uint32_t)entity); break; } case OpenEngine::PrimitiveType::Cube: { mesh_component.mesh = CreateCube((uint32_t)entity); break; } default: mesh_component.mesh = nullptr; break; } } void MaterialOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& material = registry.get(entity).material; ImGui::SliderFloat4("Albedo", glm::value_ptr(material.albedo), 0, 1); ImGui::SliderFloat("Roughness", &material.roughness, 0, 1); ImGui::SliderFloat("Metallic", &material.metallic, 0, 1); ImGui::SliderFloat("Ambient strength", &material.ambient_strength, 0, 1); ImGui::SliderFloat("Specular strength", &material.specular_strength, 0, 10); } void BodyOnImGuiRender(entt::registry ®istry, entt::entity entity) { auto& body_comp = registry.get(entity); const char* items[] = { "Static", "Kinematic", "Dynamic" }; int item_selected_idx = body_comp.type; if (ImGui::BeginCombo("Body type", items[item_selected_idx])) { for (int n = 0; n < 3; n++) { const bool is_selected = (item_selected_idx == n); if (ImGui::Selectable(items[n], is_selected)) item_selected_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } body_comp.type = item_selected_idx; ImGui::SliderFloat("Linear damping", &body_comp.linear_damping, 0, 1); ImGui::SliderFloat("Angular damping", &body_comp.angular_damping, 0, 1); ImGui::SliderFloat("Gravity factor", &body_comp.gravity_factor, 0, 1); ImGui::SliderFloat("Bounciness", &body_comp.restitution, 0, 1); ImGui::SliderFloat("Friction", &body_comp.friction, 0, 1); } void SphereShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) { auto& sphere_comp = registry.get(entity); ImGui::DragFloat("Radius", &sphere_comp.radius, 0.1f, 0.11f, FLT_MAX, "%.2f", ImGuiSliderFlags_AlwaysClamp); } void BoxShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) { auto& box_comp = registry.get(entity); ImGui::DragFloat3("Size", glm::value_ptr(box_comp.size), 0.1f, 0.11f, FLT_MAX, "%.2f", ImGuiSliderFlags_AlwaysClamp); } void PlaneShapeOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& planed_comp = registry.get(entity); ImGui::DragFloat("Size", &planed_comp.extent, 0.1f, 0.01f, FLT_MAX, "%.2f", ImGuiSliderFlags_AlwaysClamp); } void ModelOnImGuiRender(entt::registry& registry, entt::entity entity) { auto& model_comp = registry.get(entity); bool opened = ImGui::TreeNodeEx( (void*)(intptr_t)entity, ImGuiTreeNodeFlags_None, "Meshes"); if (opened) { unsigned int i = 0; for (auto& mesh : model_comp.model->GetMeshes()) ImGui::Text("Mesh: %i", i++); ImGui::PushStyleColor(ImGuiCol_ChildBg, {1, 1, 1, 1}); if (ImGui::BeginChild("Material list")) { for (auto& mesh : model_comp.model->GetMeshes()) ImGui::Text("Material: %s", mesh.material.name.c_str()); ImGui::EndChild(); } ImGui::PopStyleColor(); ImGui::TreePop(); } } }