You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Sandbox/Editor/AlignTool.cpp

147 lines
6.1 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorDefs.h"
#include "AlignTool.h"
// Editor
#include "Objects/BaseObject.h"
#include "Objects/SelectionGroup.h"
//////////////////////////////////////////////////////////////////////////
bool CAlignPickCallback::m_bActive = false;
//////////////////////////////////////////////////////////////////////////
//! Called when object picked.
void CAlignPickCallback::OnPick(CBaseObject* picked)
{
Matrix34 pickedTM(picked->GetWorldTM());
AABB pickedAABB;
picked->GetBoundBox(pickedAABB);
pickedAABB.Move(-pickedTM.GetTranslation());
Vec3 pickedPivot = pickedAABB.GetCenter();
AABB pickedLocalAABB;
picked->GetLocalBounds(pickedLocalAABB);
const Quat& pickedRot = picked->GetRotation();
const Vec3& pickedScale = picked->GetScale();
const Vec3& pickedPos = picked->GetPos();
float fPickedWidth = pickedAABB.max.x - pickedAABB.min.x;
float fPickedHeight = pickedAABB.max.z - pickedAABB.min.z;
float fPickedLength = pickedAABB.max.y - pickedAABB.min.y;
bool bKeepScale = CheckVirtualKey(Qt::Key_Shift);
bool bKeepRotation = CheckVirtualKey(Qt::Key_Alt);
bool bAlignToBoundBox = CheckVirtualKey(Qt::Key_Control);
bool bApplyTransform = !bKeepScale && !bKeepRotation && !bAlignToBoundBox;
{
bool bUndo = !CUndo::IsRecording();
if (bUndo)
{
GetIEditor()->BeginUndo();
}
CSelectionGroup* selGroup = GetIEditor()->GetSelection();
selGroup->FilterParents();
for (int i = 0; i < selGroup->GetFilteredCount(); i++)
{
CBaseObject* pMovedObj = selGroup->GetFilteredObject(i);
if (bKeepScale || bKeepRotation || bApplyTransform)
{
if (bKeepScale && bKeepRotation) // Keep scale and rotation of a moved object
{
pMovedObj->SetWorldTM(Matrix34::Create(pMovedObj->GetScale(), pMovedObj->GetRotation(), pickedPos), eObjectUpdateFlags_UserInput);
}
else if (bKeepScale) // Keep only scale of a moved object
{
pMovedObj->SetWorldTM(Matrix34::Create(pMovedObj->GetScale(), pickedRot, pickedPos), eObjectUpdateFlags_UserInput);
}
else if (bKeepRotation) // Keep only rotation of a moved object
{
pMovedObj->SetWorldTM(Matrix34::Create(pickedScale, pMovedObj->GetRotation(), pickedPos), eObjectUpdateFlags_UserInput);
}
else // Scale, Rotation and Position of a picked object are applied to a moved object.
{
pMovedObj->SetWorldTM(pickedTM, eObjectUpdateFlags_UserInput);
}
}
else if (bAlignToBoundBox) // align to the bounding box.
{
if (pickedLocalAABB.GetVolume() == 0.0f)
{
continue;
}
AABB movedLocalAABB;
pMovedObj->GetLocalBounds(movedLocalAABB);
if (fabs(movedLocalAABB.max.x - movedLocalAABB.min.x) < VEC_EPSILON &&
fabs(movedLocalAABB.max.y - movedLocalAABB.min.y) < VEC_EPSILON &&
fabs(movedLocalAABB.max.z - movedLocalAABB.min.z) < VEC_EPSILON)
{
continue;
}
const Vec3& movedScale(pMovedObj->GetScale());
Matrix34 movedScaleTM = Matrix34::CreateScale(movedScale);
AABB movedLocalScaledAABB;
movedLocalScaledAABB.min = movedScaleTM.TransformVector(movedLocalAABB.min);
movedLocalScaledAABB.max = movedScaleTM.TransformVector(movedLocalAABB.max);
float fMovedWidth = movedLocalScaledAABB.max.x - movedLocalScaledAABB.min.x;
float fMovedHeight = movedLocalScaledAABB.max.z - movedLocalScaledAABB.min.z;
float fMovedLength = movedLocalScaledAABB.max.y - movedLocalScaledAABB.min.y;
Matrix34 pickedScaleTM = Matrix34::CreateScale(picked->GetScale());
AABB pickedLocalScaledAABB;
pickedLocalScaledAABB.min = pickedScaleTM.TransformVector(pickedLocalAABB.min);
pickedLocalScaledAABB.max = pickedScaleTM.TransformVector(pickedLocalAABB.max);
float fScaledPickedtWidth = pickedLocalScaledAABB.max.x - pickedLocalScaledAABB.min.x;
float fScaledPickedHeight = pickedLocalScaledAABB.max.z - pickedLocalScaledAABB.min.z;
float fScaledPickedLength = pickedLocalScaledAABB.max.y - pickedLocalScaledAABB.min.y;
Vec3 scale((fScaledPickedtWidth / fMovedWidth) * movedScale.x, (fScaledPickedLength / fMovedLength) * movedScale.y, (fScaledPickedHeight / fMovedHeight) * movedScale.z);
Matrix34 scaleRotTM = Matrix34::Create(scale, pickedRot, Vec3(0, 0, 0));
Vec3 movedPivot = scaleRotTM.TransformVector(movedLocalAABB.GetCenter());
pMovedObj->SetWorldTM(Matrix34::Create(scale, pickedRot, Vec3(pickedPos + (pickedPivot - movedPivot))), eObjectUpdateFlags_UserInput);
}
}
m_bActive = false;
if (bUndo)
{
GetIEditor()->AcceptUndo("Align To Object");
}
}
delete this;
}
//! Called when pick mode cancelled.
void CAlignPickCallback::OnCancelPick()
{
m_bActive = false;
delete this;
}
//! Return true if specified object is pickable.
bool CAlignPickCallback::OnPickFilter([[maybe_unused]] CBaseObject* filterObject)
{
return true;
};