Skip to content

Commit

Permalink
feat(tools): add rotation gizmo
Browse files Browse the repository at this point in the history
  • Loading branch information
DiogoMendonc-a committed Mar 8, 2024
1 parent 074ff7f commit ae4fe9e
Showing 1 changed file with 109 additions and 31 deletions.
140 changes: 109 additions & 31 deletions tools/tesseratos/src/tesseratos/transform_gizmo/plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/intersect.hpp>
#include <glm/gtx/vector_angle.hpp>

#include <cubos/engine/gizmos/plugin.hpp>
#include <cubos/engine/input/plugin.hpp>
Expand Down Expand Up @@ -60,19 +61,39 @@ static glm::vec3 mouseWorldCoordinates(glm::ivec2 windowSize, glm::ivec2 mousePo
return intersectLinePlane(cameraPosition, dir, transformPosition, transformNormal);
}

static void checkMovement(Position& position, glm::vec3 transformVector, glm::vec3 transformNormal,
glm::ivec2 windowSize, const Input& input, const glm::mat4& pv, glm::vec3 cameraPosition)
static void checkMovement(Position& position, glm::vec3 globalPosition, glm::vec3 transformVector,
glm::vec3 transformNormal, glm::ivec2 windowSize, const Input& input, const glm::mat4& pv,
glm::vec3 cameraPosition)
{
auto mousePosWorld =
mouseWorldCoordinates(windowSize, input.mousePosition(), position.vec, transformNormal, cameraPosition, pv);
auto oldMousePosWorld = mouseWorldCoordinates(windowSize, input.previousMousePosition(), position.vec,
mouseWorldCoordinates(windowSize, input.mousePosition(), globalPosition, transformNormal, cameraPosition, pv);
auto oldMousePosWorld = mouseWorldCoordinates(windowSize, input.previousMousePosition(), globalPosition,
transformNormal, cameraPosition, pv);
position.vec += (mousePosWorld - oldMousePosWorld) * transformVector;
}

static void drawTransformGizmo(Query<const Camera&, LocalToWorld&> cameraQuery,
Query<Position&, LocalToWorld&> positionQuery, Gizmos& gizmos, const Input& input,
const Window& window, Entity cameraEntity, Entity selectedEntity)
static void checkRotation(Rotation& rotation, glm::vec3 globalPosition, glm::vec3 axisVector, glm::ivec2 windowSize,
const Input& input, const glm::mat4& pv, glm::vec3 cameraPosition)
{
auto mousePosWorld =
mouseWorldCoordinates(windowSize, input.mousePosition(), globalPosition, axisVector, cameraPosition, pv);
auto oldMousePosWorld = mouseWorldCoordinates(windowSize, input.previousMousePosition(), globalPosition, axisVector,
cameraPosition, pv);
auto oldVec = oldMousePosWorld - globalPosition;
auto newVec = mousePosWorld - globalPosition;

if (glm::length2(oldVec) == 0 || glm::length2(newVec) == 0)
{
return;
}

auto angle = glm::orientedAngle(glm::normalize(oldVec), glm::normalize(newVec), axisVector);
rotation.quat = glm::angleAxis(angle, axisVector) * rotation.quat;
}

static void drawPositionGizmo(Query<const Camera&, LocalToWorld&> cameraQuery,
Query<Position&, LocalToWorld&> positionQuery, Gizmos& gizmos, const Input& input,
const Window& window, Entity cameraEntity, Entity selectedEntity)
{
auto [camera, cameraLtw] = *cameraQuery.at(cameraEntity);

Expand All @@ -97,62 +118,117 @@ static void drawTransformGizmo(Query<const Camera&, LocalToWorld&> cameraQuery,
glm::vec3 yzColor = {0, 1, 1};

// Axis movement
if (gizmos.locked("transform_gizmo.x"))
if (gizmos.locked("transform_gizmo.position.x"))
{
checkMovement(position, {1, 0, 0}, {0, 1, 0}, window->size(), input, pv, cameraPosition);
checkMovement(position, localToWorld.worldPosition(), {1, 0, 0}, {0, 1, 0}, window->size(), input, pv,
cameraPosition);
xColor = {1, 1, 0};
}
if (gizmos.locked("transform_gizmo.y"))
if (gizmos.locked("transform_gizmo.position.y"))
{
checkMovement(position, {0, 1, 0}, {1, 0, 0}, window->size(), input, pv, cameraPosition);
checkMovement(position, localToWorld.worldPosition(), {0, 1, 0}, {1, 0, 0}, window->size(), input, pv,
cameraPosition);
yColor = {1, 1, 0};
}
if (gizmos.locked("transform_gizmo.z"))
if (gizmos.locked("transform_gizmo.position.z"))
{
checkMovement(position, {0, 0, 1}, {0, 1, 0}, window->size(), input, pv, cameraPosition);
checkMovement(position, localToWorld.worldPosition(), {0, 0, 1}, {0, 1, 0}, window->size(), input, pv,
cameraPosition);
zColor = {1, 1, 0};
}

// Planar movement
if (gizmos.locked("transform_gizmo.xy"))
if (gizmos.locked("transform_gizmo.position.xy"))
{
checkMovement(position, {1, 1, 0}, {0, 0, 1}, window->size(), input, pv, cameraPosition);
checkMovement(position, localToWorld.worldPosition(), {1, 1, 0}, {0, 0, 1}, window->size(), input, pv,
cameraPosition);
xyColor = {1, 1, 1};
}
if (gizmos.locked("transform_gizmo.xz"))
if (gizmos.locked("transform_gizmo.position.xz"))
{
checkMovement(position, {1, 0, 1}, {0, 1, 0}, window->size(), input, pv, cameraPosition);
checkMovement(position, localToWorld.worldPosition(), {1, 0, 1}, {0, 1, 0}, window->size(), input, pv,
cameraPosition);
xzColor = {1, 1, 1};
}
if (gizmos.locked("transform_gizmo.yz"))
if (gizmos.locked("transform_gizmo.position.yz"))
{
checkMovement(position, {0, 1, 1}, {1, 0, 0}, window->size(), input, pv, cameraPosition);
checkMovement(position, localToWorld.worldPosition(), {0, 1, 1}, {1, 0, 0}, window->size(), input, pv,
cameraPosition);
yzColor = {1, 1, 1};
}

gizmos.color(xyColor);
gizmos.drawBox("transform_gizmo.xy", localToWorld.worldPosition() - glm::vec3{0, 0, 0.015F},
gizmos.drawBox("transform_gizmo.position.xy", localToWorld.worldPosition() - glm::vec3{0, 0, 0.015F},
localToWorld.worldPosition() + glm::vec3{0.25F, 0.25F, 0.015F});
gizmos.color(xzColor);
gizmos.drawBox("transform_gizmo.xz", localToWorld.worldPosition() - glm::vec3{0, 0.015F, 0},
gizmos.drawBox("transform_gizmo.position.xz", localToWorld.worldPosition() - glm::vec3{0, 0.015F, 0},
localToWorld.worldPosition() + glm::vec3{0.25F, 0.015F, 0.25F});
gizmos.color(yzColor);
gizmos.drawBox("transform_gizmo.yz", localToWorld.worldPosition() - glm::vec3{0.015F, 0, 0},
gizmos.drawBox("transform_gizmo.position.yz", localToWorld.worldPosition() - glm::vec3{0.015F, 0, 0},
localToWorld.worldPosition() + glm::vec3{0.015F, 0.25F, 0.25F});

gizmos.color({0.7F, 0.7F, 0.7F});
gizmos.drawBox("", localToWorld.worldPosition() + glm::vec3{0.03F, 0.03F, 0.03F},
localToWorld.worldPosition() - glm::vec3{0.03F, 0.03F, 0.03F});

gizmos.color(xColor);
gizmos.drawArrow("transform_gizmo.x", localToWorld.worldPosition() + glm::vec3{0.03F, 0, 0}, {1, 0, 0}, 0.03F,
0.07F, 0.7F);
gizmos.drawArrow("transform_gizmo.position.x", localToWorld.worldPosition() + glm::vec3{0.03F, 0, 0}, {1, 0, 0},
0.03F, 0.07F, 0.7F);
gizmos.color(yColor);
gizmos.drawArrow("transform_gizmo.position.y", localToWorld.worldPosition() + glm::vec3{0, 0.03F, 0}, {0, 1, 0},
0.03F, 0.07F, 0.7F);
gizmos.color(zColor);
gizmos.drawArrow("transform_gizmo.position.z", localToWorld.worldPosition() + glm::vec3{0, 0, 0.03F}, {0, 0, 1},
0.03F, 0.07F, 0.7F);
}

static void drawRotationGizmo(Query<const Camera&, LocalToWorld&> cameraQuery,
Query<Rotation&, LocalToWorld&> positionQuery, Gizmos& gizmos, const Input& input,
const Window& window, Entity cameraEntity, Entity selectedEntity)
{
auto [camera, cameraLtw] = *cameraQuery.at(cameraEntity);

auto [rotation, localToWorld] = *positionQuery.at(selectedEntity);

auto cameraPosition = cameraLtw.worldPosition();

auto pv = cameraLtw.mat;

pv = glm::inverse(pv);

pv = glm::perspective(glm::radians(camera.fovY), (float)window->size().x / (float)window->size().y, camera.zNear,
camera.zFar) *
pv;

glm::vec3 xColor = {1, 0, 0};
glm::vec3 yColor = {0, 1, 0};
glm::vec3 zColor = {0, 0, 1};

if (gizmos.locked("transform_gizmo.rotation.x"))
{
checkRotation(rotation, localToWorld.worldPosition(), {1, 0, 0}, window->size(), input, pv, cameraPosition);
xColor = {1, 1, 0};
}
if (gizmos.locked("transform_gizmo.rotation.y"))
{
checkRotation(rotation, localToWorld.worldPosition(), {0, 1, 0}, window->size(), input, pv, cameraPosition);
yColor = {1, 1, 0};
}
if (gizmos.locked("transform_gizmo.rotation.z"))
{
checkRotation(rotation, localToWorld.worldPosition(), {0, 0, 1}, window->size(), input, pv, cameraPosition);
zColor = {1, 1, 0};
}

gizmos.color(xColor);
gizmos.drawRing("transform_gizmo.rotation.x", localToWorld.worldPosition() + glm::vec3{0.01F, 0, 0},
localToWorld.worldPosition() - glm::vec3{0.01F, 0, 0}, 1.4F, 1.25F);
gizmos.color(yColor);
gizmos.drawArrow("transform_gizmo.y", localToWorld.worldPosition() + glm::vec3{0, 0.03F, 0}, {0, 1, 0}, 0.03F,
0.07F, 0.7F);
gizmos.drawRing("transform_gizmo.rotation.y", localToWorld.worldPosition() + glm::vec3{0, 0.01F, 0},
localToWorld.worldPosition() - glm::vec3{0, 0.01F, 0}, 1.4F, 1.25F);
gizmos.color(zColor);
gizmos.drawArrow("transform_gizmo.z", localToWorld.worldPosition() + glm::vec3{0, 0, 0.03F}, {0, 0, 1}, 0.03F,
0.07F, 0.7F);
gizmos.drawRing("transform_gizmo.rotation.z", localToWorld.worldPosition() + glm::vec3{0, 0, 0.01F},
localToWorld.worldPosition() - glm::vec3{0, 0, 0.01F}, 1.4F, 1.25F);
}

void tesseratos::transformGizmoPlugin(Cubos& cubos)
Expand All @@ -167,7 +243,7 @@ void tesseratos::transformGizmoPlugin(Cubos& cubos)
.tagged("cubos.imgui")
.call([](const EntitySelector& entitySelector, const ActiveCameras& activeCameras, const Window& window,
const Input& input, Gizmos& gizmos, Query<Position&, LocalToWorld&> positionQuery,
Query<const Camera&, LocalToWorld&> cameraQuery) {
Query<Rotation&, LocalToWorld&> rotationQuery, Query<const Camera&, LocalToWorld&> cameraQuery) {
if (entitySelector.selection.isNull())
{
return;
Expand All @@ -185,7 +261,9 @@ void tesseratos::transformGizmoPlugin(Cubos& cubos)
return;
}

drawTransformGizmo(cameraQuery, positionQuery, gizmos, input, window, activeCameras.entities[0],
entitySelector.selection);
drawPositionGizmo(cameraQuery, positionQuery, gizmos, input, window, activeCameras.entities[0],
entitySelector.selection);
drawRotationGizmo(cameraQuery, rotationQuery, gizmos, input, window, activeCameras.entities[0],
entitySelector.selection);
});
}

0 comments on commit ae4fe9e

Please sign in to comment.