Scale gizmo transform functionality implemented

This commit is contained in:
parax0 2015-08-28 18:57:24 -04:00
parent 8d633553c9
commit 281a605586
8 changed files with 254 additions and 75 deletions

View File

@ -115,9 +115,9 @@ CQuaternion CQuaternion::FromEuler(CVector3f euler)
quat.y = ((c1 * s2 * c3) - (s1 * c2 * s3)); quat.y = ((c1 * s2 * c3) - (s1 * c2 * s3));
quat.z = ((s1 * s2 * c3) + (c1 * c2 * s3));*/ quat.z = ((s1 * s2 * c3) + (c1 * c2 * s3));*/
CQuaternion x = CQuaternion::FromAxisAngle(euler.x, CVector3f(1,0,0)); CQuaternion x = CQuaternion::FromAxisAngle(Math::DegreesToRadians(euler.x), CVector3f(1,0,0));
CQuaternion y = CQuaternion::FromAxisAngle(euler.y, CVector3f(0,1,0)); CQuaternion y = CQuaternion::FromAxisAngle(Math::DegreesToRadians(euler.y), CVector3f(0,1,0));
CQuaternion z = CQuaternion::FromAxisAngle(euler.z, CVector3f(0,0,1)); CQuaternion z = CQuaternion::FromAxisAngle(Math::DegreesToRadians(euler.z), CVector3f(0,0,1));
CQuaternion quat = z * y * x; CQuaternion quat = z * y * x;
return quat; return quat;
@ -127,7 +127,6 @@ CQuaternion CQuaternion::FromAxisAngle(float angle, CVector3f axis)
{ {
CQuaternion quat; CQuaternion quat;
axis = axis.Normalized(); axis = axis.Normalized();
angle = Math::DegreesToRadians(angle);
float sa = sinf(angle / 2); float sa = sinf(angle / 2);
quat.w = cosf(angle / 2); quat.w = cosf(angle / 2);

View File

@ -213,8 +213,9 @@ void CSceneNode::Rotate(const CQuaternion& rotation, ETransformSpace transformSp
MarkTransformChanged(); MarkTransformChanged();
} }
void CSceneNode::Scale(const CVector3f& scale, ETransformSpace transformSpace) void CSceneNode::Scale(const CVector3f& scale)
{ {
// No support for stretch/skew world-space scaling; local only
mScale *= scale; mScale *= scale;
MarkTransformChanged(); MarkTransformChanged();
} }

View File

@ -71,7 +71,7 @@ public:
// Transform // Transform
void Translate(const CVector3f& translation, ETransformSpace transformSpace); void Translate(const CVector3f& translation, ETransformSpace transformSpace);
void Rotate(const CQuaternion& rotation, ETransformSpace transformSpace); void Rotate(const CQuaternion& rotation, ETransformSpace transformSpace);
void Scale(const CVector3f& scale, ETransformSpace transformSpace); void Scale(const CVector3f& scale);
void UpdateTransform(); void UpdateTransform();
void ForceRecalculateTransform(); void ForceRecalculateTransform();
void MarkTransformChanged(); void MarkTransformChanged();

View File

@ -45,7 +45,7 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
{ {
mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel); mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel);
mpVolumePreviewNode->SetInheritance(true, (VolumeShape == 1), false); mpVolumePreviewNode->SetInheritance(true, (VolumeShape == 1), false);
mpVolumePreviewNode->Scale(mpInstance->GetVolume(), eWorldTransform); mpVolumePreviewNode->Scale(mpInstance->GetVolume());
mpVolumePreviewNode->ForceAlphaEnabled(true); mpVolumePreviewNode->ForceAlphaEnabled(true);
} }
} }

View File

