feat: add imguizmo + trigger buxfix
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#include <destrum/Util/TransformGizmo.h>
|
||||
|
||||
#include <destrum/Graphics/Camera.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtx/matrix_decompose.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <ImGuizmo.h>
|
||||
|
||||
namespace {
|
||||
ImGuizmo::OPERATION toImGuizmo(GizmoOperation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case GizmoOperation::Rotate:
|
||||
return ImGuizmo::ROTATE;
|
||||
case GizmoOperation::Scale:
|
||||
return ImGuizmo::SCALE;
|
||||
case GizmoOperation::Translate:
|
||||
break;
|
||||
}
|
||||
return ImGuizmo::TRANSLATE;
|
||||
}
|
||||
}
|
||||
|
||||
void TransformGizmo::HandleShortcuts()
|
||||
{
|
||||
if (ImGui::GetIO().WantTextInput || ImGuizmo::IsUsing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_T, false)) {
|
||||
operation = GizmoOperation::Translate;
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_R, false)) {
|
||||
operation = GizmoOperation::Rotate;
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Y, false)) {
|
||||
operation = GizmoOperation::Scale;
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_L, false)) {
|
||||
space = space == GizmoSpace::World ? GizmoSpace::Local : GizmoSpace::World;
|
||||
}
|
||||
}
|
||||
|
||||
void TransformGizmo::DrawToolbar()
|
||||
{
|
||||
if (!ImGui::Begin("Gizmo", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto operationButton = [this](const char* label, GizmoOperation buttonOperation) {
|
||||
if (ImGui::RadioButton(label, operation == buttonOperation)) {
|
||||
operation = buttonOperation;
|
||||
}
|
||||
};
|
||||
operationButton("Move (T)", GizmoOperation::Translate);
|
||||
ImGui::SameLine();
|
||||
operationButton("Rotate (R)", GizmoOperation::Rotate);
|
||||
ImGui::SameLine();
|
||||
operationButton("Scale (Y)", GizmoOperation::Scale);
|
||||
|
||||
if (operation != GizmoOperation::Scale) {
|
||||
bool local = space == GizmoSpace::Local;
|
||||
if (ImGui::Checkbox("Local (L)", &local)) {
|
||||
space = local ? GizmoSpace::Local : GizmoSpace::World;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Snap", &snap);
|
||||
if (snap) {
|
||||
ImGui::SetNextItemWidth(80.0f);
|
||||
switch (operation) {
|
||||
case GizmoOperation::Translate:
|
||||
ImGui::DragFloat("Step", &translationSnap, 0.05f, 0.01f, 10.0f, "%.2f m");
|
||||
break;
|
||||
case GizmoOperation::Rotate:
|
||||
ImGui::DragFloat("Step", &rotationSnapDegrees, 1.0f, 1.0f, 90.0f, "%.0f deg");
|
||||
break;
|
||||
case GizmoOperation::Scale:
|
||||
ImGui::DragFloat("Step", &scaleSnap, 0.01f, 0.01f, 1.0f, "%.2f");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool TransformGizmo::Manipulate(GameObject& object, const Camera& camera)
|
||||
{
|
||||
ImGuizmo::BeginFrame();
|
||||
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGuizmo::SetOrthographic(false);
|
||||
ImGuizmo::SetRect(viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y);
|
||||
|
||||
const glm::mat4 view = camera.GetViewMatrix();
|
||||
glm::mat4 projection = camera.GetProjectionMatrix();
|
||||
// ImGuizmo expects OpenGL's y up clip space, the engine flips y for Vulkan
|
||||
projection[1][1] *= -1.0f;
|
||||
|
||||
Transform& transform = object.GetTransform();
|
||||
glm::mat4 worldMatrix = transform.GetWorldMatrix();
|
||||
|
||||
const float snapStep = operation == GizmoOperation::Translate ? translationSnap
|
||||
: operation == GizmoOperation::Rotate ? rotationSnapDegrees
|
||||
: scaleSnap;
|
||||
const float snapValues[3] = {snapStep, snapStep, snapStep};
|
||||
const ImGuizmo::MODE mode =
|
||||
operation == GizmoOperation::Scale || space == GizmoSpace::Local ? ImGuizmo::LOCAL : ImGuizmo::WORLD;
|
||||
|
||||
const bool changed = ImGuizmo::Manipulate(
|
||||
glm::value_ptr(view),
|
||||
glm::value_ptr(projection),
|
||||
toImGuizmo(operation),
|
||||
mode,
|
||||
glm::value_ptr(worldMatrix),
|
||||
nullptr,
|
||||
snap ? snapValues : nullptr);
|
||||
|
||||
// Stops the click on a handle from reaching the game, e.g. grabbing the mouse for first person
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
ImGui::SetNextFrameWantCaptureMouse(true);
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
glm::vec3 scale;
|
||||
glm::vec3 skew;
|
||||
glm::vec4 perspective;
|
||||
if (!glm::decompose(worldMatrix, scale, rotation, position, skew, perspective)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
case GizmoOperation::Translate:
|
||||
transform.SetWorldPosition(position);
|
||||
break;
|
||||
case GizmoOperation::Rotate:
|
||||
transform.SetWorldRotation(rotation);
|
||||
break;
|
||||
case GizmoOperation::Scale:
|
||||
transform.SetWorldScale(scale);
|
||||
break;
|
||||
}
|
||||
|
||||
object.RefreshPhysicsInHierarchy();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransformGizmo::IsUsing() const
|
||||
{
|
||||
return ImGuizmo::IsUsing();
|
||||
}
|
||||
|
||||
bool TransformGizmo::IsOver() const
|
||||
{
|
||||
return ImGuizmo::IsOver();
|
||||
}
|
||||
Reference in New Issue
Block a user