Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs

This commit is contained in:
Danilo Aimini
2021-09-28 15:55:39 -07:00
62 changed files with 2089 additions and 941 deletions
@@ -151,6 +151,10 @@ namespace AzToolsFramework
m_ui->m_assetBrowserTableViewWidget, &AssetBrowserTableView::ClearTypeFilter, m_ui->m_searchWidget,
&SearchWidget::ClearTypeFilter);
connect(
this, &AssetPickerDialog::SizeChangedSignal, m_ui->m_assetBrowserTableViewWidget,
&AssetBrowserTableView::UpdateSizeSlot);
m_ui->m_assetBrowserTableViewWidget->SetName("AssetBrowserTableView_main");
m_tableModel->UpdateTableModelMaps();
}
@@ -206,6 +210,12 @@ namespace AzToolsFramework
}
}
void AssetPickerDialog::resizeEvent(QResizeEvent* resizeEvent)
{
emit SizeChangedSignal(m_ui->verticalLayout_4->geometry().width());
QDialog::resizeEvent(resizeEvent);
}
void AssetPickerDialog::keyPressEvent(QKeyEvent* e)
{
// Until search widget is revised, Return key should not close the dialog,
@@ -46,6 +46,9 @@ namespace AzToolsFramework
explicit AssetPickerDialog(AssetSelectionModel& selection, QWidget* parent = nullptr);
virtual ~AssetPickerDialog();
Q_SIGNALS:
void SizeChangedSignal(int newWidth);
protected:
//////////////////////////////////////////////////////////////////////////
// QDialog
@@ -53,6 +56,7 @@ namespace AzToolsFramework
void accept() override;
void reject() override;
void keyPressEvent(QKeyEvent* e) override;
void resizeEvent(QResizeEvent* resizeEvent) override;
private Q_SLOTS:
void DoubleClickedSlot(const QModelIndex& index);
@@ -117,6 +117,9 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="AzToolsFramework::AssetBrowser::AssetBrowserTableView" name="m_assetBrowserTableViewWidget"/>
</item>
<item>
<widget class="AzToolsFramework::AssetBrowser::AssetBrowserTreeView" name="m_assetBrowserTreeViewWidget">
<property name="sizePolicy">
@@ -142,9 +145,6 @@
</property>
</widget>
</item>
<item>
<widget class="AzToolsFramework::AssetBrowser::AssetBrowserTableView" name="m_assetBrowserTableViewWidget"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
@@ -20,13 +20,17 @@ AZ_PUSH_DISABLE_WARNING(
#include <QCoreApplication>
#include <QHeaderView>
#include <QMenu>
#include <QResizeEvent>
#include <QTimer>
AZ_POP_DISABLE_WARNING
namespace AzToolsFramework
{
namespace AssetBrowser
{
const float MinHeaderResizeProportion = .25f;
const float MaxHeaderResizeProportion = .75f;
const float DefaultHeaderResizeProportion = .5f;
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
: AzQtComponents::TableView(parent)
, m_delegate(new SearchEntryDelegate(this))
@@ -65,8 +69,10 @@ namespace AzToolsFramework
AzQtComponents::TableView::setModel(model);
connect(m_tableModel, &AssetBrowserTableModel::layoutChanged, this, &AssetBrowserTableView::layoutChangedSlot);
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
header()->setStretchLastSection(true);
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Interactive);
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Interactive);
UpdateSizeSlot(parentWidget()->width());
header()->setSortIndicatorShown(false);
header()->setSectionsClickable(false);
}
@@ -148,8 +154,17 @@ namespace AzToolsFramework
void AssetBrowserTableView::OnAssetBrowserComponentReady()
{
UpdateSizeSlot(parentWidget()->width());
}
void AssetBrowserTableView::UpdateSizeSlot(int newWidth)
{
setColumnWidth(0, aznumeric_cast<int>(newWidth * DefaultHeaderResizeProportion));
header()->setMinimumSectionSize(aznumeric_cast<int>(newWidth * MinHeaderResizeProportion));
header()->setMaximumSectionSize(aznumeric_cast<int>(newWidth * MaxHeaderResizeProportion));
}
void AssetBrowserTableView::OnContextMenu([[maybe_unused]] const QPoint& point)
{
const auto& selectedAssets = GetSelectedAssets();
@@ -59,12 +59,14 @@ namespace AzToolsFramework
void ClearStringFilter();
void ClearTypeFilter();
public Q_SLOTS:
void UpdateSizeSlot(int newWidth);
protected Q_SLOTS:
void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) override;
void rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) override;
void layoutChangedSlot(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
private:
QString m_name;
QPointer<AssetBrowserTableModel> m_tableModel;
@@ -381,12 +381,22 @@ namespace AzToolsFramework
return;
}
//orphan any children that remain attached to the entity
auto children = entityInfo.GetChildren();
for (auto childId : children)
bool isPrefabSystemEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
// For slices, orphan any children that remain attached to the entity
// For prefabs, this is an unneeded operation because the prefab system handles the orphans
// and the extra reparenting operation can be problematic for consumers subscribed to entity
// events, such as the entity outliner.
if (!isPrefabSystemEnabled)
{
ReparentChild(childId, AZ::EntityId(), entityId);
m_entityOrphanTable[entityId].insert(childId);
auto children = entityInfo.GetChildren();
for (auto childId : children)
{
ReparentChild(childId, AZ::EntityId(), entityId);
m_entityOrphanTable[entityId].insert(childId);
}
}
m_savedOrderInfo[entityId] = AZStd::make_pair(entityInfo.GetParent(), entityInfo.GetIndexForSorting());
@@ -56,5 +56,7 @@ namespace AzToolsFramework
virtual void StopPlayInEditor() = 0;
virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0;
virtual bool IsRootPrefabAssigned() const = 0;
};
}
@@ -79,6 +79,8 @@ namespace AzToolsFramework
void PrefabEditorEntityOwnershipService::Reset()
{
m_isRootPrefabAssigned = false;
if (m_rootInstance)
{
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
@@ -203,6 +205,7 @@ namespace AzToolsFramework
m_rootInstance->SetTemplateSourcePath(m_loaderInterface->GenerateRelativePath(filename));
m_rootInstance->SetContainerEntityName("Level");
m_prefabSystemComponent->PropagateTemplateChanges(templateId);
m_isRootPrefabAssigned = true;
return true;
}
@@ -302,6 +305,12 @@ namespace AzToolsFramework
}
m_prefabSystemComponent->PropagateTemplateChanges(templateId);
m_isRootPrefabAssigned = true;
}
bool PrefabEditorEntityOwnershipService::IsRootPrefabAssigned() const
{
return m_isRootPrefabAssigned;
}
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::CreatePrefab(
@@ -167,6 +167,7 @@ namespace AzToolsFramework
void StopPlayInEditor() override;
void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) override;
bool IsRootPrefabAssigned() const override;
protected:
@@ -215,5 +216,6 @@ namespace AzToolsFramework
Prefab::PrefabLoaderInterface* m_loaderInterface;
AzFramework::EntityContextId m_entityContextId;
AZ::SerializeContext m_serializeContext;
bool m_isRootPrefabAssigned = false;
};
}
@@ -71,6 +71,7 @@ namespace AzToolsFramework
}
m_uniformScaleManipulator->SetVisualOrientationOverride(QuaternionFromTransformNoScaling(localTransform));
m_uniformScaleManipulator->SetLocalPosition(localTransform.GetTranslation());
m_uniformScaleManipulator->SetLocalOrientation(AZ::Quaternion::CreateIdentity());
}
@@ -13,14 +13,14 @@
namespace AzToolsFramework
{
static const float s_surfaceManipulatorTransparency = 0.75f;
static const float s_axisLength = 2.0f;
static const float s_surfaceManipulatorRadius = 0.1f;
static const float SurfaceManipulatorTransparency = 0.75f;
static const float LinearManipulatorAxisLength = 2.0f;
static const float SurfaceManipulatorRadius = 0.1f;
static const AZ::Color s_xAxisColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
static const AZ::Color s_yAxisColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
static const AZ::Color s_zAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f);
static const AZ::Color s_surfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f);
static const AZ::Color LinearManipulatorXAxisColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
static const AZ::Color LinearManipulatorYAxisColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
static const AZ::Color LinearManipulatorZAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f);
static const AZ::Color SurfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f);
TranslationManipulators::TranslationManipulators(
const Dimensions dimensions, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
@@ -291,7 +291,7 @@ namespace AzToolsFramework
{
const AZ::Color color[2] = {
defaultColor,
Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), s_surfaceManipulatorTransparency)
Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), SurfaceManipulatorTransparency)
};
return color[mouseOver];
@@ -325,15 +325,16 @@ namespace AzToolsFramework
void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators)
{
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
translationManipulators->ConfigurePlanarView(s_xAxisColor, s_yAxisColor, s_zAxisColor);
translationManipulators->ConfigureLinearView(s_axisLength, s_xAxisColor, s_yAxisColor, s_zAxisColor);
translationManipulators->ConfigureSurfaceView(s_surfaceManipulatorRadius, s_surfaceManipulatorColor);
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureLinearView(
LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureSurfaceView(SurfaceManipulatorRadius, SurfaceManipulatorColor);
}
void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators)
{
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY());
translationManipulators->ConfigurePlanarView(s_xAxisColor);
translationManipulators->ConfigureLinearView(s_axisLength, s_xAxisColor, s_yAxisColor);
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor);
translationManipulators->ConfigureLinearView(LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor);
}
} // namespace AzToolsFramework
@@ -329,6 +329,11 @@ namespace AzToolsFramework
return AZ::Failure(AZStd::string("Could not instantiate prefab - internal error "
"(PrefabEditorEntityOwnershipInterface unavailable)."));
}
if (!prefabEditorEntityOwnershipInterface->IsRootPrefabAssigned())
{
return AZ::Failure(AZStd::string("Could not instantiate prefab - no root prefab assigned. "
"Currently, prefabs can only be instantiated inside a level"));
}
InstanceOptionalReference instanceToParentUnder;
@@ -82,6 +82,8 @@ namespace AzToolsFramework
, m_entityExpansionState()
, m_entityFilteredState()
{
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
AZ_Assert(m_focusModeInterface != nullptr, "EntityOutlinerListModel requires a FocusModeInterface instance on construction.");
}
EntityOutlinerListModel::~EntityOutlinerListModel()
@@ -106,11 +108,6 @@ namespace AzToolsFramework
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
AZ_Assert(m_editorEntityUiInterface != nullptr,
"EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize.");
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
AZ_Assert(
m_focusModeInterface != nullptr,
"EntityOutlinerListModel requires a FocusModeInterface instance on Initialize.");
}
int EntityOutlinerListModel::rowCount(const QModelIndex& parent) const
@@ -1347,7 +1344,10 @@ namespace AzToolsFramework
//add/remove operations trigger selection change signals which assert and break undo/redo operations in progress in inspector etc.
//so disallow selection updates until change is complete
emit EnableSelectionUpdates(false);
beginResetModel();
auto parentIndex = GetIndexFromEntity(parentId);
auto childIndex = GetIndexFromEntity(childId);
beginRemoveRows(parentIndex, childIndex.row(), childIndex.row());
}
void EntityOutlinerListModel::OnEntityInfoUpdatedRemoveChildEnd(AZ::EntityId parentId, AZ::EntityId childId)
@@ -1355,7 +1355,7 @@ namespace AzToolsFramework
(void)childId;
AZ_PROFILE_FUNCTION(AzToolsFramework);
endResetModel();
endRemoveRows();
//must refresh partial lock/visibility of parents
m_isFilterDirty = true;
@@ -232,6 +232,9 @@ namespace AzToolsFramework
m_gui->m_objectTree->header()->setSortIndicatorShown(false);
m_gui->m_objectTree->header()->setStretchLastSection(false);
// Always expand root entity (level entity) - needed if the widget is re-created while a level is already open.
m_gui->m_objectTree->expand(m_proxyModel->index(0, 0));
// resize the icon columns so that the Visibility and Lock toggle icon columns stay right-justified
m_gui->m_objectTree->header()->setStretchLastSection(false);
m_gui->m_objectTree->header()->setMinimumSectionSize(0);
@@ -700,13 +700,6 @@ namespace AzToolsFramework
switch (referenceFrame)
{
case ReferenceFrame::Local:
// if we have a group selection, always use the pivot override if one
// is set when moving to local space (can't pick individual local space)
if (entityIdMap.size() > 1)
{
pivot.m_worldOrientation = pivotOverrideFrame.m_orientationOverride.value();
}
break;
case ReferenceFrame::Parent:
pivot.m_worldOrientation = pivotOverrideFrame.m_orientationOverride.value();
break;
@@ -784,7 +777,7 @@ namespace AzToolsFramework
SortEntitiesByLocationInHierarchy(sortedEntityIdsOut);
}
static void UpdateInitialRotation(EntityIdManipulators& entityManipulators)
static void UpdateInitialTransform(EntityIdManipulators& entityManipulators)
{
// save new start orientation (if moving rotation axes separate from object
// or switching type of rotation (modifier keys change))
@@ -797,22 +790,17 @@ namespace AzToolsFramework
}
}
// utility function to immediately return the current reference frame
// based on the state of the modifiers
// utility function to immediately return the current reference frame based on the state of the modifiers
static ReferenceFrame ReferenceFrameFromModifiers(const ViewportInteraction::KeyboardModifiers modifiers)
{
if (modifiers.Shift() && !modifiers.Alt())
{
return ReferenceFrame::World;
}
else if (modifiers.Alt() && !modifiers.Shift())
{
return ReferenceFrame::Local;
}
else
{
return ReferenceFrame::Parent;
}
return modifiers.Shift() ? ReferenceFrame::World : ReferenceFrame::Local;
}
// utility function to immediately return the current sphere of influence of the manipulators based on the
// state of the modifiers
static Influence InfluenceFromModifiers(const ViewportInteraction::KeyboardModifiers modifiers)
{
return modifiers.Alt() ? Influence::Individual : Influence::Group;
}
template<typename Action, typename EntityIdContainer>
@@ -838,6 +826,7 @@ namespace AzToolsFramework
else
{
const ReferenceFrame referenceFrame = spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
const Influence influence = InfluenceFromModifiers(action.m_modifiers);
// note: used for parent and world depending on the current reference frame
const auto pivotOrientation =
@@ -854,9 +843,9 @@ namespace AzToolsFramework
const AZ::Vector3 worldTranslation = GetWorldTranslation(entityId);
switch (referenceFrame)
switch (influence)
{
case ReferenceFrame::Local:
case Influence::Individual:
{
// move in each entities local space at once
AZ::Quaternion worldOrientation = AZ::Quaternion::CreateIdentity();
@@ -876,10 +865,9 @@ namespace AzToolsFramework
entityId, entityItLookupIt->second.m_initial.GetTranslation() + localOffset, transformChangedInternally);
}
break;
case ReferenceFrame::Parent:
case ReferenceFrame::World:
case Influence::Group:
{
AZ::Quaternion offsetRotation = pivotOrientation.m_worldOrientation *
const AZ::Quaternion offsetRotation = pivotOrientation.m_worldOrientation *
QuaternionFromTransformNoScaling(entityIdManipulators.m_manipulators->GetLocalTransform().GetInverse());
const AZ::Vector3 localOffset = offsetRotation.TransformVector(action.LocalPositionOffset());
@@ -1062,7 +1050,8 @@ namespace AzToolsFramework
{
AZStd::chrono::milliseconds timeNow;
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::BroadcastResult(
timeNow, &AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Events::EditorViewportInputTimeNow);
timeNow,
&AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Events::EditorViewportInputTimeNow);
return timeNow;
});
}
@@ -1263,7 +1252,7 @@ namespace AzToolsFramework
AZStd::unique_ptr<TranslationManipulators> translationManipulators = AZStd::make_unique<TranslationManipulators>(
TranslationManipulators::Dimensions::Three, AZ::Transform::CreateIdentity(), AZ::Vector3::CreateOne());
translationManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth(ViewportUi::DefaultViewportId));
translationManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth());
InitializeManipulators(*translationManipulators);
@@ -1297,7 +1286,7 @@ namespace AzToolsFramework
ViewportInteraction::KeyboardModifiers prevModifiers{};
translationManipulators->InstallLinearManipulatorMouseMoveCallback(
[this, prevModifiers, manipulatorEntityIds](const LinearManipulator::Action& action) mutable -> void
[this, prevModifiers, manipulatorEntityIds](const LinearManipulator::Action& action) mutable
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
@@ -1331,7 +1320,7 @@ namespace AzToolsFramework
});
translationManipulators->InstallPlanarManipulatorMouseMoveCallback(
[this, prevModifiers, manipulatorEntityIds](const PlanarManipulator::Action& action) mutable -> void
[this, prevModifiers, manipulatorEntityIds](const PlanarManipulator::Action& action) mutable
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
@@ -1364,7 +1353,7 @@ namespace AzToolsFramework
});
translationManipulators->InstallSurfaceManipulatorMouseMoveCallback(
[this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable -> void
[this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
@@ -1391,7 +1380,7 @@ namespace AzToolsFramework
AZStd::unique_ptr<RotationManipulators> rotationManipulators =
AZStd::make_unique<RotationManipulators>(AZ::Transform::CreateIdentity());
rotationManipulators->SetCircleBoundWidth(ManipulatorCicleBoundWidth(ViewportUi::DefaultViewportId));
rotationManipulators->SetCircleBoundWidth(ManipulatorCicleBoundWidth());
InitializeManipulators(*rotationManipulators);
@@ -1415,7 +1404,7 @@ namespace AzToolsFramework
AZStd::shared_ptr<SharedRotationState> sharedRotationState = AZStd::make_shared<SharedRotationState>();
rotationManipulators->InstallLeftMouseDownCallback(
[this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) mutable -> void
[this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) mutable
{
sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity();
sharedRotationState->m_referenceFrameAtMouseDown = m_referenceFrame;
@@ -1437,11 +1426,13 @@ namespace AzToolsFramework
BeginRecordManipulatorCommand();
});
ViewportInteraction::KeyboardModifiers prevModifiers{};
rotationManipulators->InstallMouseMoveCallback(
[this, prevModifiers, sharedRotationState](const AngularManipulator::Action& action) mutable -> void
[this, prevModifiers = ViewportInteraction::KeyboardModifiers(),
sharedRotationState](const AngularManipulator::Action& action) mutable
{
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
const Influence influence = InfluenceFromModifiers(action.m_modifiers);
const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta;
// store the pivot override frame when positioning the manipulator manually (ctrl)
// so we don't lose the orientation when adding/removing entities from the selection
@@ -1452,9 +1443,7 @@ namespace AzToolsFramework
// only update the manipulator orientation if we're rotating in a local reference frame or we're
// manually modifying the manipulator orientation independent of the entity by holding ctrl
if ((sharedRotationState->m_referenceFrameAtMouseDown == ReferenceFrame::Local &&
m_entityIdManipulators.m_lookups.size() == 1) ||
action.m_modifiers.Ctrl())
if (sharedRotationState->m_referenceFrameAtMouseDown == ReferenceFrame::Local || action.m_modifiers.Ctrl())
{
m_entityIdManipulators.m_manipulators->SetLocalTransform(AZ::Transform::CreateFromQuaternionAndTranslation(
manipulatorOrientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation()));
@@ -1463,20 +1452,24 @@ namespace AzToolsFramework
// save state if we change the type of rotation we're doing to to prevent snapping
if (prevModifiers != action.m_modifiers)
{
UpdateInitialRotation(m_entityIdManipulators);
UpdateInitialTransform(m_entityIdManipulators);
sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull();
}
// allow the user to modify the orientation without moving the object if ctrl is held
if (action.m_modifiers.Ctrl())
{
UpdateInitialRotation(m_entityIdManipulators);
UpdateInitialTransform(m_entityIdManipulators);
sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull();
}
else
{
const auto pivotOrientation = ETCS::CalculateSelectionPivotOrientation(
m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, ReferenceFrame::Parent);
// only update the pivot override if the orientation is being modified in local space and we have
// more than one entity selected (so rotating a single entity does not set the orientation override)
if (referenceFrame == ReferenceFrame::Local && sharedRotationState->m_entityIds.size() > 1)
{
m_pivotOverrideFrame.m_orientationOverride = manipulatorOrientation;
}
// note: must use sorted entityIds based on hierarchy order when updating transforms
for (AZ::EntityId entityId : sharedRotationState->m_entityIds)
@@ -1492,9 +1485,9 @@ namespace AzToolsFramework
const AZ::Transform offsetRotation =
AZ::Transform::CreateFromQuaternion(sharedRotationState->m_savedOrientation * action.m_current.m_delta);
switch (referenceFrame)
switch (influence)
{
case ReferenceFrame::Local:
case Influence::Individual:
{
const AZ::Quaternion rotation = entityIdLookupIt->second.m_initial.GetRotation().GetNormalized();
const AZ::Vector3 position = entityIdLookupIt->second.m_initial.GetTranslation();
@@ -1510,23 +1503,10 @@ namespace AzToolsFramework
AZ::Transform::CreateTranslation(-centerOffset) * AZ::Transform::CreateUniformScale(scale));
}
break;
case ReferenceFrame::Parent:
case Influence::Group:
{
const AZ::Transform pivotTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
pivotOrientation.m_worldOrientation,
m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation());
const AZ::Transform transformInPivotSpace =
pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial;
SetEntityWorldTransform(entityId, pivotTransform * offsetRotation * transformInPivotSpace);
}
break;
case ReferenceFrame::World:
{
const AZ::Transform pivotTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateIdentity(),
m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation());
manipulatorOrientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation());
const AZ::Transform transformInPivotSpace =
pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial;
@@ -1561,7 +1541,7 @@ namespace AzToolsFramework
AZ_PROFILE_FUNCTION(AzToolsFramework);
AZStd::unique_ptr<ScaleManipulators> scaleManipulators = AZStd::make_unique<ScaleManipulators>(AZ::Transform::CreateIdentity());
scaleManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth(ViewportUi::DefaultViewportId));
scaleManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth());
InitializeManipulators(*scaleManipulators);
@@ -1571,13 +1551,20 @@ namespace AzToolsFramework
scaleManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
scaleManipulators->ConfigureView(2.0f, AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne());
// lambdas capture shared_ptr by value to increment ref count
auto manipulatorEntityIds = AZStd::make_shared<ManipulatorEntityIds>();
auto uniformLeftMouseDownCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action)
struct SharedScaleState
{
AZ::Vector3 m_savedScaleOffset = AZ::Vector3::CreateZero();
EntityIdList m_entityIds;
};
// lambdas capture shared_ptr by value to increment ref count
auto sharedScaleState = AZStd::make_shared<SharedScaleState>();
auto uniformLeftMouseDownCallback = [this, sharedScaleState]([[maybe_unused]] const LinearManipulator::Action& action)
{
sharedScaleState->m_savedScaleOffset = AZ::Vector3::CreateZero();
// important to sort entityIds based on hierarchy order when updating transforms
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, sharedScaleState->m_entityIds);
for (auto& entityIdLookup : m_entityIdManipulators.m_lookups)
{
@@ -1591,20 +1578,32 @@ namespace AzToolsFramework
m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform());
};
auto uniformLeftMouseUpCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action)
auto uniformLeftMouseUpCallback = [this, sharedScaleState]([[maybe_unused]] const LinearManipulator::Action& action)
{
AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
&AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
manipulatorEntityIds->m_entityIds);
&AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, sharedScaleState->m_entityIds);
m_entityIdManipulators.m_manipulators->SetLocalTransform(RecalculateAverageManipulatorTransform(
m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame));
};
auto uniformLeftMouseMoveCallback = [this, manipulatorEntityIds](const LinearManipulator::Action& action)
auto uniformLeftMouseMoveCallback = [this, sharedScaleState, prevModifiers = ViewportInteraction::KeyboardModifiers()](
const LinearManipulator::Action& action) mutable
{
// do nothing to modify the manipulator
if (action.m_modifiers.Ctrl())
{
return;
}
if (prevModifiers != action.m_modifiers)
{
UpdateInitialTransform(m_entityIdManipulators);
sharedScaleState->m_savedScaleOffset = action.LocalScaleOffset();
}
// note: must use sorted entityIds based on hierarchy order when updating transforms
for (AZ::EntityId entityId : manipulatorEntityIds->m_entityIds)
for (AZ::EntityId entityId : sharedScaleState->m_entityIds)
{
auto entityIdLookupIt = m_entityIdManipulators.m_lookups.find(entityId);
if (entityIdLookupIt == m_entityIdManipulators.m_lookups.end())
@@ -1620,26 +1619,33 @@ namespace AzToolsFramework
return vec.GetX() + vec.GetY() + vec.GetZ();
};
const float uniformScale = action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset());
const float uniformScale =
action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset() - sharedScaleState->m_savedScaleOffset);
const float scale = AZ::GetClamp(1.0f + uniformScale / initialScale, AZ::MinTransformScale, AZ::MaxTransformScale);
const AZ::Transform scaleTransform = AZ::Transform::CreateUniformScale(scale);
if (action.m_modifiers.Alt())
switch (InfluenceFromModifiers(action.m_modifiers))
{
const AZ::Transform pivotTransform = TransformNormalizedScale(entityIdLookupIt->second.m_initial);
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
case Influence::Individual:
{
const AZ::Transform pivotTransform = TransformNormalizedScale(entityIdLookupIt->second.m_initial);
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
}
else
{
const AZ::Transform pivotTransform =
TransformNormalizedScale(m_entityIdManipulators.m_manipulators->GetLocalTransform());
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
}
break;
case Influence::Group:
{
const AZ::Transform pivotTransform =
TransformNormalizedScale(m_entityIdManipulators.m_manipulators->GetLocalTransform());
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
}
}
}
prevModifiers = action.m_modifiers;
};
scaleManipulators->InstallAxisLeftMouseDownCallback(uniformLeftMouseDownCallback);
@@ -2729,8 +2735,7 @@ namespace AzToolsFramework
if (m_pivotOverrideFrame.m_orientationOverride && m_entityIdManipulators.m_manipulators)
{
m_pivotOverrideFrame.m_orientationOverride =
QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform());
m_pivotOverrideFrame.m_orientationOverride = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetRotation();
}
if (m_pivotOverrideFrame.m_translationOverride && m_entityIdManipulators.m_manipulators)
@@ -3337,7 +3342,7 @@ namespace AzToolsFramework
display.SetLineWidth(4.0f);
const auto axisFlip = [&transform, &cameraState](const AZ::Vector3& axis) -> float
const auto axisFlip = [&transform, &cameraState](const AZ::Vector3& axis)
{
return ShouldFlipCameraAxis(
AZ::Transform::CreateIdentity(), transform.GetTranslation(), TransformDirectionNoScaling(transform, axis),
@@ -3554,7 +3559,7 @@ namespace AzToolsFramework
// screen space
const auto calculateGizmoAxis = [&cameraView, &cameraProjection, &screenOffset](const AZ::Vector3& axis)
{
auto result = AZ::Vector2(AzFramework::WorldToScreenNDC(axis, cameraView, cameraProjection));
auto result = AZ::Vector2(AzFramework::WorldToScreenNdc(axis, cameraView, cameraProjection));
result.SetY(1.0f - result.GetY());
return result + screenOffset;
};
@@ -96,6 +96,14 @@ namespace AzToolsFramework
AZ::u8 m_pickTypes = PickType::None; //!< What mode(s) were we in when picking an EntityId override.
};
//! How a manipulator should treat an adjustment.
//! @note Determines if a transform is applied to an individual entity or the whole group.
enum class Influence
{
Group,
Individual
};
//! What frame/space is the manipulator currently operating in.
enum class ReferenceFrame
{
@@ -328,7 +336,8 @@ namespace AzToolsFramework
OptionalFrame m_pivotOverrideFrame; //!< Has a pivot override been set.
Mode m_mode = Mode::Translation; //!< Manipulator mode - default to translation.
Pivot m_pivotMode = Pivot::Object; //!< Entity pivot mode - default to object (authored root).
ReferenceFrame m_referenceFrame = ReferenceFrame::Parent; //!< What reference frame is the Manipulator currently operating in.
ReferenceFrame m_referenceFrame = ReferenceFrame::Local; //!< What reference frame is the Manipulator currently operating in.
Influence m_influence = Influence::Group; //!< What sphere of influence does the Manipulator have.
Frame m_axisPreview; //!< Axes of entity at the time of mouse down to indicate delta of translation.
bool m_triedToRefresh = false; //!< Did a refresh event occur to recalculate the current Manipulator transform.
//! Was EditorTransformComponentSelection responsible for the most recent entity selection change.