@ -25,15 +25,17 @@ CGizmo::CGizmo()
mPosition = CVector3f::skZero; mPosition = CVector3f::skZero;
mRotation = CQuaternion::skIdentity; mRotation = CQuaternion::skIdentity;
mLocalRotation = CQuaternion::skIdentity;
mScale = CVector3f::skOne; mScale = CVector3f::skOne;
mFlipScaleX = false;
mFlipScaleY = false;
mFlipScaleZ = false;
mDeltaTranslation = CVector3f::skZero; mDeltaTranslation = CVector3f::skZero;
mDeltaRotation = CQuaternion::skIdentity; mDeltaRotation = CQuaternion::skIdentity;
mDeltaScale = CVector3f::skOne; mDeltaScale = CVector3f::skOne;
mTotalScale = CVector3f::skOne; mTotalScale = CVector3f::skOne;
mSetOffset = false; mSetOffset = false;
mFlipScaleX = false;
mFlipScaleY = false;
mFlipScaleZ = false;
} }
CGizmo::~CGizmo() CGizmo::~CGizmo()
@ -74,7 +76,13 @@ void CGizmo::DrawAsset(ERenderOptions options, u32 asset)
SModelPart *pPart = mpCurrentParts; SModelPart *pPart = mpCurrentParts;
// Set model matrix // Set model matrix
CGraphics::sMVPBlock.ModelMatrix = (pPart[asset].isBillboard ? mBillboardTransform.ToMatrix4f() : mTransform.ToMatrix4f()); if (pPart[asset].isBillboard)
CGraphics::sMVPBlock.ModelMatrix = mBillboardTransform.ToMatrix4f();
else if ((mMode == eScale) && ((mSelectedAxes & pPart[asset].modelAxes) != 0))
CGraphics::sMVPBlock.ModelMatrix = mScaledTransform.ToMatrix4f();
else
CGraphics::sMVPBlock.ModelMatrix = mTransform.ToMatrix4f();
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
// Choose material set // Choose material set
@ -107,24 +115,23 @@ void CGizmo::DecrementSize()
void CGizmo::UpdateForCamera(const CCamera &camera) void CGizmo::UpdateForCamera(const CCamera &camera)
{ {
CVector3f camPos = camera.Position(); CVector3f camPos = camera.Position();
mFlipScaleX = camPos.x < mPosition.x; CVector3f cameraToGizmo = (mPosition - camPos).Normalized();
mFlipScaleY = camPos.y < mPosition.y; mFlipScaleX = (mRotation.XAxis().Dot(cameraToGizmo) >= 0.f);
mFlipScaleZ = camPos.z < mPosition.z; mFlipScaleY = (mRotation.YAxis().Dot(cameraToGizmo) >= 0.f);
mFlipScaleZ = (mRotation.ZAxis().Dot(cameraToGizmo) >= 0.f);
if ((!mIsTransforming) || (mMode != eTranslate)) if ((!mIsTransforming) || (mMode != eTranslate))
mCameraDist = mPosition.Distance(camPos); mCameraDist = mPosition.Distance(camPos);
// todo: make this cleaner... // todo: make this cleaner...
CVector3f billDir = (mPosition - camPos).Normalized(); CVector3f billDir = (camPos - mPosition).Normalized();
CVector3f axis = CVector3f::skForward.Cross(billDir); CVector3f axis = CVector3f::skForward.Cross(billDir);
float angle = acosf(CVector3f::skForward.Dot(billDir)); float angle = acosf(CVector3f::skForward.Dot(billDir));
angle = 180 + (angle * 180 / 3.14159265358979323846f);
mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis); mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis);
} }
bool CGizmo::CheckSelectedAxes(const CRay &ray) bool CGizmo::CheckSelectedAxes(const CRay &ray)
{ {
// 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()); CRay billRay = ray.Transformed(mBillboardTransform.Inverse());
@ -231,7 +238,7 @@ void CGizmo::StartTransform()
mCurrentRotation = CQuaternion::skIdentity; mCurrentRotation = CQuaternion::skIdentity;
mTotalScale = CVector3f::skOne; mTotalScale = CVector3f::skOne;
// Set rotation clockwise direction // Set rotation direction
if (mMode == eRotate) if (mMode == eRotate)
{ {
CVector3f axis; CVector3f axis;
@ -240,7 +247,31 @@ void CGizmo::StartTransform()
else axis = mRotation.ZAxis(); else axis = mRotation.ZAxis();
CVector3f gizmoToHit = (mHitPoint - mPosition).Normalized(); CVector3f gizmoToHit = (mHitPoint - mPosition).Normalized();
mClockwiseDir = axis.Cross(gizmoToHit); mMoveDir = axis.Cross(gizmoToHit);
}
// Set scale direction
else if (mMode == eScale)
{
// Only need to set scale direction if < 3 axes selected
if (NumSelectedAxes() != 3)
{
// One axis; direction = selected axis
if (NumSelectedAxes() == 1)
{
if (mSelectedAxes & eX) mMoveDir = mRotation.XAxis();
else if (mSelectedAxes & eY) mMoveDir = mRotation.YAxis();
else mMoveDir = mRotation.ZAxis();
}
// Two axes; interpolate between the two selected axes
else if (NumSelectedAxes() == 2)
{
CVector3f axisA = (mSelectedAxes & eX ? mRotation.XAxis() : mRotation.YAxis());
CVector3f axisB = (mSelectedAxes & eZ ? mRotation.ZAxis() : mRotation.YAxis());
mMoveDir = (axisA + axisB) / 2.f;
}
}
} }
} }
@ -347,11 +378,11 @@ bool CGizmo::TransformFromInput(const CRay& ray, CCamera& camera)
else if (mSelectedAxes & eY) axis = CVector3f::skUnitY; else if (mSelectedAxes & eY) axis = CVector3f::skUnitY;
else axis = CVector3f::skUnitZ; else axis = CVector3f::skUnitZ;
// Convert hit point + clockwise direction into a line in screen space // Convert hit point + move direction into a line in screen space
// Clockwise direction is set in StartTransform(). Is there a cleaner way to calculate the direction? // Clockwise direction is set in StartTransform(). Is there a cleaner way to calculate the direction?
CMatrix4f VP = camera.ViewMatrix().Transpose() * camera.ProjectionMatrix().Transpose(); CMatrix4f VP = camera.ViewMatrix().Transpose() * camera.ProjectionMatrix().Transpose();
CVector2f lineOrigin = (mHitPoint * VP).xy(); CVector2f lineOrigin = (mHitPoint * VP).xy();
CVector2f lineDir = (((mHitPoint + mClockwiseDir) * VP).xy() - lineOrigin).Normalized(); CVector2f lineDir = (((mHitPoint + mMoveDir) * VP).xy() - lineOrigin).Normalized();
float rotAmount = lineDir.Dot(mouseCoords + mWrapOffset - lineOrigin) * 180.f; float rotAmount = lineDir.Dot(mouseCoords + mWrapOffset - lineOrigin) * 180.f;
// Set offset // Set offset
@ -366,7 +397,7 @@ bool CGizmo::TransformFromInput(const CRay& ray, CCamera& camera)
// Apply rotation // Apply rotation
rotAmount += mRotateOffset; rotAmount += mRotateOffset;
CQuaternion oldRot = mCurrentRotation; CQuaternion oldRot = mCurrentRotation;
mCurrentRotation = CQuaternion::FromAxisAngle(rotAmount, axis); mCurrentRotation = CQuaternion::FromAxisAngle(Math::DegreesToRadians(rotAmount), axis);
mDeltaRotation = mCurrentRotation * oldRot.Inverse(); mDeltaRotation = mCurrentRotation * oldRot.Inverse();
if (mTransformSpace == eLocalTransform) if (mTransformSpace == eLocalTransform)
@ -383,11 +414,80 @@ bool CGizmo::TransformFromInput(const CRay& ray, CCamera& camera)
return true; return true;
} }
// Scale
else if (mMode == eScale)
{
// Create a line in screen space. First step: line origin
CMatrix4f VP = camera.ViewMatrix().Transpose() * camera.ProjectionMatrix().Transpose();
CVector2f lineOrigin = (mPosition * VP).xy();
// Next step: determine the appropriate world space direction using the selected axes and then convert to screen space
// Since the axes can be flipped while the gizmo is transforming, this has to be done every frame rather than
// pre-saving the world space direction like the rotate gizmo does.
CVector3f dirX = (mFlipScaleX ? -mRotation.XAxis() : mRotation.XAxis());
CVector3f dirY = (mFlipScaleY ? -mRotation.YAxis() : mRotation.YAxis());
CVector3f dirZ = (mFlipScaleZ ? -mRotation.ZAxis() : mRotation.ZAxis());
CVector2f lineDir;
// One axis - world space direction is just the selected axis
if (NumSelectedAxes() == 1)
{
CVector3f worldDir;
if (mSelectedAxes & eX) worldDir = dirX;
else if (mSelectedAxes & eY) worldDir = dirY;
else worldDir = dirZ;
lineDir = (((mPosition + worldDir) * VP).xy() - lineOrigin).Normalized();
}
// Two axes - take the two selected axes and convert them to world space, then average them for the line direction
else if (NumSelectedAxes() == 2)
{
CVector3f axisA = (mSelectedAxes & eX ? dirX : dirY);
CVector3f axisB = (mSelectedAxes & eZ ? dirZ : dirY);
CVector2f screenA = (((mPosition + axisA) * VP).xy() - lineOrigin).Normalized();
CVector2f screenB = (((mPosition + axisB) * VP).xy() - lineOrigin).Normalized();
lineDir = ((screenA + screenB) / 2.f).Normalized();
}
// Three axes - use straight up
else lineDir = CVector2f::skUp;
float scaleAmount = lineDir.Dot(mouseCoords + mWrapOffset - lineOrigin) * 5.f;
// Set offset
if (!mSetOffset)
{
mScaleOffset = -scaleAmount;
mDeltaScale = CVector3f::skOne;
mSetOffset = true;
return false;
}
// Apply scale
scaleAmount = scaleAmount + mScaleOffset + 1.f;
if (scaleAmount < 1.f)
scaleAmount = 1.f / (-(scaleAmount - 1.f) + 1.f);
CVector3f oldScale = mTotalScale;
mTotalScale = CVector3f::skOne;
if (mSelectedAxes & eX) mTotalScale.x = scaleAmount;
if (mSelectedAxes & eY) mTotalScale.y = scaleAmount;
if (mSelectedAxes & eZ) mTotalScale.z = scaleAmount;
mDeltaScale = mTotalScale / oldScale;
if (!mHasTransformed && (scaleAmount != 0.f))
mHasTransformed = true;
return true;
}
return false; return false;
} }
void CGizmo::EndTransform() void CGizmo::EndTransform()
{ {
mTotalScale = CVector3f::skOne;
mIsTransforming = false; mIsTransforming = false;
} }
@ -478,6 +578,11 @@ void CGizmo::SetMode(EGizmoMode mode)
void CGizmo::SetTransformSpace(ETransformSpace space) void CGizmo::SetTransformSpace(ETransformSpace space)
{ {
mTransformSpace = space; mTransformSpace = space;
if (space == eWorldTransform)
mRotation = CQuaternion::skIdentity;
else
mRotation = mLocalRotation;
} }
void CGizmo::SetPosition(const CVector3f& position) void CGizmo::SetPosition(const CVector3f& position)
@ -485,9 +590,12 @@ void CGizmo::SetPosition(const CVector3f& position)
mPosition = position; mPosition = position;
} }
void CGizmo::SetRotation(const CQuaternion& orientation) void CGizmo::SetLocalRotation(const CQuaternion& orientation)
{ {
mRotation = orientation; mLocalRotation = orientation;
if (mTransformSpace == eLocalTransform)
mRotation = orientation;
} }
void CGizmo::EnableCursorWrap(bool wrap) void CGizmo::EnableCursorWrap(bool wrap)
@ -524,9 +632,9 @@ void CGizmo::LoadModels()
smScaleModels[CGIZMO_SCALE_LINES_XY] = SModelPart(eXY, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXY.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_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_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_XY] = SModelPart(eXY, true, 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_XZ] = SModelPart(eXZ, true, 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_POLY_YZ] = SModelPart(eYZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleXYZ.CMDL")); smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, true, false, (CModel*) gResCache.GetResource("../resources/editor/ScaleXYZ.CMDL"));
smModelsLoaded = true; smModelsLoaded = true;
@ -540,11 +648,9 @@ 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 total scale + axis flip if mode is Scale. // Scale also factors in axis flip if mode is Scale.
if (mMode == eScale) if (mMode == eScale)
{ {
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;
if (mFlipScaleZ) mScale.z = -mScale.z; if (mFlipScaleZ) mScale.z = -mScale.z;
@ -564,6 +670,15 @@ void CGizmo::UpdateTransform()
mBillboardTransform.Rotate(mBillboardRotation); mBillboardTransform.Rotate(mBillboardRotation);
mBillboardTransform.Translate(mPosition); mBillboardTransform.Translate(mPosition);
} }
// Create scaled transform for scale gizmo
else if (mMode == eScale)
{
mScaledTransform = CTransform4f::skIdentity;
mScaledTransform.Scale(mScale * mTotalScale);
mScaledTransform.Rotate(mRotation);
mScaledTransform.Translate(mPosition);
}
} }
void CGizmo::WrapCursor() void CGizmo::WrapCursor()

