Rotate gizmo transform functionality implemented

This commit is contained in:
parax0 2015-08-23 21:02:14 -04:00
parent 04b4f36da9
commit 614f73487e
12 changed files with 460 additions and 103 deletions

View File

@ -28,6 +28,26 @@ void CVector2f::Write(COutputStream &Output)
Output.WriteFloat(y); Output.WriteFloat(y);
} }
float CVector2f::Magnitude() const
{
return sqrtf(SquaredMagnitude());
}
float CVector2f::SquaredMagnitude() const
{
return Dot(*this);
}
CVector2f CVector2f::Normalized() const
{
return *this / Magnitude();
}
float CVector2f::Dot(const CVector2f& other) const
{
return ((x * other.x) + (y * other.y));
}
CVector2f CVector2f::operator+(const CVector2f& src) const CVector2f CVector2f::operator+(const CVector2f& src) const
{ {
CVector2f out; CVector2f out;
@ -142,11 +162,21 @@ bool CVector2f::operator!=(const CVector2f& other) const
return (!(*this == other)); return (!(*this == other));
} }
CVector2f CVector2f::operator-() const
{
return CVector2f(-x, -y);
}
float& CVector2f::operator[](long index) float& CVector2f::operator[](long index)
{ {
return (&x)[index]; return (&x)[index];
} }
const float& CVector2f::operator[](long index) const
{
return (&x)[index];
}
// ************ STATIC MEMBER INITIALIZATION ************ // ************ STATIC MEMBER INITIALIZATION ************
const CVector2f CVector2f::skZero = CVector2f(0, 0); const CVector2f CVector2f::skZero = CVector2f(0, 0);
const CVector2f CVector2f::skOne = CVector2f(1, 1); const CVector2f CVector2f::skOne = CVector2f(1, 1);

View File

@ -14,6 +14,11 @@ public:
CVector2f(CInputStream& Input); CVector2f(CInputStream& Input);
void Write(COutputStream& Output); void Write(COutputStream& Output);
float Magnitude() const;
float SquaredMagnitude() const;
CVector2f Normalized() const;
float Dot(const CVector2f& other) const;
CVector2f operator+(const CVector2f& other) const; CVector2f operator+(const CVector2f& other) const;
CVector2f operator-(const CVector2f& other) const; CVector2f operator-(const CVector2f& other) const;
CVector2f operator*(const CVector2f& other) const; CVector2f operator*(const CVector2f& other) const;
@ -32,7 +37,9 @@ public:
void operator/=(const float other); void operator/=(const float other);
bool operator==(const CVector2f& other) const; bool operator==(const CVector2f& other) const;
bool operator!=(const CVector2f& other) const; bool operator!=(const CVector2f& other) const;
CVector2f operator-() const;
float& operator[](long index); float& operator[](long index);
const float& operator[](long index) const;
// Static Members // Static Members
static const CVector2f skZero; static const CVector2f skZero;

View File

@ -65,7 +65,7 @@ float CVector3f::SquaredMagnitude() const
CVector3f CVector3f::Normalized() const CVector3f CVector3f::Normalized() const
{ {
return *this / Magnitude();; return *this / Magnitude();
} }
float CVector3f::Dot(const CVector3f& other) const float CVector3f::Dot(const CVector3f& other) const

View File

@ -153,7 +153,14 @@ CRay CCamera::CastRay(CVector2f DeviceCoords)
void CCamera::LoadMatrices() void CCamera::LoadMatrices()
{ {
CGraphics::sMVPBlock.ViewMatrix = ViewMatrix(); CGraphics::sMVPBlock.ViewMatrix = ViewMatrix();
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix(); CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
CGraphics::UpdateMVPBlock();
}
void CCamera::LoadRotationOnlyMatrices()
{
CGraphics::sMVPBlock.ViewMatrix = RotationOnlyViewMatrix();
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
} }
@ -187,6 +194,17 @@ const CMatrix4f& CCamera::ViewMatrix()
return mCachedViewMatrix; return mCachedViewMatrix;
} }
const CMatrix4f& CCamera::RotationOnlyViewMatrix()
{
if (mViewOutdated)
CalculateView();
return CMatrix4f(mCachedViewMatrix[0][0], mCachedViewMatrix[0][1], mCachedViewMatrix[0][2], 0.f,
mCachedViewMatrix[1][0], mCachedViewMatrix[1][1], mCachedViewMatrix[1][2], 0.f,
mCachedViewMatrix[2][0], mCachedViewMatrix[2][1], mCachedViewMatrix[2][2], 0.f,
mCachedViewMatrix[3][0], mCachedViewMatrix[3][1], mCachedViewMatrix[3][2], 1.f);
}
const CMatrix4f& CCamera::ProjectionMatrix() const CMatrix4f& CCamera::ProjectionMatrix()
{ {
if (mProjectionOutdated) if (mProjectionOutdated)

View File

@ -45,6 +45,7 @@ public:
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement); void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
CRay CastRay(CVector2f DeviceCoords); CRay CastRay(CVector2f DeviceCoords);
void LoadMatrices(); void LoadMatrices();
void LoadRotationOnlyMatrices();
// Getters // Getters
CVector3f Position() const; CVector3f Position() const;
@ -52,6 +53,7 @@ public:
float GetYaw() const; float GetYaw() const;
float GetPitch() const; float GetPitch() const;
const CMatrix4f& ViewMatrix(); const CMatrix4f& ViewMatrix();
const CMatrix4f& RotationOnlyViewMatrix();
const CMatrix4f& ProjectionMatrix(); const CMatrix4f& ProjectionMatrix();
// Setters // Setters

View File

@ -245,6 +245,9 @@ void CRenderer::RenderBloom()
glBlendFunc(GL_DST_ALPHA, GL_ZERO); glBlendFunc(GL_DST_ALPHA, GL_ZERO);
CDrawUtil::DrawSquare(); CDrawUtil::DrawSquare();
} }
// Clean up
glEnable(GL_DEPTH_TEST);
} }
void CRenderer::RenderSky(CModel *pSkyboxModel, CVector3f CameraPosition) void CRenderer::RenderSky(CModel *pSkyboxModel, CVector3f CameraPosition)

View File

