Skip to content

Commit

Permalink
Feat: Show gizmo for selected entity
Browse files Browse the repository at this point in the history
  • Loading branch information
brenocq committed Jan 19, 2025
1 parent d74f3d8 commit 5edf760
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 149 deletions.
1 change: 1 addition & 0 deletions src/atta/ui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(ATTA_UI_MODULE_SOURCE

widgets/align.cpp
widgets/button.cpp
widgets/gizmo.cpp
widgets/help.cpp
widgets/image.cpp

Expand Down
55 changes: 30 additions & 25 deletions src/atta/ui/widgets/gizmo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,35 @@

namespace atta::ui {

Gizmo::Gizmo() : _operation(TRANSLATE), _mode(WORLD), _isOrthographic(false), _snap(false) {}
Gizmo::Gizmo() : _operation(TRANSLATE), _mode(WORLD), _snap(false) {}

void Gizmo::setOperation(Operation operation) { _operation = operation; }
void Gizmo::setMode(Mode mode) { _mode = mode; }
void Gizmo::setCamera(std::weak_ptr<gfx::Camera> camera) { _camera = camera; }
void Gizmo::setSnap(bool snap) { _snap = snap; }

void Gizmo::setCamera(std::weak_ptr<Camera> camera) { _camera = camera; }

ImGuizmo::OPERATION convert(Operation operation) {
ImGuizmo::OPERATION convert(Gizmo::Operation operation) {
ImGuizmo::OPERATION result{};
if (operation & TRANSLATE > 0)
if ((operation & Gizmo::TRANSLATE) > 0)
result = result | ImGuizmo::OPERATION::TRANSLATE;
if (operation & ROTATE > 0)
if ((operation & Gizmo::ROTATE) > 0)
result = result | ImGuizmo::OPERATION::ROTATE;
if (operation & SCALE > 0)
if ((operation & Gizmo::SCALE) > 0)
result = result | ImGuizmo::OPERATION::SCALE;
return result;
}

ImGuizmo::MODE convert(Mode mode) { return mode == WORLD ? ImGuizmo::MODE::WORLD : ImGuizmo::MODE::LOCAL; }
ImGuizmo::MODE convert(Gizmo::Mode mode) { return mode == Gizmo::WORLD ? ImGuizmo::MODE::WORLD : ImGuizmo::MODE::LOCAL; }

bool Gizmo::manipulate(component::EntityId entity) {
std::shared_ptr<Camera> camera = _camera.lock();
component::Transform* t = component::getComponent<component::Transform>(entity);
if (t) {
bool Gizmo::manipulate(cmp::EntityId entity) {
std::shared_ptr<gfx::Camera> camera = _camera.lock();
cmp::Transform* t = cmp::getComponent<cmp::Transform>(entity);
if (camera && t) {
mat4 transform = transpose(t->getWorldTransformMatrix(entity));

ImGuizmo::SetDrawlist();
ImGuizmo::SetRect(ImGui::GetWindowPos().x + 5.0f, ImGui::GetWindowPos().y + 24.0f, 500, 500);
ImVec2 windowPos = ImGui::GetWindowPos();
ImVec2 windowSize = ImGui::GetWindowSize();
ImGuizmo::SetRect(windowPos.x, windowPos.y, windowSize.x - 10.0f, windowSize.y - 8.0f);

ImGuizmo::OPERATION operation = convert(_operation);
ImGuizmo::MODE mode = convert(_mode);
Expand All @@ -54,7 +54,12 @@ bool Gizmo::manipulate(component::EntityId entity) {
mat4 proj = transpose(camera->getProj());
proj.mat[1][1] *= -1;

if (ImGuizmo::Manipulate(transpose(_view).data, _proj.data, operation, mode, transform.data, nullptr, snap ? snapValues : nullptr)) {
float snapValue = 0.5f;
if (operation == ImGuizmo::OPERATION::ROTATE)
snapValue = 45.0f;
float snapValues[3] = {snapValue, snapValue, snapValue};

if (ImGuizmo::Manipulate(view.data, proj.data, operation, mode, transform.data, nullptr, _snap ? snapValues : nullptr)) {
transform.transpose();

// Get changed
Expand All @@ -66,22 +71,22 @@ bool Gizmo::manipulate(component::EntityId entity) {
ori.setEuler(t->orientation.getEuler() + oriDelta);

// Delta world to local
component::Relationship* r = component::getComponent<component::Relationship>(entity);
cmp::Relationship* r = cmp::getComponent<cmp::Relationship>(entity);
if (r && r->getParent() != -1) {
// Get transform of the first entity that has transform when going up in the hierarchy
component::Transform* pt = nullptr;
component::EntityId parentId = -1;
cmp::Transform* pt = nullptr;
cmp::EntityId parentId = -1;
while (pt == nullptr) {
parentId = r->getParent();
pt = component::getComponent<component::Transform>(parentId);
r = component::getComponent<component::Relationship>(parentId);
pt = cmp::getComponent<cmp::Transform>(parentId);
r = cmp::getComponent<cmp::Relationship>(parentId);
if (r->getParent() == -1)
break;
}

// If found some entity with transform component, convert result to be relative to it
if (pt) {
component::Transform pTransform = pt->getWorldTransform(parentId);
cmp::Transform pTransform = pt->getWorldTransform(parentId);
vec3 pPos = pTransform.position;
vec3 pScale = pTransform.scale;
quat pOri = pTransform.orientation;
Expand All @@ -94,14 +99,14 @@ bool Gizmo::manipulate(component::EntityId entity) {
}

// Update entity transform
if (mouseOperation == ImGuizmo::OPERATION::TRANSLATE)
if (operation == ImGuizmo::OPERATION::TRANSLATE)
t->position = pos;
else if (mouseOperation == ImGuizmo::OPERATION::ROTATE)
else if (operation == ImGuizmo::OPERATION::ROTATE)
t->orientation = ori;
else if (mouseOperation == ImGuizmo::OPERATION::SCALE)
else if (operation == ImGuizmo::OPERATION::SCALE)
t->scale = scale;

// component::RigidBody2D* rb2d = component::getComponent<component::RigidBody2D>(entity);
// cmp::RigidBody2D* rb2d = cmp::getComponent<cmp::RigidBody2D>(entity);
// if (rb2d) {
// if (mouseOperation == ImGuizmo::OPERATION::TRANSLATE || mouseOperation == ImGuizmo::OPERATION::ROTATE) {
// vec2 pos = vec2(t->position);
Expand Down
10 changes: 7 additions & 3 deletions src/atta/ui/widgets/gizmo.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,27 @@ class Gizmo {
TRANSLATE = 1 << 0,
ROTATE = 1 << 1,
SCALE = 1 << 2,
TRANSLATE_ROTATE = TRANSLATE | ROTATE,
TRANSLATE_SCALE = TRANSLATE | SCALE,
ROTATE_SCALE = ROTATE | SCALE,
ALL = TRANSLATE | ROTATE | SCALE
};
inline Operation operator|(OPERATION l, OPERATION r) { return Operation(int(l) | int(r)); }
friend inline Operation operator|(Operation l, Operation r) { return Operation(int(l) | int(r)); }
enum Mode { WORLD = 0, LOCAL };

Gizmo();

void setOperation(Operation operation);
void setMode(Mode mode);
void setCamera(std::weak_ptr<Camera> camera);
void setCamera(std::weak_ptr<gfx::Camera> camera);
void setSnap(bool snap);

bool manipulate(component::EntityId entity);

private:
Operation _operation;
Mode _mode;
std::weak_ptr<Camera> _camera;
std::weak_ptr<gfx::Camera> _camera;
bool _snap;
};

Expand Down
149 changes: 28 additions & 121 deletions src/atta/ui/windows/viewport/viewportWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// Date: 2021-12-28
// By Breno Cunha Queiroz
//--------------------------------------------------
#include <atta/component/base.h>
#include <atta/component/components/material.h>
#include <atta/component/components/mesh.h>
#include <atta/component/components/name.h>
Expand Down Expand Up @@ -107,130 +108,36 @@ void ViewportWindows::renderUI() {
ImGui::OpenPopup("Editor_AddBasicShape");
addBasicShapePopup();

//----- Keyboard click -----//
// static ImGuizmo::OPERATION mouseOperation = ImGuizmo::OPERATION::TRANSLATE;
// static ImGuizmo::MODE mouseMode = ImGuizmo::MODE::LOCAL;
// static bool snap = false;

// if (ImGui::IsWindowHovered()) {
// snap = false;
// ImGuiIO& io = ImGui::GetIO();
// if (ImGui::IsKeyPressed(ImGuiKey_T) && io.KeyCtrl) {
// mouseOperation = ImGuizmo::OPERATION::TRANSLATE;
// mouseMode = ImGuizmo::MODE::LOCAL;
// } else if (ImGui::IsKeyPressed(ImGuiKey_T) && io.KeyShift) {
// mouseOperation = ImGuizmo::OPERATION::TRANSLATE;
// mouseMode = ImGuizmo::MODE::WORLD;
// } else if (ImGui::IsKeyPressed(ImGuiKey_S) && io.KeyCtrl) {
// mouseOperation = ImGuizmo::OPERATION::SCALE;
// mouseMode = ImGuizmo::MODE::LOCAL;
// } else if (ImGui::IsKeyPressed(ImGuiKey_S) && io.KeyShift) {
// mouseOperation = ImGuizmo::OPERATION::SCALE;
// mouseMode = ImGuizmo::MODE::WORLD;
// } else if (ImGui::IsKeyPressed(ImGuiKey_R) && io.KeyCtrl) {
// mouseOperation = ImGuizmo::OPERATION::ROTATE;
// mouseMode = ImGuizmo::MODE::LOCAL;
// } else if (ImGui::IsKeyPressed(ImGuiKey_R) && io.KeyShift) {
// mouseOperation = ImGuizmo::OPERATION::ROTATE;
// mouseMode = ImGuizmo::MODE::WORLD;
// } else if (io.KeyCtrl)
// snap = true;
// }

//----- Render to texture -----//
//----- Operation selection -----//
if (ImGui::IsWindowHovered()) {
ImGuiIO& io = ImGui::GetIO();

if (io.KeyCtrl)
_gizmo.setMode(Gizmo::LOCAL);
if (io.KeyShift)
_gizmo.setMode(Gizmo::WORLD);

if (ImGui::IsKeyPressed(ImGuiKey_T))
_gizmo.setOperation(Gizmo::TRANSLATE);
else if (ImGui::IsKeyPressed(ImGuiKey_S))
_gizmo.setOperation(Gizmo::SCALE);
else if (ImGui::IsKeyPressed(ImGuiKey_R))
_gizmo.setOperation(Gizmo::ROTATE);
}

//----- Render viewport to texture -----//
ImVec2 size = ImVec2(viewport->getWidth(), viewport->getHeight());
ImGui::Image((ImTextureID)(intptr_t)viewport->getImGuiTexture(), size, ImVec2(0, 0), ImVec2(1, 1));

//----- ImGuizmo -----//
bool imGuizmoUsingMouse = false;
// component::EntityId entity = component::getSelectedEntity();
// if (entity >= 0) {
// component::Transform* t = component::getComponent<component::Transform>(entity);

// if (t) {
// ImGuizmo::SetOrthographic(viewport->getCamera()->getName() == "OrthographicCamera");
// ImGuizmo::SetDrawlist();
// ImGuizmo::SetRect(ImGui::GetWindowPos().x + 5.0f, ImGui::GetWindowPos().y + 24.0f, viewport->getWidth(),
// viewport->getHeight());
// mat4 view = transpose(viewport->getCamera()->getView());
// mat4 proj = viewport->getCamera()->getProj();
// proj.mat[1][1] *= -1;
// proj.transpose();

// mat4 transform = transpose(t->getWorldTransformMatrix(entity));

// float snapValue = 0.5f;
// if (mouseOperation == ImGuizmo::OPERATION::ROTATE)
// snapValue = 45.0f;
// float snapValues[3] = {snapValue, snapValue, snapValue};

// ImGuizmo::Manipulate(view.data, proj.data, mouseOperation, mouseMode, transform.data, nullptr, snap ? snapValues :
// nullptr);

// if (ImGuizmo::IsUsing()) {
// imGuizmoUsingMouse = true;
// transform.transpose();

// // Get changed
// vec3 pos, scale;
// quat newOri;
// transform.getPosOriScale(pos, newOri, scale);
// vec3 oriDelta = newOri.getEuler() - t->orientation.getEuler();
// quat ori;
// ori.setEuler(t->orientation.getEuler() + oriDelta);

// // Delta world to local
// component::Relationship* r = component::getComponent<component::Relationship>(entity);
// if (r && r->getParent() != -1) {
// // Get transform of the first entity that has transform when going up in the hierarchy
// component::Transform* pt = nullptr;
// component::EntityId parentId = -1;
// while (pt == nullptr) {
// parentId = r->getParent();
// pt = component::getComponent<component::Transform>(parentId);
// r = component::getComponent<component::Relationship>(parentId);
// if (r->getParent() == -1)
// break;
// }

// // If found some entity with transform component, convert result to be relative to it
// if (pt) {
// component::Transform pTransform = pt->getWorldTransform(parentId);
// vec3 pPos = pTransform.position;
// vec3 pScale = pTransform.scale;
// quat pOri = pTransform.orientation;

// // Calculate pos ori scale relative to parent
// pos -= pPos;
// scale /= pScale;
// ori = ori * (-pOri); // Rotation from pOri to ori
// }
// }

// // Update entity transform
// if (mouseOperation == ImGuizmo::OPERATION::TRANSLATE)
// t->position = pos;
// else if (mouseOperation == ImGuizmo::OPERATION::ROTATE)
// t->orientation = ori;
// else if (mouseOperation == ImGuizmo::OPERATION::SCALE)
// t->scale = scale;

// // component::RigidBody2D* rb2d = component::getComponent<component::RigidBody2D>(entity);
// // if (rb2d) {
// // if (mouseOperation == ImGuizmo::OPERATION::TRANSLATE || mouseOperation == ImGuizmo::OPERATION::ROTATE) {
// // vec2 pos = vec2(t->position);
// // float angle = -t->orientation.getEuler().z;
// // rb2d->setTransform(pos, angle);
// // } else if (mouseOperation == ImGuizmo::OPERATION::SCALE) {
// // // TODO Recreate box2d rigid body
// // }
// // }
// }
// }
// }

// //----- Mouse click selection -----//
if (!imGuizmoUsingMouse) {
//----- Gizmo manipulation -----//
bool gizmoUsingMouse = false;
_gizmo.setCamera(viewport->getCamera());
cmp::EntityId eid = component::getSelectedEntity();
if (eid >= 0 && _gizmo.manipulate(eid))
gizmoUsingMouse = true;

//----- Mouse click selection -----//
if (!gizmoUsingMouse) {
if (click.x >= 0 && click.y >= 0 && click.x < (int)viewport->getWidth() && click.y < (int)viewport->getHeight()) {
cmp::EntityId eid = _computeEntityClick->click(viewport->getRenderer(), viewport->getCamera(), click);
cmp::setSelectedEntity(eid);
Expand Down
6 changes: 6 additions & 0 deletions src/atta/ui/windows/viewport/viewportWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <atta/component/interface.h>
#include <atta/graphics/compute/entityClick.h>
#include <atta/ui/widgets/gizmo.h>
#include <atta/ui/windows/viewport/viewport.h>

namespace atta::ui {
Expand Down Expand Up @@ -40,8 +41,13 @@ class ViewportWindows {
float _viewportFPS = 30.0; ///< Desired viewport FPS (UI module handles the viewport rendering)
bool _viewportRendering = true; ///< If should render the viewport

// Gizmo
Gizmo _gizmo;

// Compute
std::unique_ptr<gfx::EntityClick> _computeEntityClick;

// Modals
std::map<StringId, bool> _openModals; ///< Open modals for each viewport
};

Expand Down

0 comments on commit 5edf760

Please sign in to comment.