View File

@ -60,8 +60,6 @@ private:
EGizmoMode mMode; EGizmoMode mMode;
EGizmoAxes mSelectedAxes; EGizmoAxes mSelectedAxes;
ETransformSpace mTransformSpace; ETransformSpace mTransformSpace;
CVector3f mHitPoint;
CTransform4f mBillboardTransform;
CQuaternion mBillboardRotation; CQuaternion mBillboardRotation;
float mGizmoSize; float mGizmoSize;
float mCameraDist; float mCameraDist;
@ -71,27 +69,32 @@ private:
bool mEnableCursorWrap; bool mEnableCursorWrap;
CTransform4f mTransform; CTransform4f mTransform;
CTransform4f mBillboardTransform;
CTransform4f mScaledTransform;
CVector3f mPosition; CVector3f mPosition;
CVector3f mDeltaTranslation;
CVector3f mTotalTranslation;
CQuaternion mRotation; CQuaternion mRotation;
CQuaternion mDeltaRotation; CQuaternion mLocalRotation;
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 mTotalScale;
bool mFlipScaleX; bool mFlipScaleX;
bool mFlipScaleY; bool mFlipScaleY;
bool mFlipScaleZ; bool mFlipScaleZ;
CVector3f mDeltaTranslation;
CVector3f mTotalTranslation;
CQuaternion mDeltaRotation;
CQuaternion mCurrentRotation;
CVector3f mTotalRotation; // This is a CVector3f because this value displays on the UI and a quat would cause rollover
CVector3f mDeltaScale;
CVector3f mTotalScale;
CPlane mTranslatePlane; CPlane mTranslatePlane;
CVector3f mTranslateOffset; CVector3f mTranslateOffset;
float mRotateOffset; float mRotateOffset;
float mScaleOffset;
bool mSetOffset; bool mSetOffset;
CVector3f mRotateHitPoint; CVector3f mHitPoint;
CVector3f mClockwiseDir; CVector3f mMoveDir;
struct SModelPart struct SModelPart
{ {
@ -145,7 +148,7 @@ public:
void SetMode(EGizmoMode mode); void SetMode(EGizmoMode mode);
void SetTransformSpace(ETransformSpace space); void SetTransformSpace(ETransformSpace space);
void SetPosition(const CVector3f& position); void SetPosition(const CVector3f& position);
void SetRotation(const CQuaternion& orientation); void SetLocalRotation(const CQuaternion& orientation);
void EnableCursorWrap(bool wrap); void EnableCursorWrap(bool wrap);
// Protected // Protected

View File

@ -61,13 +61,14 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
ui->CamSpeedSpinBox->SetDefaultValue(1.0); ui->CamSpeedSpinBox->SetDefaultValue(1.0);
ResetHover(); ResetHover();
mTransformSpace = eWorldTransform; mTranslateSpace = eWorldTransform;
mRotateSpace = eWorldTransform;
QComboBox *pTransformCombo = new QComboBox(this); mpTransformSpaceComboBox = new QComboBox(this);
pTransformCombo->setMinimumWidth(75); mpTransformSpaceComboBox->setMinimumWidth(75);
pTransformCombo->addItem("World"); mpTransformSpaceComboBox->addItem("World");
pTransformCombo->addItem("Local"); mpTransformSpaceComboBox->addItem("Local");
ui->MainToolBar->insertWidget(0, pTransformCombo); ui->MainToolBar->insertWidget(0, mpTransformSpaceComboBox);
// Initialize offscreen actions // Initialize offscreen actions
addAction(ui->ActionIncrementGizmo); addAction(ui->ActionIncrementGizmo);
@ -76,7 +77,7 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
// Connect signals and slots // Connect signals and slots
connect(ui->TransformSpinBox, SIGNAL(EditingDone(CVector3f)), this, SLOT(OnTransformSpinBoxEdited(CVector3f))); connect(ui->TransformSpinBox, SIGNAL(EditingDone(CVector3f)), this, SLOT(OnTransformSpinBoxEdited(CVector3f)));
connect(ui->TransformSpinBox, SIGNAL(ValueChanged(CVector3f)), this, SLOT(OnTransformSpinBoxModified(CVector3f))); connect(ui->TransformSpinBox, SIGNAL(ValueChanged(CVector3f)), this, SLOT(OnTransformSpinBoxModified(CVector3f)));
connect(pTransformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(SetTransformSpace(int))); connect(mpTransformSpaceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetTransformSpace(int)));
connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double))); connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double)));
connect(ui->MainViewport, SIGNAL(PreRender()), this, SLOT(ViewportPreRender())); connect(ui->MainViewport, SIGNAL(PreRender()), this, SLOT(ViewportPreRender()));
connect(ui->MainViewport, SIGNAL(Render(CCamera&)), this, SLOT(ViewportRender(CCamera&))); connect(ui->MainViewport, SIGNAL(Render(CCamera&)), this, SLOT(ViewportRender(CCamera&)));
@ -193,27 +194,37 @@ void CWorldEditor::ViewportRayCast()
{ {
switch (mGizmo.Mode()) switch (mGizmo.Mode())
{ {
case CGizmo::eTranslate: case CGizmo::eTranslate:
{
CVector3f delta = mGizmo.DeltaTranslation();
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
{ {
(*it)->Translate(delta, mTransformSpace); CVector3f delta = mGizmo.DeltaTranslation();
(*it)->BuildLightList(this->mpArea);
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
{
(*it)->Translate(delta, mTranslateSpace);
(*it)->BuildLightList(this->mpArea);
}
break;
} }
break;
}
case CGizmo::eRotate: case CGizmo::eRotate:
{ {
CQuaternion delta = mGizmo.DeltaRotation(); CQuaternion delta = mGizmo.DeltaRotation();
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++) for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
(*it)->Rotate(delta, mTransformSpace); (*it)->Rotate(delta, mRotateSpace);
break; break;
} }
case CGizmo::eScale:
{
CVector3f delta = mGizmo.DeltaScale();
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
(*it)->Scale(delta);
break;
}
} }
RecalculateSelectionBounds(); RecalculateSelectionBounds();
@ -432,20 +443,23 @@ void CWorldEditor::SetViewportSize(int Width, int Height)
void CWorldEditor::SetTransformSpace(int space) void CWorldEditor::SetTransformSpace(int space)
{ {
if (mGizmo.Mode() == CGizmo::eScale) return;
ETransformSpace& transformSpace = (mGizmo.Mode() == CGizmo::eTranslate ? mTranslateSpace : mRotateSpace);
switch (space) switch (space)
{ {
case 0: case 0:
mTransformSpace = eWorldTransform; transformSpace = eWorldTransform;
mGizmo.SetRotation(CQuaternion::skIdentity); mGizmo.SetLocalRotation(CQuaternion::skIdentity);
break; break;
case 1: case 1:
mTransformSpace = eLocalTransform; transformSpace = eLocalTransform;
if (!mSelectedNodes.empty()) if (!mSelectedNodes.empty())
mGizmo.SetRotation(mSelectedNodes.front()->AbsoluteRotation()); mGizmo.SetLocalRotation(mSelectedNodes.front()->AbsoluteRotation());
break; break;
} }
mGizmo.SetTransformSpace(mTransformSpace); mGizmo.SetTransformSpace(transformSpace);
} }
// ************ PRIVATE ************ // ************ PRIVATE ************
@ -570,10 +584,17 @@ void CWorldEditor::UpdateGizmoUI()
if (!mSelectedNodes.empty()) if (!mSelectedNodes.empty())
mGizmo.SetPosition(mSelectedNodes.front()->AbsolutePosition()); mGizmo.SetPosition(mSelectedNodes.front()->AbsolutePosition());
if ((mTransformSpace == eLocalTransform) && !mSelectedNodes.empty()) // Determine transform space
mGizmo.SetRotation(mSelectedNodes.front()->AbsoluteRotation()); ETransformSpace space;
else if (mGizmo.Mode() == CGizmo::eTranslate) space = mTranslateSpace;
mGizmo.SetRotation(CQuaternion::skIdentity); else if (mGizmo.Mode() == CGizmo::eRotate) space = mRotateSpace;
else space = eLocalTransform;
// Set gizmo transform space
mGizmo.SetTransformSpace(space);
if (!mSelectedNodes.empty())
mGizmo.SetLocalRotation(mSelectedNodes.front()->AbsoluteRotation());
} }
mGizmoUIOutdated = false; mGizmoUIOutdated = false;
@ -764,6 +785,16 @@ void CWorldEditor::on_ActionSelectObjects_triggered()
ui->ActionTranslate->setChecked(false); ui->ActionTranslate->setChecked(false);
ui->ActionRotate->setChecked(false); ui->ActionRotate->setChecked(false);
ui->ActionScale->setChecked(false); ui->ActionScale->setChecked(false);
// Set transform spin box settings
ui->TransformSpinBox->SetSingleStep(0.1);
ui->TransformSpinBox->SetDefaultValue(0.0);
// Set transform space combo box
mpTransformSpaceComboBox->setEnabled(false);
mpTransformSpaceComboBox->blockSignals(true);
mpTransformSpaceComboBox->setCurrentIndex(0);
mpTransformSpaceComboBox->blockSignals(false);
} }
void CWorldEditor::on_ActionTranslate_triggered() void CWorldEditor::on_ActionTranslate_triggered()
@ -771,13 +802,22 @@ void CWorldEditor::on_ActionTranslate_triggered()
mShowGizmo = true; mShowGizmo = true;
mGizmoUIOutdated = true; mGizmoUIOutdated = true;
mGizmo.SetMode(CGizmo::eTranslate); mGizmo.SetMode(CGizmo::eTranslate);
mGizmo.SetTransformSpace(mTranslateSpace);
ui->ActionSelectObjects->setChecked(false); ui->ActionSelectObjects->setChecked(false);
ui->ActionTranslate->setChecked(true); ui->ActionTranslate->setChecked(true);
ui->ActionRotate->setChecked(false); ui->ActionRotate->setChecked(false);
ui->ActionScale->setChecked(false); ui->ActionScale->setChecked(false);
// Set transform spin box settings
ui->TransformSpinBox->SetSingleStep(0.1); ui->TransformSpinBox->SetSingleStep(0.1);
ui->TransformSpinBox->SetDefaultValue(0.0); ui->TransformSpinBox->SetDefaultValue(0.0);
// Set transform space combo box
int index = (mTranslateSpace == eWorldTransform ? 0 : 1);
mpTransformSpaceComboBox->setEnabled(true);
mpTransformSpaceComboBox->blockSignals(true);
mpTransformSpaceComboBox->setCurrentIndex(index);
mpTransformSpaceComboBox->blockSignals(false);
} }
void CWorldEditor::on_ActionRotate_triggered() void CWorldEditor::on_ActionRotate_triggered()
@ -785,13 +825,22 @@ void CWorldEditor::on_ActionRotate_triggered()
mShowGizmo = true; mShowGizmo = true;
mGizmoUIOutdated = true; mGizmoUIOutdated = true;
mGizmo.SetMode(CGizmo::eRotate); mGizmo.SetMode(CGizmo::eRotate);
mGizmo.SetTransformSpace(mRotateSpace);
ui->ActionSelectObjects->setChecked(false); ui->ActionSelectObjects->setChecked(false);
ui->ActionTranslate->setChecked(false); ui->ActionTranslate->setChecked(false);
ui->ActionRotate->setChecked(true); ui->ActionRotate->setChecked(true);
ui->ActionScale->setChecked(false); ui->ActionScale->setChecked(false);
// Set transform spin box settings
ui->TransformSpinBox->SetSingleStep(1.0); ui->TransformSpinBox->SetSingleStep(1.0);
ui->TransformSpinBox->SetDefaultValue(0.0); ui->TransformSpinBox->SetDefaultValue(0.0);
// Set transform space combo box
int index = (mRotateSpace == eWorldTransform ? 0 : 1);
mpTransformSpaceComboBox->setEnabled(true);
mpTransformSpaceComboBox->blockSignals(true);
mpTransformSpaceComboBox->setCurrentIndex(index);
mpTransformSpaceComboBox->blockSignals(false);
} }
void CWorldEditor::on_ActionScale_triggered() void CWorldEditor::on_ActionScale_triggered()
@ -799,13 +848,21 @@ void CWorldEditor::on_ActionScale_triggered()
mShowGizmo = true; mShowGizmo = true;
mGizmoUIOutdated = true; mGizmoUIOutdated = true;
mGizmo.SetMode(CGizmo::eScale); mGizmo.SetMode(CGizmo::eScale);
mGizmo.SetTransformSpace(eLocalTransform);
ui->ActionSelectObjects->setChecked(false); ui->ActionSelectObjects->setChecked(false);
ui->ActionTranslate->setChecked(false); ui->ActionTranslate->setChecked(false);
ui->ActionRotate->setChecked(false); ui->ActionRotate->setChecked(false);
ui->ActionScale->setChecked(true); ui->ActionScale->setChecked(true);
// Set transform spin box settings
ui->TransformSpinBox->SetSingleStep(0.1); ui->TransformSpinBox->SetSingleStep(0.1);
ui->TransformSpinBox->SetDefaultValue(1.0); ui->TransformSpinBox->SetDefaultValue(1.0);
// Set transform space combo box - force to local
mpTransformSpaceComboBox->setEnabled(false);
mpTransformSpaceComboBox->blockSignals(true);
mpTransformSpaceComboBox->setCurrentIndex(1);
mpTransformSpaceComboBox->blockSignals(false);
} }
void CWorldEditor::on_ActionIncrementGizmo_triggered() void CWorldEditor::on_ActionIncrementGizmo_triggered()

View File

@ -3,6 +3,7 @@
#include <QMainWindow> #include <QMainWindow>
#include <QList> #include <QList>
#include <QComboBox>
#include "CGizmo.h" #include "CGizmo.h"
#include <Common/CRay.h> #include <Common/CRay.h>
@ -26,7 +27,8 @@ class CWorldEditor : public QMainWindow
CRenderer *mpRenderer; CRenderer *mpRenderer;
CSceneManager *mpSceneManager; CSceneManager *mpSceneManager;
CGizmo mGizmo; CGizmo mGizmo;
ETransformSpace mTransformSpace; ETransformSpace mTranslateSpace;
ETransformSpace mRotateSpace;
CCamera mCamera; CCamera mCamera;
CGameArea *mpArea; CGameArea *mpArea;
CWorld *mpWorld; CWorld *mpWorld;
@ -44,6 +46,8 @@ class CWorldEditor : public QMainWindow
std::list<CSceneNode*> mSelectedNodes; std::list<CSceneNode*> mSelectedNodes;
CAABox mSelectionAABox; CAABox mSelectionAABox;
QComboBox *mpTransformSpaceComboBox;
CTimer mFPSTimer; CTimer mFPSTimer;
int mFrameCount; int mFrameCount;