@ -201,7 +201,15 @@ void CSceneNode::Translate(const CVector3f& translation, ETransformSpace transfo
void CSceneNode::Rotate(const CQuaternion& rotation, ETransformSpace transformSpace) void CSceneNode::Rotate(const CQuaternion& rotation, ETransformSpace transformSpace)
{ {
mRotation *= rotation; switch (transformSpace)
{
case eWorldTransform:
mRotation = rotation * mRotation;
break;
case eLocalTransform:
mRotation *= rotation;
break;
}
MarkTransformChanged(); MarkTransformChanged();
} }
@ -370,6 +378,30 @@ void CSceneNode::SetName(const std::string& Name)
mName = Name; mName = Name;
} }
void CSceneNode::SetPosition(const CVector3f& position)
{
mPosition = position;
MarkTransformChanged();
}
void CSceneNode::SetRotation(const CQuaternion& rotation)
{
mRotation = rotation;
MarkTransformChanged();
}
void CSceneNode::SetRotation(const CVector3f& rotEuler)
{
mRotation = CQuaternion::FromEuler(rotEuler);
MarkTransformChanged();
}
void CSceneNode::SetScale(const CVector3f& scale)
{
mScale = scale;
MarkTransformChanged();
}
void CSceneNode::SetMouseHovering(bool Hovering) void CSceneNode::SetMouseHovering(bool Hovering)
{ {
mMouseHovering = Hovering; mMouseHovering = Hovering;

View File

@ -98,6 +98,10 @@ public:
// Setters // Setters
void SetName(const std::string& Name); void SetName(const std::string& Name);
void SetPosition(const CVector3f& position);
void SetRotation(const CQuaternion& rotation);
void SetRotation(const CVector3f& rotEuler);
void SetScale(const CVector3f& scale);
void SetMouseHovering(bool Hovering); void SetMouseHovering(bool Hovering);
void SetSelected(bool Selected); void SetSelected(bool Selected);
void SetVisible(bool Visible); void SetVisible(bool Visible);

View File

@ -3,6 +3,10 @@
#include <Core/CRenderer.h> #include <Core/CRenderer.h>
#include <Core/CResCache.h> #include <Core/CResCache.h>
#include <Core/CDrawUtil.h> #include <Core/CDrawUtil.h>
#include <Core/Log.h>
#include <QApplication>
#include <QDesktopWidget>
#include <iostream> #include <iostream>
CGizmo::CGizmo() CGizmo::CGizmo()
@ -11,8 +15,13 @@ CGizmo::CGizmo()
SetMode(eTranslate); SetMode(eTranslate);
mSelectedAxes = eNone; mSelectedAxes = eNone;
mTransformSpace = eWorldTransform;
mGizmoSize = 1.f; mGizmoSize = 1.f;
mCameraDist = 0.f; mCameraDist = 0.f;
mIsTransforming = false;
mHasTransformed = false;
mWrapOffset = 0.f;
mEnableCursorWrap = true;
mPosition = CVector3f::skZero; mPosition = CVector3f::skZero;
mRotation = CQuaternion::skIdentity; mRotation = CQuaternion::skIdentity;
@ -43,7 +52,8 @@ void CGizmo::AddToRenderer(CRenderer *pRenderer)
CModel *pModel = pPart->pModel; CModel *pModel = pPart->pModel;
// Determine whether to use the mat set for regular (0) or highlight (1) // Determine whether to use the mat set for regular (0) or highlight (1)
bool isHighlighted = (mSelectedAxes & pPart->modelAxes) == pPart->modelAxes; EGizmoAxes partAxes = pPart->modelAxes;
bool isHighlighted = (partAxes != eNone) && ((mSelectedAxes & partAxes) == pPart->modelAxes);
u32 setID = (isHighlighted ? 1 : 0); u32 setID = (isHighlighted ? 1 : 0);
// Add to renderer... // Add to renderer...
@ -58,24 +68,21 @@ void CGizmo::AddToRenderer(CRenderer *pRenderer)
void CGizmo::DrawAsset(ERenderOptions options, u32 asset) void CGizmo::DrawAsset(ERenderOptions options, u32 asset)
{ {
CGraphics::sMVPBlock.ModelMatrix = mTransform.ToMatrix4f();
CGraphics::UpdateMVPBlock();
// Determine which SModelPart array to use // Determine which SModelPart array to use
if (asset >= mNumCurrentParts) return; if (asset >= mNumCurrentParts) return;
SModelPart *pPart = mpCurrentParts; SModelPart *pPart = mpCurrentParts;
// Draw model // Set model matrix
bool isHighlighted = (mSelectedAxes & pPart[asset].modelAxes) == pPart[asset].modelAxes; CGraphics::sMVPBlock.ModelMatrix = (pPart[asset].isBillboard ? mBillboardTransform.ToMatrix4f() : mTransform.ToMatrix4f());
u32 setID = (isHighlighted ? 1 : 0);
pPart[asset].pModel->Draw((ERenderOptions) 0, setID);
}
void CGizmo::DrawRotationOutline()
{
CGraphics::sMVPBlock.ModelMatrix = mBillboardTransform.ToMatrix4f();
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
smRotateClipOutline.pModel->Draw((ERenderOptions) 0, 0);
// Choose material set
EGizmoAxes partAxes = pPart[asset].modelAxes;
bool isHighlighted = (partAxes != eNone) && ((mSelectedAxes & partAxes) == pPart[asset].modelAxes);
u32 setID = (isHighlighted ? 1 : 0);
// Draw model
pPart[asset].pModel->Draw((ERenderOptions) 0, setID);
} }
void CGizmo::IncrementSize() void CGizmo::IncrementSize()
@ -99,15 +106,17 @@ void CGizmo::DecrementSize()
void CGizmo::UpdateForCamera(const CCamera &camera) void CGizmo::UpdateForCamera(const CCamera &camera)
{ {
CVector3f camPos = camera.Position(); CVector3f camPos = camera.Position();
mCameraDist = mPosition.Distance(camPos);
mFlipScaleX = camPos.x < mPosition.x; mFlipScaleX = camPos.x < mPosition.x;
mFlipScaleY = camPos.y < mPosition.y; mFlipScaleY = camPos.y < mPosition.y;
mFlipScaleZ = camPos.z < mPosition.z; mFlipScaleZ = camPos.z < mPosition.z;
if ((!mIsTransforming) || (mMode != eTranslate))
mCameraDist = mPosition.Distance(camPos);
// todo: make this cleaner... // todo: make this cleaner...
CVector3f billDir = (mPosition - camPos).Normalized(); CVector3f billDir = (mPosition - camPos).Normalized();
CVector3f axis = CVector3f::skForward.Cross(billDir); CVector3f axis = CVector3f::skForward.Cross(billDir);
float angle = acos(CVector3f::skForward.Dot(billDir)); float angle = acosf(CVector3f::skForward.Dot(billDir));
angle = 180 + (angle * 180 / 3.14159265358979323846f); angle = 180 + (angle * 180 / 3.14159265358979323846f);
mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis); mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis);
} }
@ -116,6 +125,7 @@ bool CGizmo::CheckSelectedAxes(const CRay &ray)
{ {
// todo: fix raycasting for rotate gizmo; currently it can hit the invisible back side of the model // todo: fix raycasting for rotate gizmo; currently it can hit the invisible back side of the model
CRay localRay = ray.Transformed(mTransform.Inverse()); CRay localRay = ray.Transformed(mTransform.Inverse());
CRay billRay = ray.Transformed(mBillboardTransform.Inverse());
// Do raycast on each model // Do raycast on each model
SModelPart *pPart = mpCurrentParts; SModelPart *pPart = mpCurrentParts;
@ -135,11 +145,12 @@ bool CGizmo::CheckSelectedAxes(const CRay &ray)
} }
CModel *pModel = pPart->pModel; CModel *pModel = pPart->pModel;
CRay& partRay = (pPart->isBillboard ? billRay : localRay);
// Ray/Model AABox test - allow buffer room because lines are small // Ray/Model AABox test - allow buffer room because lines are small
CAABox AABox = pModel->AABox(); CAABox AABox = pModel->AABox();
AABox.ExpandBy(CVector3f::skOne); AABox.ExpandBy(CVector3f::skOne);
bool modelBoxCheck = Math::RayBoxIntersection(localRay, AABox).first; bool modelBoxCheck = Math::RayBoxIntersection(partRay, AABox).first;
if (modelBoxCheck) if (modelBoxCheck)
{ {
@ -150,7 +161,7 @@ bool CGizmo::CheckSelectedAxes(const CRay &ray)
{ {
// Skip surface/box check - since we use lines the boxes might be too small // Skip surface/box check - since we use lines the boxes might be too small
SSurface *pSurf = pModel->GetSurface(iSurf); SSurface *pSurf = pModel->GetSurface(iSurf);
std::pair<bool,float> surfCheck = pSurf->IntersectsRay(localRay, 0.05f); std::pair<bool,float> surfCheck = pSurf->IntersectsRay(partRay, 0.05f);
if (surfCheck.first) if (surfCheck.first)
{ {
@ -186,8 +197,11 @@ bool CGizmo::CheckSelectedAxes(const CRay &ray)
return (a.dist < b.dist); return (a.dist < b.dist);
}); });
CRay& partRay = (pPart->isBillboard ? billRay : localRay);
mSelectedAxes = results.front().pPart->modelAxes; mSelectedAxes = results.front().pPart->modelAxes;
return true; mHitPoint = mTransform * partRay.PointOnRay(results.front().dist);
return (mSelectedAxes != eNone);
} }
u32 CGizmo::NumSelectedAxes() u32 CGizmo::NumSelectedAxes()
@ -207,14 +221,43 @@ void CGizmo::ResetSelectedAxes()
void CGizmo::StartTransform() void CGizmo::StartTransform()
{ {
mIsTransforming = true;
mHasTransformed = false;
mWrapOffset = CVector2f::skZero;
mSetOffset = false; mSetOffset = false;
mTotalTranslation = CVector3f::skZero; mTotalTranslation = CVector3f::skZero;
mTotalRotation = CQuaternion::skIdentity; mTotalRotation = CVector3f::skZero;
mCurrentRotation = CQuaternion::skIdentity;
mTotalScale = CVector3f::skOne; mTotalScale = CVector3f::skOne;
// Set rotation clockwise direction
if (mMode == eRotate)
{
CVector3f axis;
if (mSelectedAxes & eX) axis = mRotation.XAxis();
else if (mSelectedAxes & eY) axis = mRotation.YAxis();
else axis = mRotation.ZAxis();
CVector3f gizmoToHit = (mHitPoint - mPosition).Normalized();
mClockwiseDir = axis.Cross(gizmoToHit);
}
} }
bool CGizmo::TransformFromInput(const CRay& ray, const CCamera& camera) bool CGizmo::TransformFromInput(const CRay& ray, CCamera& camera)
{ {
// Wrap cursor (this has no effect until the next time this function is called)
if (mEnableCursorWrap && (mMode != eTranslate))
WrapCursor();
// Calculate normalized cursor position
QPoint cursorPos = QCursor::pos();
QRect geom = QApplication::desktop()->screenGeometry();
CVector2f mouseCoords(
(((2.f * cursorPos.x()) / geom.width()) - 1.f),
(1.f - ((2.f * cursorPos.y()) / geom.height()))
);
// Translate
if (mMode == eTranslate) if (mMode == eTranslate)
{ {
// Create translate plane // Create translate plane
@ -273,8 +316,16 @@ bool CGizmo::TransformFromInput(const CRay& ray, const CCamera& camera)
else else
{ {
mDeltaTranslation = mRotation.Inverse() * (newPos - mPosition + mTranslateOffset); mDeltaTranslation = mRotation.Inverse() * (newPos - mPosition + mTranslateOffset);
if (!(mSelectedAxes & eX)) mDeltaTranslation.x = 0.f;
if (!(mSelectedAxes & eY)) mDeltaTranslation.y = 0.f;
if (!(mSelectedAxes & eZ)) mDeltaTranslation.z = 0.f;
mTotalTranslation += mDeltaTranslation; mTotalTranslation += mDeltaTranslation;
mPosition = newPos + mTranslateOffset; mPosition += mRotation * mDeltaTranslation;
if (!mHasTransformed && (mDeltaTranslation != CVector3f::skZero))
mHasTransformed = true;
return true; return true;
} }
} }
@ -286,11 +337,62 @@ bool CGizmo::TransformFromInput(const CRay& ray, const CCamera& camera)
} }
} }
// Rotate
else if (mMode == eRotate)
{
// Choose rotation axis
CVector3f axis;
if (mSelectedAxes & eX) axis = CVector3f::skUnitX;
else if (mSelectedAxes & eY) axis = CVector3f::skUnitY;
else axis = CVector3f::skUnitZ;
// Convert hit point + clockwise direction into a line in screen space
// Clockwise direction is set in StartTransform(). Is there a cleaner way to calculate the direction?
CMatrix4f VP = camera.ViewMatrix().Transpose() * camera.ProjectionMatrix().Transpose();
CVector2f lineOrigin = (mHitPoint * VP).xy();
CVector2f lineDir = (((mHitPoint + mClockwiseDir) * VP).xy() - lineOrigin).Normalized();
float rotAmount = lineDir.Dot(mouseCoords + mWrapOffset - lineOrigin) * 180.f;
// Set offset
if (!mSetOffset)
{
mRotateOffset = -rotAmount;
mDeltaRotation = CQuaternion::skIdentity;
mSetOffset = true;
return false;
}
// Apply rotation
rotAmount += mRotateOffset;
CQuaternion oldRot = mCurrentRotation;
mCurrentRotation = CQuaternion::FromAxisAngle(rotAmount, axis);
mDeltaRotation = mCurrentRotation * oldRot.Inverse();
if (mTransformSpace == eLocalTransform)
mRotation *= mDeltaRotation;
// Add to total
if (mSelectedAxes & eX) mTotalRotation.x = rotAmount;
else if (mSelectedAxes & eY) mTotalRotation.y = rotAmount;
else mTotalRotation.z = rotAmount;
if (!mHasTransformed && (rotAmount != 0.f))
mHasTransformed = true;
return true;
}
return false; return false;
} }
void CGizmo::EndTransform() void CGizmo::EndTransform()
{ {
mIsTransforming = false;
}
bool CGizmo::HasTransformed()
{
return mHasTransformed;
} }
CGizmo::EGizmoMode CGizmo::Mode() CGizmo::EGizmoMode CGizmo::Mode()
@ -313,6 +415,36 @@ CVector3f CGizmo::TotalTranslation()
return mTotalTranslation; return mTotalTranslation;
} }
CQuaternion CGizmo::Rotation()
{
return mRotation;
}
CQuaternion CGizmo::DeltaRotation()
{
return mDeltaRotation;
}
CVector3f CGizmo::TotalRotation()
{
return mTotalRotation;
}
CVector3f CGizmo::Scale()
{
return mScale;
}
CVector3f CGizmo::DeltaScale()
{
return mDeltaScale;
}
CVector3f CGizmo::TotalScale()
{
return mTotalScale;
}
void CGizmo::SetMode(EGizmoMode mode) void CGizmo::SetMode(EGizmoMode mode)
{ {
mMode = mode; mMode = mode;
@ -328,7 +460,7 @@ void CGizmo::SetMode(EGizmoMode mode)
case eRotate: case eRotate:
mpCurrentParts = smRotateModels; mpCurrentParts = smRotateModels;
mNumCurrentParts = 4; mNumCurrentParts = 5;
mDeltaTranslation = CVector3f::skZero; mDeltaTranslation = CVector3f::skZero;
mDeltaScale = CVector3f::skOne; mDeltaScale = CVector3f::skOne;
break; break;
@ -342,47 +474,59 @@ void CGizmo::SetMode(EGizmoMode mode)
} }
} }
void CGizmo::SetTransformSpace(ETransformSpace space)
{
mTransformSpace = space;
}
void CGizmo::SetPosition(const CVector3f& position) void CGizmo::SetPosition(const CVector3f& position)
{ {
mPosition = position; mPosition = position;
} }
void CGizmo::SetOrientation(const CQuaternion& orientation) void CGizmo::SetRotation(const CQuaternion& orientation)
{ {
mRotation = orientation; mRotation = orientation;
} }
void CGizmo::EnableCursorWrap(bool wrap)
{
mEnableCursorWrap = wrap;
}
// ************ PRIVATE STATIC ************ // ************ PRIVATE STATIC ************
void CGizmo::LoadModels() void CGizmo::LoadModels()
{ {
if (!smModelsLoaded) if (!smModelsLoaded)
{ {
smTranslateModels[CGIZMO_TRANSLATE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateX.CMDL")); Log::Write("Loading transform gizmo models");
smTranslateModels[CGIZMO_TRANSLATE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_LINES_XY] = SModelPart(eXY, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_LINES_XZ] = SModelPart(eXZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_LINES_YZ] = SModelPart(eYZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesYZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_XY] = SModelPart(eXY, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_XZ] = SModelPart(eXZ, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_YZ] = SModelPart(eYZ, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyYZ.CMDL"));
smRotateModels[CGIZMO_ROTATE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/RotateX.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_X] = SModelPart(eX, true, false, (CModel*) gResCache.GetResource("../resources/editor/TranslateX.CMDL"));
smRotateModels[CGIZMO_ROTATE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/RotateY.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_Y] = SModelPart(eY, true, false, (CModel*) gResCache.GetResource("../resources/editor/TranslateY.CMDL"));
smRotateModels[CGIZMO_ROTATE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/RotateZ.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_Z] = SModelPart(eZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/TranslateZ.CMDL"));
smRotateModels[CGIZMO_ROTATE_XYZ] = SModelPart(eXYZ, false, (CModel*) gResCache.GetResource("../resources/editor/RotateXYZ.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_LINES_XY] = SModelPart(eXY, true, false, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXY.CMDL"));
smRotateClipOutline = SModelPart(eNone, false, (CModel*) gResCache.GetResource("../resources/editor/RotateClipOutline.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_LINES_XZ] = SModelPart(eXZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_LINES_YZ] = SModelPart(eYZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesYZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_XY] = SModelPart(eXY, false, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_XZ] = SModelPart(eXZ, false, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_YZ] = SModelPart(eYZ, false, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleX.CMDL")); smRotateModels[CGIZMO_ROTATE_OUTLINE] = SModelPart(eNone, true, true, (CModel*) gResCache.GetResource("../resources/editor/RotateClipOutline.CMDL"));
smScaleModels[CGIZMO_SCALE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleY.CMDL")); smRotateModels[CGIZMO_ROTATE_X] = SModelPart(eX, true, false, (CModel*) gResCache.GetResource("../resources/editor/RotateX.CMDL"));
smScaleModels[CGIZMO_SCALE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleZ.CMDL")); smRotateModels[CGIZMO_ROTATE_Y] = SModelPart(eY, true, false, (CModel*) gResCache.GetResource("../resources/editor/RotateY.CMDL"));
smScaleModels[CGIZMO_SCALE_LINES_XY] = SModelPart(eXY, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXY.CMDL")); smRotateModels[CGIZMO_ROTATE_Z] = SModelPart(eZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/RotateZ.CMDL"));
smScaleModels[CGIZMO_SCALE_LINES_XZ] = SModelPart(eXZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXZ.CMDL")); smRotateModels[CGIZMO_ROTATE_XYZ] = SModelPart(eXYZ, false, false, (CModel*) gResCache.GetResource("../resources/editor/RotateXYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_LINES_YZ] = SModelPart(eYZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_XY] = SModelPart(eXY, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXY.CMDL")); smScaleModels[CGIZMO_SCALE_X] = SModelPart(eX, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleX.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_XZ] = SModelPart(eXZ, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXZ.CMDL")); smScaleModels[CGIZMO_SCALE_Y] = SModelPart(eY, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleY.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_YZ] = SModelPart(eYZ, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyYZ.CMDL")); smScaleModels[CGIZMO_SCALE_Z] = SModelPart(eZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleZ.CMDL"));
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleXYZ.CMDL")); smScaleModels[CGIZMO_SCALE_LINES_XY] = SModelPart(eXY, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXY.CMDL"));
smScaleModels[CGIZMO_SCALE_LINES_XZ] = SModelPart(eXZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXZ.CMDL"));
smScaleModels[CGIZMO_SCALE_LINES_YZ] = SModelPart(eYZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_XY] = SModelPart(eXY, false, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXY.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_XZ] = SModelPart(eXZ, false, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXZ.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_YZ] = SModelPart(eYZ, false, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleXYZ.CMDL"));
smModelsLoaded = true; smModelsLoaded = true;
} }
@ -395,10 +539,10 @@ void CGizmo::UpdateTransform()
// Rotation and position values are just saved directly // Rotation and position values are just saved directly
mScale = mGizmoSize * (mCameraDist / 10.f); mScale = mGizmoSize * (mCameraDist / 10.f);
// Scale also factors in delta scale + axis flip if mode is Scale. // Scale also factors in total scale + axis flip if mode is Scale.
if (mMode == eScale) if (mMode == eScale)
{ {
mScale *= mDeltaScale; mScale *= mTotalScale;
if (mFlipScaleX) mScale.x = -mScale.x; if (mFlipScaleX) mScale.x = -mScale.x;
if (mFlipScaleY) mScale.y = -mScale.y; if (mFlipScaleY) mScale.y = -mScale.y;
@ -421,9 +565,40 @@ void CGizmo::UpdateTransform()
} }
} }
void CGizmo::WrapCursor()
{
QRect geom = QApplication::desktop()->screenGeometry();
QPoint cursorPos = QCursor::pos();
// Horizontal
if (cursorPos.x() == geom.width() - 1)
{
QCursor::setPos(1, cursorPos.y());
mWrapOffset.x += 2.f;
}
else if (cursorPos.x() == 0)
{
QCursor::setPos(geom.width() - 2, cursorPos.y());
mWrapOffset.x -= 2.f;
}
// Vertical
cursorPos = QCursor::pos(); // Grab again to account for changes on horizontal wrap
if (cursorPos.y() == geom.height() - 1)
{
QCursor::setPos(cursorPos.x(), 1);
mWrapOffset.y -= 2.f;
}
else if (cursorPos.y() == 0)
{
QCursor::setPos(cursorPos.x(), geom.height() - 2);
mWrapOffset.y += 2.f;
}
}
// ************ STATIC MEMBER INITIALIZATION ************ // ************ STATIC MEMBER INITIALIZATION ************
bool CGizmo::smModelsLoaded = false; bool CGizmo::smModelsLoaded = false;
CGizmo::SModelPart CGizmo::smTranslateModels[9]; CGizmo::SModelPart CGizmo::smTranslateModels[9];
CGizmo::SModelPart CGizmo::smRotateModels[4]; CGizmo::SModelPart CGizmo::smRotateModels[5];
CGizmo::SModelPart CGizmo::smScaleModels[10]; CGizmo::SModelPart CGizmo::smScaleModels[10];
CGizmo::SModelPart CGizmo::smRotateClipOutline;

View File

@ -5,6 +5,7 @@
#include <Common/CQuaternion.h> #include <Common/CQuaternion.h>
#include <Common/CVector3f.h> #include <Common/CVector3f.h>
#include <Common/EnumUtil.h> #include <Common/EnumUtil.h>
#include <Common/ETransformSpace.h>
#include <Core/CCamera.h> #include <Core/CCamera.h>
#include <Core/CToken.h> #include <Core/CToken.h>
#include <Core/IRenderable.h> #include <Core/IRenderable.h>
@ -19,10 +20,11 @@
#define CGIZMO_TRANSLATE_POLY_XY 6 #define CGIZMO_TRANSLATE_POLY_XY 6
#define CGIZMO_TRANSLATE_POLY_XZ 7 #define CGIZMO_TRANSLATE_POLY_XZ 7
#define CGIZMO_TRANSLATE_POLY_YZ 8 #define CGIZMO_TRANSLATE_POLY_YZ 8
#define CGIZMO_ROTATE_X 0 #define CGIZMO_ROTATE_OUTLINE 0
#define CGIZMO_ROTATE_Y 1 #define CGIZMO_ROTATE_X 1
#define CGIZMO_ROTATE_Z 2 #define CGIZMO_ROTATE_Y 2
#define CGIZMO_ROTATE_XYZ 3 #define CGIZMO_ROTATE_Z 3
#define CGIZMO_ROTATE_XYZ 4
#define CGIZMO_SCALE_X 0 #define CGIZMO_SCALE_X 0
#define CGIZMO_SCALE_Y 1 #define CGIZMO_SCALE_Y 1
#define CGIZMO_SCALE_Z 2 #define CGIZMO_SCALE_Z 2
@ -57,10 +59,16 @@ public:
private: private:
EGizmoMode mMode; EGizmoMode mMode;
EGizmoAxes mSelectedAxes; EGizmoAxes mSelectedAxes;
ETransformSpace mTransformSpace;
CVector3f mHitPoint;
CTransform4f mBillboardTransform; CTransform4f mBillboardTransform;
CQuaternion mBillboardRotation; CQuaternion mBillboardRotation;
float mGizmoSize; float mGizmoSize;
float mCameraDist; float mCameraDist;
bool mIsTransforming;
bool mHasTransformed;
CVector2f mWrapOffset;
bool mEnableCursorWrap;
CTransform4f mTransform; CTransform4f mTransform;
CVector3f mPosition; CVector3f mPosition;
@ -68,7 +76,8 @@ private:
CVector3f mTotalTranslation; CVector3f mTotalTranslation;
CQuaternion mRotation; CQuaternion mRotation;
CQuaternion mDeltaRotation; CQuaternion mDeltaRotation;
CQuaternion mTotalRotation; CQuaternion mCurrentRotation;
CVector3f mTotalRotation; // This is a CVector3f because this value displays on the UI and a quat would cause rollover
CVector3f mScale; CVector3f mScale;
CVector3f mDeltaScale; CVector3f mDeltaScale;
CVector3f mTotalScale; CVector3f mTotalScale;
@ -77,21 +86,24 @@ private:
bool mFlipScaleZ; bool mFlipScaleZ;
CPlane mTranslatePlane; CPlane mTranslatePlane;
CVector3f mLastTranslatePosition;
CVector3f mTranslateOffset; CVector3f mTranslateOffset;
float mRotateOffset;
bool mSetOffset; bool mSetOffset;
CVector3f mRotateHitPoint;
CVector3f mClockwiseDir;
struct SModelPart struct SModelPart
{ {
EGizmoAxes modelAxes; EGizmoAxes modelAxes;
bool enableRayCast; bool enableRayCast;
bool isBillboard;
CModel *pModel; CModel *pModel;
CToken modelToken; CToken modelToken;
SModelPart() {} SModelPart() {}
SModelPart(EGizmoAxes axes, bool rayCastOn, CModel *_pModel) : SModelPart(EGizmoAxes axes, bool rayCastOn, bool billboard, CModel *_pModel) :
modelAxes(axes), enableRayCast(rayCastOn), pModel(_pModel), modelToken(_pModel) {} modelAxes(axes), enableRayCast(rayCastOn), isBillboard(billboard), pModel(_pModel), modelToken(_pModel) {}
}; };
SModelPart *mpCurrentParts; SModelPart *mpCurrentParts;
u32 mNumCurrentParts; u32 mNumCurrentParts;
@ -99,9 +111,8 @@ private:
// Static // Static
static bool smModelsLoaded; static bool smModelsLoaded;
static SModelPart smTranslateModels[9]; static SModelPart smTranslateModels[9];
static SModelPart smRotateModels[4]; static SModelPart smRotateModels[5];
static SModelPart smScaleModels[10]; static SModelPart smScaleModels[10];
static SModelPart smRotateClipOutline;
public: public:
CGizmo(); CGizmo();
@ -109,7 +120,6 @@ public:
void AddToRenderer(CRenderer *pRenderer); void AddToRenderer(CRenderer *pRenderer);
void DrawAsset(ERenderOptions options, u32 asset); void DrawAsset(ERenderOptions options, u32 asset);
void DrawRotationOutline();
void IncrementSize(); void IncrementSize();
void DecrementSize(); void DecrementSize();
@ -118,20 +128,30 @@ public:
u32 NumSelectedAxes(); u32 NumSelectedAxes();
void ResetSelectedAxes(); void ResetSelectedAxes();
void StartTransform(); void StartTransform();
bool TransformFromInput(const CRay& ray, const CCamera& camera); bool TransformFromInput(const CRay& ray, CCamera& camera);
void EndTransform(); void EndTransform();
bool HasTransformed();
EGizmoMode Mode(); EGizmoMode Mode();
CVector3f Position(); CVector3f Position();
CVector3f DeltaTranslation(); CVector3f DeltaTranslation();
CVector3f TotalTranslation(); CVector3f TotalTranslation();
CQuaternion Rotation();
CQuaternion DeltaRotation();
CVector3f TotalRotation();
CVector3f Scale();
CVector3f DeltaScale();
CVector3f TotalScale();
void SetMode(EGizmoMode mode); void SetMode(EGizmoMode mode);
void SetTransformSpace(ETransformSpace space);
void SetPosition(const CVector3f& position); void SetPosition(const CVector3f& position);
void SetOrientation(const CQuaternion& orientation); void SetRotation(const CQuaternion& orientation);
void EnableCursorWrap(bool wrap);
// Protected // Protected
protected: protected:
void UpdateTransform(); void UpdateTransform();
void WrapCursor();
// Private Static // Private Static
private: private:

View File

@ -35,7 +35,7 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
mShowGizmo = false; mShowGizmo = false;
mGizmoHovering = false; mGizmoHovering = false;
mGizmoTransforming = false; mGizmoTransforming = false;
mUpdateUILater = false; mGizmoUIOutdated = true;
mFrameCount = 0; mFrameCount = 0;
mFPSTimer.Start(); mFPSTimer.Start();
@ -144,15 +144,20 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
ui->InstancesTabContents->SetMaster(pMaster); ui->InstancesTabContents->SetMaster(pMaster);
} }
void CWorldEditor::ViewportRayCast(CRay Ray) void CWorldEditor::ViewportRayCast()
{ {
if (!ui->MainViewport->IsMouseInputActive()) if (!ui->MainViewport->IsMouseInputActive())
{ {
// Cast ray
CVector2f mouseCoords = ui->MainViewport->MouseDeviceCoordinates();
CCamera camera = ui->MainViewport->Camera();
CRay ray = camera.CastRay(mouseCoords);
if (!mGizmoTransforming) if (!mGizmoTransforming)
{ {
// Gizmo hover check // Gizmo hover check
if (mShowGizmo && !mSelectedNodes.empty()) if (mShowGizmo && !mSelectedNodes.empty())
mGizmoHovering = mGizmo.CheckSelectedAxes(Ray); mGizmoHovering = mGizmo.CheckSelectedAxes(ray);
else else
{ {
mGizmoHovering = false; mGizmoHovering = false;
@ -160,7 +165,7 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
} }
// Scene ray check // Scene ray check
SRayIntersection Result = mpSceneManager->SceneRayCast(Ray); SRayIntersection Result = mpSceneManager->SceneRayCast(ray);
if (Result.Hit) if (Result.Hit)
{ {
@ -170,26 +175,44 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
mpHoverNode = Result.pNode; mpHoverNode = Result.pNode;
mpHoverNode->SetMouseHovering(true); mpHoverNode->SetMouseHovering(true);
mHoverPoint = Ray.PointOnRay(Result.Distance); mHoverPoint = ray.PointOnRay(Result.Distance);
} }
else else
ResetHover(); ResetHover();
} }
else else
{ {
bool moved = mGizmo.TransformFromInput(Ray, ui->MainViewport->Camera()); bool transformed = mGizmo.TransformFromInput(ray, ui->MainViewport->Camera());
if (moved) if (transformed)
{ {
CVector3f delta = mGizmo.DeltaTranslation(); switch (mGizmo.Mode())
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
{ {
(*it)->Translate(delta, mTransformSpace); case CGizmo::eTranslate:
(*it)->BuildLightList(this->mpArea); {
CVector3f delta = mGizmo.DeltaTranslation();
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
{
(*it)->Translate(delta, mTransformSpace);
(*it)->BuildLightList(this->mpArea);
}
break;
} }
case CGizmo::eRotate:
{
CQuaternion delta = mGizmo.DeltaRotation();
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
(*it)->Rotate(delta, mTransformSpace);
break;
}
}
RecalculateSelectionBounds(); RecalculateSelectionBounds();
mUpdateUILater = true; mGizmoUIOutdated = true;
} }
} }
} }
@ -293,7 +316,9 @@ void CWorldEditor::ViewportMouseRelease(QMouseEvent *pEvent)
// Gizmo transform stop // Gizmo transform stop
if (mGizmoTransforming) if (mGizmoTransforming)
{ {
mGizmo.EndTransform();
mGizmoTransforming = false; mGizmoTransforming = false;
mGizmoUIOutdated = true;
} }
// Object selection/deselection // Object selection/deselection
@ -346,7 +371,7 @@ void CWorldEditor::ViewportPreRender()
{ {
// Perform raycast // Perform raycast
if (ui->MainViewport->underMouse()) if (ui->MainViewport->underMouse())
ViewportRayCast(ui->MainViewport->CastRay()); ViewportRayCast();
else else
ResetHover(); ResetHover();
@ -373,13 +398,11 @@ void CWorldEditor::ViewportRender(CCamera& Camera)
mpRenderer->ClearDepthBuffer(); mpRenderer->ClearDepthBuffer();
Camera.LoadMatrices(); Camera.LoadMatrices();
if (!mGizmoTransforming) mGizmo.UpdateForCamera(Camera); mGizmo.UpdateForCamera(Camera);
mGizmo.AddToRenderer(mpRenderer); mGizmo.AddToRenderer(mpRenderer);
if (mGizmo.Mode() == CGizmo::eRotate)
mGizmo.DrawRotationOutline();
mpRenderer->RenderBuckets(Camera); mpRenderer->RenderBuckets(Camera);
mpRenderer->ClearDepthBuffer();
} }
mpRenderer->EndFrame(); mpRenderer->EndFrame();
@ -393,11 +416,7 @@ void CWorldEditor::ViewportPostRender()
UpdateCursor(); UpdateCursor();
UpdateStatusBar(); UpdateStatusBar();
if (mUpdateUILater) if (mGizmoUIOutdated) UpdateGizmoUI();
{
UpdateSelectionUI();
mUpdateUILater = false;
}
} }
void CWorldEditor::SetViewportSize(int Width, int Height) void CWorldEditor::SetViewportSize(int Width, int Height)
@ -411,14 +430,16 @@ void CWorldEditor::SetTransformSpace(int space)
{ {
case 0: case 0:
mTransformSpace = eWorldTransform; mTransformSpace = eWorldTransform;
mGizmo.SetOrientation(CQuaternion::skIdentity); mGizmo.SetRotation(CQuaternion::skIdentity);
break; break;
case 1: case 1:
mTransformSpace = eLocalTransform; mTransformSpace = eLocalTransform;
if (!mSelectedNodes.empty()) if (!mSelectedNodes.empty())
mGizmo.SetOrientation(mSelectedNodes.front()->AbsoluteRotation()); mGizmo.SetRotation(mSelectedNodes.front()->AbsoluteRotation());
break; break;
} }
mGizmo.SetTransformSpace(mTransformSpace);
} }
// ************ PRIVATE ************ // ************ PRIVATE ************
@ -491,22 +512,62 @@ void CWorldEditor::UpdateSelectionUI()
SelectionText = Metrics.elidedText(SelectionText, Qt::ElideRight, ui->SelectionInfoFrame->width() - 10); SelectionText = Metrics.elidedText(SelectionText, Qt::ElideRight, ui->SelectionInfoFrame->width() - 10);
ui->SelectionInfoLabel->setText(SelectionText); ui->SelectionInfoLabel->setText(SelectionText);
// Update transform // Update gizmo stuff
CVector3f pos = (!mSelectedNodes.empty() ? mSelectedNodes.front()->AbsolutePosition() : CVector3f::skZero); UpdateGizmoUI();
ui->XSpinBox->setValue(pos.x); }
ui->YSpinBox->setValue(pos.y);
ui->ZSpinBox->setValue(pos.z); void CWorldEditor::UpdateGizmoUI()
{
// Update transform XYZ spin boxes
CVector3f spinBoxValue = CVector3f::skZero;
// If the gizmo is transforming, use the total transform amount
// Otherwise, use the first selected node transform, or 0 if no selection
if (mShowGizmo)
{
switch (mGizmo.Mode())
{
case CGizmo::eTranslate:
if (mGizmoTransforming && mGizmo.HasTransformed())
spinBoxValue = mGizmo.TotalTranslation();
else if (!mSelectedNodes.empty())
spinBoxValue = mSelectedNodes.front()->AbsolutePosition();
break;
case CGizmo::eRotate:
if (mGizmoTransforming && mGizmo.HasTransformed())
spinBoxValue = mGizmo.TotalRotation();
else if (!mSelectedNodes.empty())
spinBoxValue = mSelectedNodes.front()->AbsoluteRotation().ToEuler();
break;
case CGizmo::eScale:
if (mGizmoTransforming && mGizmo.HasTransformed())
spinBoxValue = mGizmo.TotalScale();
else if (!mSelectedNodes.empty())
spinBoxValue = mSelectedNodes.front()->AbsoluteScale();
break;
}
}
else if (!mSelectedNodes.empty()) spinBoxValue = mSelectedNodes.front()->AbsolutePosition();
ui->XSpinBox->setValue(spinBoxValue.x);
ui->YSpinBox->setValue(spinBoxValue.y);
ui->ZSpinBox->setValue(spinBoxValue.z);
// Update gizmo // Update gizmo
if (!mGizmoTransforming) if (!mGizmoTransforming)
{ {
mGizmo.SetPosition(pos); if (!mSelectedNodes.empty())
mGizmo.SetPosition(mSelectedNodes.front()->AbsolutePosition());
if ((mTransformSpace == eLocalTransform) && !mSelectedNodes.empty()) if ((mTransformSpace == eLocalTransform) && !mSelectedNodes.empty())
mGizmo.SetOrientation(mSelectedNodes.front()->AbsoluteRotation()); mGizmo.SetRotation(mSelectedNodes.front()->AbsoluteRotation());
else else
mGizmo.SetOrientation(CQuaternion::skIdentity); mGizmo.SetRotation(CQuaternion::skIdentity);
} }
mGizmoUIOutdated = false;
} }
// ************ ACTIONS ************ // ************ ACTIONS ************
@ -660,6 +721,7 @@ void CWorldEditor::on_ActionEditLayers_triggered()
void CWorldEditor::on_ActionSelectObjects_triggered() void CWorldEditor::on_ActionSelectObjects_triggered()
{ {
mShowGizmo = false; mShowGizmo = false;
mGizmoUIOutdated = true;
ui->ActionSelectObjects->setChecked(true); ui->ActionSelectObjects->setChecked(true);
ui->ActionTranslate->setChecked(false); ui->ActionTranslate->setChecked(false);
ui->ActionRotate->setChecked(false); ui->ActionRotate->setChecked(false);
@ -669,6 +731,7 @@ void CWorldEditor::on_ActionSelectObjects_triggered()
void CWorldEditor::on_ActionTranslate_triggered() void CWorldEditor::on_ActionTranslate_triggered()
{ {
mShowGizmo = true; mShowGizmo = true;
mGizmoUIOutdated = true;
mGizmo.SetMode(CGizmo::eTranslate); mGizmo.SetMode(CGizmo::eTranslate);
ui->ActionSelectObjects->setChecked(false); ui->ActionSelectObjects->setChecked(false);
ui->ActionTranslate->setChecked(true); ui->ActionTranslate->setChecked(true);
@ -679,6 +742,7 @@ void CWorldEditor::on_ActionTranslate_triggered()
void CWorldEditor::on_ActionRotate_triggered() void CWorldEditor::on_ActionRotate_triggered()
{ {
mShowGizmo = true; mShowGizmo = true;
mGizmoUIOutdated = true;
mGizmo.SetMode(CGizmo::eRotate); mGizmo.SetMode(CGizmo::eRotate);
ui->ActionSelectObjects->setChecked(false); ui->ActionSelectObjects->setChecked(false);
ui->ActionTranslate->setChecked(false); ui->ActionTranslate->setChecked(false);
@ -689,6 +753,7 @@ void CWorldEditor::on_ActionRotate_triggered()
void CWorldEditor::on_ActionScale_triggered() void CWorldEditor::on_ActionScale_triggered()
{ {
mShowGizmo = true; mShowGizmo = true;
mGizmoUIOutdated = true;
mGizmo.SetMode(CGizmo::eScale); mGizmo.SetMode(CGizmo::eScale);
ui->ActionSelectObjects->setChecked(false); ui->ActionSelectObjects->setChecked(false);
ui->ActionTranslate->setChecked(false); ui->ActionTranslate->setChecked(false);

View File

@ -37,7 +37,7 @@ class CWorldEditor : public QMainWindow
bool mShowGizmo; bool mShowGizmo;
bool mGizmoHovering; bool mGizmoHovering;
bool mGizmoTransforming; bool mGizmoTransforming;
bool mUpdateUILater; bool mGizmoUIOutdated;
CVector3f mHoverPoint; CVector3f mHoverPoint;
CSceneNode *mpHoverNode; CSceneNode *mpHoverNode;
@ -52,7 +52,7 @@ public:
~CWorldEditor(); ~CWorldEditor();
bool eventFilter(QObject *pObj, QEvent *pEvent); bool eventFilter(QObject *pObj, QEvent *pEvent);
void SetArea(CWorld *pWorld, CGameArea *pArea); void SetArea(CWorld *pWorld, CGameArea *pArea);
void ViewportRayCast(CRay Ray); void ViewportRayCast();
CRenderer* Renderer(); CRenderer* Renderer();
CSceneManager* Scene(); CSceneManager* Scene();
CGameArea* ActiveArea(); CGameArea* ActiveArea();
@ -82,6 +82,7 @@ private:
void OnSidebarResize(); void OnSidebarResize();
void UpdateSelectionUI(); void UpdateSelectionUI();
void UpdateStatusBar(); void UpdateStatusBar();
void UpdateGizmoUI();
private slots: private slots:
void OnCameraSpeedChange(double speed); void OnCameraSpeedChange(double speed);