#include "inspector_panel.hpp" #include #include #include void InspectorPanel::onUpdate(const sophia::FrameInfo&) { selected = context.selected; if (!selected) { ImGui::TextDisabled("No entity selected"); return; } drawTag(); ImGui::Separator(); drawTransform(); drawCamera(); drawSprite(); drawMesh(); ImGui::Separator(); drawAddComponent(); } void InspectorPanel::drawTag() { auto& tag = selected.getComponent(); char nameBuf[128]; std::snprintf(nameBuf, sizeof(nameBuf), "%s", tag.tag.c_str()); if (ImGui::InputText("Name", nameBuf, sizeof(nameBuf))) { tag.tag = nameBuf; } } void InspectorPanel::drawTransform() { if (!selected.hasComponent() || !ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) { return; } auto& transform = selected.getComponent(); ImGui::DragFloat3("Position", &transform.position.x, 0.1f); // Euler angles in degrees, recomputed from the quaternion every frame. // Near 90 degrees of pitch the angles can jump between equivalent values // while dragging. // TODO: keep each entity's edited angles, or replace with gizmo rotation. glm::vec3 degrees = glm::degrees(glm::eulerAngles(transform.rotation)); if (ImGui::DragFloat3("Rotation", °rees.x, 1.0f)) { transform.rotation = glm::quat{glm::radians(degrees)}; } ImGui::DragFloat3("Scale", &transform.scale.x, 0.1f); } void InspectorPanel::drawCamera() { if (!selected.hasComponent() || !ImGui::CollapsingHeader("Camera", ImGuiTreeNodeFlags_DefaultOpen)) { return; } auto& camera = selected.getComponent(); int projection = static_cast(camera.projection); if (ImGui::Combo("Projection", &projection, "Orthographic\0Perspective\0")) { camera.projection = static_cast(projection); } if (camera.projection == sophia::CameraComponent::Projection::Orthographic) { ImGui::DragFloat("Height", &camera.ortho.height, 0.1f, 0.01f, 10000.f); } else { float fov = glm::degrees(camera.perspective.fov); if (ImGui::DragFloat("FOV", &fov, 0.5f, 1.f, 179.f)) { camera.perspective.fov = glm::radians(fov); } } } void InspectorPanel::drawSprite() { if (!selected.hasComponent()) { return; } bool open = true; if (!ImGui::CollapsingHeader("Sprite", &open, ImGuiTreeNodeFlags_DefaultOpen)) { if (!open) { selected.removeComponent(); } return; } auto& sprite = selected.getComponent(); const char* current = "None"; for (const auto& [name, handle] : textures) { if (handle == sprite.texture) { current = name.c_str(); } } if (ImGui::BeginCombo("Texture", current)) { if (ImGui::Selectable("None", !sprite.texture.isValid())) { sprite.texture = sophia::INVALID_HANDLE; } for (const auto& [name, handle] : textures) { if (ImGui::Selectable(name.c_str(), handle == sprite.texture)) { sprite.texture = handle; } } ImGui::EndCombo(); } ImGui::ColorEdit4("Color", &sprite.color.x); ImGui::DragFloat2("Size", &sprite.size.x, 0.05f); ImGui::SliderFloat2("Pivot", &sprite.pivot.x, 0.f, 1.f); ImGui::DragFloat4("UV Rect", &sprite.uvRect.x, 0.01f); ImGui::DragInt("Sort Order", &sprite.sortOrder); if (!open) { selected.removeComponent(); } } void InspectorPanel::drawMesh() { if (!selected.hasComponent()) { return; } bool open = true; if (!ImGui::CollapsingHeader("Mesh", &open, ImGuiTreeNodeFlags_DefaultOpen)) { if (!open) { selected.removeComponent(); } return; } auto& mesh = selected.getComponent(); // TODO: pick the mesh once assets have names. ImGui::Text("Mesh: %u", static_cast(mesh.handle.index)); ImGui::ColorEdit3("Color", &mesh.color.x); if (!open) { selected.removeComponent(); } } void InspectorPanel::drawAddComponent() { if (ImGui::Button("Add Component")) { ImGui::OpenPopup("AddComponent"); } if (ImGui::BeginPopup("AddComponent")) { if (!selected.hasComponent() && ImGui::MenuItem("Sprite")) { selected.addComponent(); } if (!selected.hasComponent() && ImGui::MenuItem("Camera")) { selected.addComponent(); } ImGui::EndPopup(); } }