mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-07-07 05:36:07 +00:00
Scale gizmo transform functionality implemented
This commit is contained in:
parent
8d633553c9
commit
281a605586
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
159
UI/CGizmo.cpp
159
UI/CGizmo.cpp
@ -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,8 +590,11 @@ void CGizmo::SetPosition(const CVector3f& position)
|
|||||||
mPosition = position;
|
mPosition = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGizmo::SetRotation(const CQuaternion& orientation)
|
void CGizmo::SetLocalRotation(const CQuaternion& orientation)
|
||||||
{
|
{
|
||||||
|
mLocalRotation = orientation;
|
||||||
|
|
||||||
|
if (mTransformSpace == eLocalTransform)
|
||||||
mRotation = orientation;
|
mRotation = orientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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()
|
||||||
|
27
UI/CGizmo.h
27
UI/CGizmo.h
@ -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
|
||||||
|
@ -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&)));
|
||||||
@ -199,7 +200,7 @@ void CWorldEditor::ViewportRayCast()
|
|||||||
|
|
||||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||||
{
|
{
|
||||||
(*it)->Translate(delta, mTransformSpace);
|
(*it)->Translate(delta, mTranslateSpace);
|
||||||
(*it)->BuildLightList(this->mpArea);
|
(*it)->BuildLightList(this->mpArea);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -210,7 +211,17 @@ void CWorldEditor::ViewportRayCast()
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CGizmo::eScale:
|
||||||
|
{
|
||||||
|
CVector3f delta = mGizmo.DeltaScale();
|
||||||
|
|
||||||
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||||
|
(*it)->Scale(delta);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -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()
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user