Files
Nuake-custom/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp
2025-01-27 21:30:18 -05:00

169 lines
7.0 KiB
C++

#include "ViewportWidget.h"
#include <src/UI/ImUI.h>
#include "src/Core/Input.h"
#include "../../EditorInterface.h"
#include "src/Rendering/Vulkan/VulkanRenderer.h"
#include "src/Rendering/Vulkan/SceneViewport.h"
#include <glm/gtc/type_ptr.hpp>
using namespace Nuake;
ViewportWidget::ViewportWidget(EditorContext& context) : IEditorWidget(context)
{
const Vector2& defaultSize = { 1280, 720 };
const UUID viewId = editorContext.GetScene()->m_EditorCamera->ID;
auto& vkRenderer = Nuake::VkRenderer::Get();
auto viewport = vkRenderer.CreateViewport(viewId, defaultSize);
vkRenderer.RegisterSceneViewport(context.GetScene(), viewport->GetID());
sceneViewport = viewport;
}
ViewportWidget::~ViewportWidget()
{
Nuake::VkRenderer::Get().RemoveViewport(sceneViewport->GetID());
}
void ViewportWidget::Update(float ts)
{
}
void ViewportWidget::Draw()
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
if (BeginWidgetWindow(ICON_FA_GAMEPAD + std::string("Viewport")))
{
ImGui::PopStyleVar();
ImGuizmo::BeginFrame();
ImGuizmo::SetOrthographic(false);
ImVec2 regionAvail = ImGui::GetContentRegionAvail();
Vector2 viewportPanelSize = glm::vec2(regionAvail.x, regionAvail.y);
// This is important for make UI mouse coord relative to viewport
// Nuake::Input::SetViewportDimensions(m_ViewportPos, viewportPanelSize);
VkDescriptorSet textureDesc = VkRenderer::Get().DrawImage->GetImGuiDescriptorSet();
ImVec2 imagePos = ImGui::GetWindowPos() + ImGui::GetCursorPos();
// Input::SetEditorViewportSize(m_ViewportPos, viewportPanelSize);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
//m_ViewportPos = { imagePos.x, imagePos.y };
ImGui::Image(textureDesc, regionAvail, { 0, 1 }, { 1, 0 });
ImGui::PopStyleVar();
const Vector2& mousePos = Input::GetMousePosition();
const ImVec2& windowPos = ImGui::GetWindowPos();
const auto windowPosNuake = Vector2(windowPos.x, windowPos.y);
const ImVec2& windowSize = ImGui::GetWindowSize();
const bool isInsideWidth = mousePos.x > windowPos.x && mousePos.x < windowPos.x + windowSize.x;
const bool isInsideHeight = mousePos.y > windowPos.y && mousePos.y < windowPos.y + windowSize.y;
// m_IsHoveringViewport = isInsideWidth && isInsideHeight;
// TODO(antopilo) drag n drop
ImGuizmo::SetDrawlist();
ImGuizmo::AllowAxisFlip(true);
ImGuizmo::SetRect(imagePos.x, imagePos.y, viewportPanelSize.x, viewportPanelSize.y);
// TODO(grid)
auto selection = editorContext.GetSelection();
if (selection.Type == EditorSelectionType::Entity && !Engine::IsPlayMode())
{
if (!selection.Entity.IsValid())
{
editorContext.SetSelection(EditorSelection());
}
else
{
TransformComponent& tc = selection.Entity.GetComponent<TransformComponent>();
Matrix4 transform = tc.GetGlobalTransform();
const auto& editorCam = Engine::GetCurrentScene()->GetCurrentCamera();
Matrix4 cameraView = editorCam->GetTransform();
// Since imguizmo doesnt support reverse-Z, we need to create a new projection matrix
// With a normal near and far plane.
Matrix4 normalZProjection = glm::perspectiveFov(glm::radians(editorCam->Fov), 9.0f * editorCam->AspectRatio, 9.0f, editorCam->Far, editorCam->Near);
static Vector3 camPreviousPos = Engine::GetCurrentScene()->m_EditorCamera->Translation;
static Vector3 camNewPos = Vector3(0, 0, 0);
Vector3 camDelta = camNewPos - camPreviousPos;
Vector3 previousGlobalPos = transform[3];
// Imguizmo calculates the delta from the gizmo,
ImGuizmo::Manipulate(
glm::value_ptr(Engine::GetCurrentScene()->GetCurrentCamera()->GetTransform()),
glm::value_ptr(normalZProjection),
CurrentOperation, CurrentMode,
glm::value_ptr(transform), NULL,
UseSnapping ? &CurrentSnapping.x : NULL
);
if (ImGuizmo::IsUsing())
{
// Since imguizmo returns a transform in global space and we want the local transform,
// we need to multiply by the inverse of the parent's global transform in order to revert
// the changes from the parent transform.
Matrix4 localTransform = Matrix4(transform);
Vector3 newGlobalPos = transform[3];
if (ImGui::IsKeyDown(ImGuiKey_LeftShift))
{
Vector3 positionDelta = newGlobalPos - previousGlobalPos;
Engine::GetCurrentScene()->m_EditorCamera->Translation += positionDelta;
camNewPos = Engine::GetCurrentScene()->m_EditorCamera->Translation;
}
ParentComponent& parent = selection.Entity.GetComponent<ParentComponent>();
if (parent.HasParent)
{
const auto& parentTransformComponent = parent.Parent.GetComponent<TransformComponent>();
const Matrix4& parentTransform = parentTransformComponent.GetGlobalTransform();
localTransform = glm::inverse(parentTransform) * localTransform;
}
// Decompose local transform
float decomposedPosition[3];
float decomposedEuler[3];
float decomposedScale[3];
ImGuizmo::DecomposeMatrixToComponents(glm::value_ptr(localTransform), decomposedPosition, decomposedEuler, decomposedScale);
const auto& localPosition = Vector3(decomposedPosition[0], decomposedPosition[1], decomposedPosition[2]);
const auto& localScale = Vector3(decomposedScale[0], decomposedScale[1], decomposedScale[2]);
localTransform[0] /= localScale.x;
localTransform[1] /= localScale.y;
localTransform[2] /= localScale.z;
const auto& rotationMatrix = Matrix3(localTransform);
const Quat& localRotation = glm::normalize(Quat(rotationMatrix));
const Matrix4& rotationMatrix4 = glm::mat4_cast(localRotation);
const Matrix4& scaleMatrix = glm::scale(Matrix4(1.0f), localScale);
const Matrix4& translationMatrix = glm::translate(Matrix4(1.0f), localPosition);
const Matrix4& newLocalTransform = translationMatrix * rotationMatrix4 * scaleMatrix;
tc.Translation = localPosition;
if (CurrentOperation != ImGuizmo::SCALE)
{
tc.Rotation = localRotation;
}
tc.Scale = localScale;
tc.LocalTransform = newLocalTransform;
tc.Dirty = true;
}
}
}
}
else
{
ImGui::PopStyleVar();
}
ImGui::End();
}