Merge branch 'main' of https://github.com/aws-lumberyard/o3de into Spawnable/ScriptCanvas/Integration

This commit is contained in:
sconel
2021-05-26 16:45:23 -07:00
407 changed files with 35045 additions and 3306 deletions
@@ -60,10 +60,20 @@ namespace AzToolsFramework
//! and is generally checked into source control.
virtual const char* GetAbsoluteDevRootFolderPath() = 0;
/// Convert a full source path like "c:\\dev\gamename\\blah\\test.tga" into a relative product path.
/// Convert a full source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative product path.
/// asset paths never mention their alias and are relative to the asset cache root
virtual bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) = 0;
/** Convert a source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative source path, like "blah/test.tga".
* If no valid relative path could be created, the input source path will be returned in relativePath.
* @param sourcePath partial or full path to a source file. (The file doesn't need to exist)
* @param relativePath the output relative path for the source file, if a valid one could be created
* @param rootFilePath the root path that relativePath is relative to
* @return true if a valid relative path was created, false if it wasn't
*/
virtual bool GenerateRelativeSourcePath(
const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& rootFilePath) = 0;
/// Convert a relative asset path like "blah/test.tga" to a full source path path.
/// Once the asset processor has finished building, this function is capable of handling even when the extension changes
/// or when the source is in a different folder or in a different location (such as inside gems)
@@ -0,0 +1,80 @@
/*
* 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.
*
*/
#pragma once
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Math/Color.h>
#include <AzFramework/Viewport/ViewportId.h>
namespace AzToolsFramework
{
//! An interface for loading simple icon assets and rendering them to screen on a per-viewport basis.
class EditorViewportIconDisplayInterface
{
public:
AZ_RTTI(EditorViewportIconDisplayInterface, "{D5190B58-2561-4F3F-B793-F1E7D454CDF2}");
using IconId = AZ::s32;
static constexpr IconId InvalidIconId = -1;
enum class CoordinateSpace : AZ::u8
{
ScreenSpace,
WorldSpace
};
//! These draw parameters control rendering for a single icon to a single viewport.
struct DrawParameters
{
//! The ViewportId to render to.
AzFramework::ViewportId m_viewport = AzFramework::InvalidViewportId;
//! The icon ID, retrieved from GetOrLoadIconForPath, to render to screen.
IconId m_icon = InvalidIconId;
//! The color, including opacity, to render the icon with. White will render the icon as opaque in its original color.
AZ::Color m_color = AZ::Colors::White;
//! The position to render the icon to, in world or screen space depending on m_positionSpace.
AZ::Vector3 m_position;
//! The coordinate system to use for m_position.
//! ScreenSpace will accept m_position in the form of [X, Y, Depth], where X & Y are screen coordinates in
//! pixels and Depth is a z-ordering depth value from 0.0f to 1.0f.
//! WorldSpace will accept a 3D vector in world space coordinates that will be translated back into screen
//! space when the icon is rendered.
CoordinateSpace m_positionSpace = CoordinateSpace::ScreenSpace;
//! The size to render the icon as, in pixels.
AZ::Vector2 m_size;
};
//! The current load status of an icon retrieved by GetOrLoadIconForPath.
enum class IconLoadStatus : AZ::u8
{
Unloaded,
Loading,
Loaded,
Error
};
//! Draws an icon to a viewport given a set of draw parameters.
//! Requires an IconId retrieved from GetOrLoadIconForPath.
virtual void DrawIcon(const DrawParameters& drawParameters) = 0;
//! Retrieves a reusable IconId for an icon at a given path.
//! This will load the icon, if it has not already been loaded.
//! @param path should be a relative asset path to an icon image asset.
//! png and svg icons are currently supported.
virtual IconId GetOrLoadIconForPath(AZStd::string_view path) = 0;
//! Gets the current load status of an icon retrieved via GetOrLoadIconForPath.
virtual IconLoadStatus GetIconLoadStatus(IconId icon) = 0;
};
using EditorViewportIconDisplay = AZ::Interface<EditorViewportIconDisplayInterface>;
} //namespace AzToolsFramework
@@ -239,6 +239,11 @@ namespace AzToolsFramework
*/
virtual int RemoveDirtyEntity(AZ::EntityId target) = 0;
/*!
* Clears the dirty entity set.
*/
virtual void ClearDirtyEntities() = 0;
/*!
* \return true if an undo/redo operation is in progress.
*/
@@ -1354,6 +1354,11 @@ namespace AzToolsFramework
return static_cast<int>(m_dirtyEntities.erase(entityId));
}
void ToolsApplication::ClearDirtyEntities()
{
m_dirtyEntities.clear();
}
void ToolsApplication::UndoPressed()
{
if (m_undoStack)
@@ -85,6 +85,7 @@ namespace AzToolsFramework
void AddDirtyEntity(AZ::EntityId entityId) override;
int RemoveDirtyEntity(AZ::EntityId entityId) override;
void ClearDirtyEntities() override;
bool IsDuringUndoRedo() override { return m_isDuringUndoRedo; }
void UndoPressed() override;
void RedoPressed() override;
@@ -265,6 +265,30 @@ namespace AzToolsFramework
return response.m_resolved;
}
bool AssetSystemComponent::GenerateRelativeSourcePath(
const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& rootFilePath)
{
AzFramework::SocketConnection* engineConnection = AzFramework::SocketConnection::GetInstance();
if (!engineConnection || !engineConnection->IsConnected())
{
relativePath = sourcePath;
return false;
}
AzFramework::AssetSystem::GenerateRelativeSourcePathRequest request(sourcePath);
AzFramework::AssetSystem::GenerateRelativeSourcePathResponse response;
if (!SendRequest(request, response))
{
AZ_Error("Editor", false, "Failed to send GenerateRelativeSourcePath request for %s", sourcePath.c_str());
relativePath = sourcePath;
return false;
}
relativePath = response.m_relativeSourcePath;
rootFilePath = response.m_rootFolder;
return response.m_resolved;
}
bool AssetSystemComponent::GetFullSourcePathFromRelativeProductPath(const AZStd::string& relPath, AZStd::string& fullPath)
{
auto foundIt = m_assetSourceRelativePathToFullPathCache.find(relPath);
@@ -63,6 +63,8 @@ namespace AzToolsFramework
const char* GetAbsoluteDevGameFolderPath() override;
const char* GetAbsoluteDevRootFolderPath() override;
bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& outputPath) override;
bool GenerateRelativeSourcePath(
const AZStd::string& sourcePath, AZStd::string& outputPath, AZStd::string& watchFolder) override;
bool GetFullSourcePathFromRelativeProductPath(const AZStd::string& relPath, AZStd::string& fullPath) override;
bool GetAssetInfoById(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, AZStd::string& rootFilePath) override;
bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override;
@@ -56,5 +56,7 @@ namespace AzToolsFramework
virtual void StartPlayInEditor() = 0;
virtual void StopPlayInEditor() = 0;
virtual void CreateNewLevelPrefab(AZStd::string_view filename) = 0;
};
}
@@ -14,9 +14,11 @@
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Script/ScriptSystemBus.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h>
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
@@ -222,12 +224,11 @@ namespace AzToolsFramework
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
m_rootInstance->SetTemplateSourcePath(relativePath);
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
// This has not been loaded yet, this is the case of being saved with a different name.
// Create it
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({m_rootInstance->m_containerEntity.get()});
HandleEntitiesAdded({ m_rootInstance->m_containerEntity.get() });
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
@@ -236,7 +237,8 @@ namespace AzToolsFramework
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(dom));
templateId = m_prefabSystemComponent->AddTemplate(relativePath, AZStd::move(dom));
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
AZ_Error("Prefab", false, "Couldn't add new template id '%i' when saving file '%.*s'", templateId, AZ_STRING_ARG(filename));
@@ -263,6 +265,71 @@ namespace AzToolsFramework
return false;
}
void PrefabEditorEntityOwnershipService::CreateNewLevelPrefab(AZStd::string_view filename)
{
AZ::IO::Path relativePath = m_loaderInterface->GetRelativePathToProject(filename);
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
m_rootInstance->SetTemplateSourcePath(relativePath);
AZStd::string watchFolder;
AZ::Data::AssetInfo assetInfo;
bool sourceInfoFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, DefaultLevelTemplateName,
assetInfo, watchFolder);
if (sourceInfoFound)
{
AZStd::string fullPath;
AZ::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), fullPath);
// Get the default prefab and copy the Dom over to the new template being saved
Prefab::TemplateId defaultId = m_loaderInterface->LoadTemplateFromFile(fullPath.c_str());
Prefab::PrefabDom& dom = m_prefabSystemComponent->FindTemplateDom(defaultId);
Prefab::PrefabDom levelDefaultDom;
levelDefaultDom.CopyFrom(dom, levelDefaultDom.GetAllocator());
Prefab::PrefabDomPath sourcePath("/Source");
sourcePath.Set(levelDefaultDom, assetInfo.m_relativePath.c_str());
templateId = m_prefabSystemComponent->AddTemplate(relativePath, AZStd::move(levelDefaultDom));
}
else
{
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({ m_rootInstance->m_containerEntity.get() });
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
{
AZ_Error(
"Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(dom));
}
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
AZ_Error("Prefab", false, "Couldn't create new template id '%i' when creating new level '%.*s'", templateId, AZ_STRING_ARG(filename));
return;
}
Prefab::TemplateId prevTemplateId = m_rootInstance->GetTemplateId();
m_rootInstance->SetTemplateId(templateId);
if (prevTemplateId != Prefab::InvalidTemplateId && templateId != prevTemplateId)
{
// Make sure we only have one level template loaded at a time
m_prefabSystemComponent->RemoveTemplate(prevTemplateId);
}
m_prefabSystemComponent->PropagateTemplateChanges(templateId);
}
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::CreatePrefab(
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder)
@@ -170,6 +170,8 @@ namespace AzToolsFramework
void StartPlayInEditor() override;
void StopPlayInEditor() override;
void CreateNewLevelPrefab(AZStd::string_view filename) override;
protected:
AZ::SliceComponent::SliceInstanceAddress GetOwningSlice() override;
@@ -216,5 +218,7 @@ namespace AzToolsFramework
Prefab::PrefabLoaderInterface* m_loaderInterface;
AzFramework::EntityContextId m_entityContextId;
AZ::SerializeContext m_serializeContext;
static inline constexpr const char* DefaultLevelTemplateName = "Prefabs/Default_Level.prefab";
};
}
@@ -82,9 +82,7 @@ namespace AzToolsFramework
m_uniformScaleManipulator->SetVisualOrientationOverride(
QuaternionFromTransformNoScaling(localTransform));
m_uniformScaleManipulator->SetLocalTransform(
AZ::Transform::CreateTranslation(localTransform.GetTranslation()) *
AZ::Transform::CreateScale(localTransform.GetScale()));
m_uniformScaleManipulator->SetLocalOrientation(AZ::Quaternion::CreateIdentity());
}
void ScaleManipulators::SetLocalPositionImpl(const AZ::Vector3& localPosition)
@@ -23,7 +23,7 @@ namespace AzToolsFramework
inline AZ::Transform TransformNormalizedScale(const AZ::Transform& transform)
{
AZ::Transform transformNormalizedScale = transform;
transformNormalizedScale.SetScale(AZ::Vector3::CreateOne());
transformNormalizedScale.SetUniformScale(1.0f);
return transformNormalizedScale;
}
@@ -33,8 +33,7 @@ namespace AzToolsFramework
inline AZ::Transform TransformUniformScale(const AZ::Transform& transform)
{
AZ::Transform transformUniformScale = transform;
const float maxScale = transformUniformScale.GetScale().GetMaxElement();
transformUniformScale.SetScale(AZ::Vector3(maxScale));
transformUniformScale.SetUniformScale(transformUniformScale.GetUniformScale());
return transformUniformScale;
}
@@ -276,18 +276,14 @@ namespace AzToolsFramework
PrefabDomValueReference linkPatchesReference =
PrefabDomUtils::FindPrefabDomValue(linkDom, PrefabDomUtils::PatchesName);
// This logic only covers addition of patches. If patches already exists, the given list of patches must be appended to them.
if (!linkPatchesReference.has_value())
{
/*
If the original allocator the patches were created with gets destroyed, then the patches would become garbage in the
linkDom. Since we cannot guarantee the lifecycle of the patch allocators, we are doing a copy of the patches here to
associate them with the linkDom's allocator.
*/
PrefabDom patchesCopy;
patchesCopy.CopyFrom(patches, linkDom.GetAllocator());
linkDom.AddMember(rapidjson::StringRef(PrefabDomUtils::PatchesName), patchesCopy, linkDom.GetAllocator());
}
/*
If the original allocator the patches were created with gets destroyed, then the patches would become garbage in the
linkDom. Since we cannot guarantee the lifecycle of the patch allocators, we are doing a copy of the patches here to
associate them with the linkDom's allocator.
*/
PrefabDom patchesCopy;
patchesCopy.CopyFrom(patches, linkDom.GetAllocator());
linkDom.AddMember(rapidjson::StringRef(PrefabDomUtils::PatchesName), patchesCopy, linkDom.GetAllocator());
}
}
}
@@ -234,5 +234,10 @@ namespace AzToolsFramework
}
}
PrefabDomValueReference Link::GetLinkPatches()
{
return PrefabDomUtils::FindPrefabDomValue(m_linkDom, PrefabDomUtils::PatchesName);
}
} // namespace Prefab
} // namespace AzToolsFramework
@@ -79,6 +79,8 @@ namespace AzToolsFramework
*/
void AddLinkIdToInstanceDom(PrefabDomValue& instanceDomValue);
PrefabDomValueReference GetLinkPatches();
private:
/**
@@ -41,7 +41,7 @@ namespace AzToolsFramework
[[maybe_unused]] bool result =
settingsRegistry->Get(m_projectPathWithOsSeparator.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
AZ_Assert(result, "Couldn't retrieve project root path");
AZ_Warning("Prefab", result, "Couldn't retrieve project root path");
m_projectPathWithSlashSeparator = AZ::IO::Path(m_projectPathWithOsSeparator.Native(), '/').MakePreferred();
AZ::Interface<PrefabLoaderInterface>::Register(this);
@@ -10,8 +10,6 @@
*
*/
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/JSON/stringbuffer.h>
#include <AzCore/JSON/writer.h>
@@ -28,6 +26,7 @@
#include <AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
#include <AzToolsFramework/Prefab/PrefabUndo.h>
#include <AzToolsFramework/Prefab/PrefabUndoHelpers.h>
@@ -98,9 +97,13 @@ namespace AzToolsFramework
AZStd::string("Could not create a new prefab out of the entities provided - invalid selection."));
}
AZStd::unordered_map<AZ::EntityId, AZStd::string> oldEntityAliases;
// Detach the retrieved entities
for (AZ::Entity* entity : entities)
{
AZ::EntityId entityId = entity->GetId();
oldEntityAliases.emplace(entityId, commonRootEntityOwningInstance->get().GetEntityAlias(entityId)->get());
commonRootEntityOwningInstance->get().DetachEntity(entity->GetId()).release();
}
@@ -110,15 +113,18 @@ namespace AzToolsFramework
{
AZStd::unique_ptr<Instance> outInstance = commonRootEntityOwningInstance->get().DetachNestedInstance(nestedInstance->GetInstanceAlias());
auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstance->GetLinkId());
LinkId detachingInstanceLinkId = nestedInstance->GetLinkId();
auto linkRef = m_prefabSystemComponentInterface->FindLink(detachingInstanceLinkId);
AZ_Assert(linkRef.has_value(), "Unable to find link with id '%llu' during prefab creation.", detachingInstanceLinkId);
if (linkRef.has_value())
{
PrefabDom oldLinkPatches;
oldLinkPatches.CopyFrom(linkRef->get().GetLinkDom(), oldLinkPatches.GetAllocator());
PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches();
AZ_Assert(
linkPatches.has_value(), "Unable to get patches on link with id '%llu' during prefab creation.",
detachingInstanceLinkId);
nestedInstanceLinkPatchesMap.emplace(nestedInstance, AZStd::move(oldLinkPatches));
}
PrefabDom linkPatchesCopy;
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
nestedInstanceLinkPatchesMap.emplace(nestedInstance, AZStd::move(linkPatchesCopy));
RemoveLink(outInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
@@ -182,6 +188,24 @@ namespace AzToolsFramework
if (nestedInstanceLinkPatchesMap.contains(nestedInstance.get()))
{
previousPatch = AZStd::move(nestedInstanceLinkPatchesMap[nestedInstance.get()]);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
previousPatch.Accept(writer);
QString previousPatchString(buffer.GetString());
for (AZ::Entity* entity : entities)
{
AZ::EntityId entityId = entity->GetId();
AZStd::string oldEntityAlias = oldEntityAliases[entityId];
EntityAliasOptionalReference newEntityAlias = instanceToCreate->get().GetEntityAlias(entityId);
AZ_Assert(
newEntityAlias.has_value(),
"Could not fetch entity alias for entity with id '%llu' during prefab creation.",
static_cast<AZ::u64>(entityId));
ReplaceOldAliases(previousPatchString, oldEntityAlias, newEntityAlias->get());
}
previousPatch.Parse(previousPatchString.toUtf8().constData());
}
// These link creations shouldn't be undone because that would put the template in a non-usable state if a user
@@ -203,36 +227,23 @@ namespace AzToolsFramework
m_instanceToTemplateInterface->GeneratePatch(reparentPatch, containerEntityDomBefore, containerEntityDomAfter);
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(reparentPatch, nestedInstanceContainerEntityId);
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes as a separate step
m_prefabUndoCache.Store(nestedInstanceContainerEntityId, AZStd::move(containerEntityDomAfter));
// Save these changes as patches to the link
PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(nestedInstanceContainerEntityId)));
linkUpdate->SetParent(undoBatch.GetUndoBatch());
linkUpdate->Capture(reparentPatch, nestedInstance->GetLinkId());
linkUpdate->Redo();
// We won't parent this undo node to the undo batch so that the newly created template and link will remain
// unaffected by undo actions. This is needed so that any future instantiations of the template will work.
PrefabUndoLinkUpdate linkUpdate = PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(nestedInstanceContainerEntityId)));
linkUpdate.Capture(reparentPatch, nestedInstance->GetLinkId());
linkUpdate.Redo();
}
});
// Create a link between the templates of the newly created instance and the instance it's being parented under.
CreateLink(
instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
AZStd::move(patch));
for (AZ::Entity* topLevelEntity : topLevelEntities)
{
AZ::EntityId topLevelEntityId = topLevelEntity->GetId();
if (topLevelEntityId.IsValid())
{
m_prefabUndoCache.UpdateCache(topLevelEntity->GetId());
// Parenting entities would mark entities as dirty. But we want to unmark the top level entities as dirty because
// if we don't, the template created would be updated and cause issues with undo operation followed by instantiation.
ToolsApplicationRequests::Bus::Broadcast(
&ToolsApplicationRequests::Bus::Events::RemoveDirtyEntity, topLevelEntity->GetId());
}
}
// This clears any entities marked as dirty due to reparenting of entities during the process of creating a prefab.
// We are doing this so that the changes in those enities are not queued up twice for propagation.
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
&AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities);
// Select Container Entity
{
@@ -824,15 +835,7 @@ namespace AzToolsFramework
// This will cover both cases where an alias could be used in a normal entity vs. an instance
for (auto aliasMapIter : oldAliasToNewAliasMap)
{
QString oldAliasQuotes = QString("\"%1\"").arg(aliasMapIter.first.c_str());
QString newAliasQuotes = QString("\"%1\"").arg(aliasMapIter.second.c_str());
newEntityDomString.replace(oldAliasQuotes, newAliasQuotes);
QString oldAliasPathRef = QString("/%1").arg(aliasMapIter.first.c_str());
QString newAliasPathRef = QString("/%1").arg(aliasMapIter.second.c_str());
newEntityDomString.replace(oldAliasPathRef, newAliasPathRef);
ReplaceOldAliases(newEntityDomString, aliasMapIter.first, aliasMapIter.second);
}
// Create the new Entity DOM from parsing the JSON string
@@ -1233,5 +1236,18 @@ namespace AzToolsFramework
return true;
}
void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias)
{
QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data());
QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data());
stringToReplace.replace(oldAliasQuotes, newAliasQuotes);
QString oldAliasPathRef = QString("/%1").arg(oldAlias.data());
QString newAliasPathRef = QString("/%1").arg(newAlias.data());
stringToReplace.replace(oldAliasPathRef, newAliasPathRef);
}
} // namespace Prefab
} // namespace AzToolsFramework
@@ -14,12 +14,15 @@
#include <AzCore/Math/Vector3.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/string/string_view.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
#include <AzToolsFramework/Prefab/PrefabUndoCache.h>
class QString;
namespace AzToolsFramework
{
using EntityList = AZStd::vector<AZ::Entity*>;
@@ -27,7 +30,6 @@ namespace AzToolsFramework
namespace Prefab
{
class Instance;
class InstanceEntityMapperInterface;
class InstanceToTemplateInterface;
class PrefabLoaderInterface;
@@ -130,6 +132,8 @@ namespace AzToolsFramework
bool IsCyclicalDependencyFound(
InstanceOptionalConstReference instance, const AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths);
void ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias);
static Instance* GetParentInstance(Instance* instance);
static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant);
static void GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation);
@@ -1475,10 +1475,8 @@ namespace AzToolsFramework
// to avoid pushing them to the slice.
// Only scale is preserved on the root entity of a slice.
transformComponent->SetParent(AZ::EntityId());
AZ::Vector3 scale = transformComponent->GetLocalScale();
transformComponent->SetWorldTranslation(AZ::Vector3::CreateZero());
transformComponent->SetLocalRotation(AZ::Vector3::CreateZero());
transformComponent->SetLocalScale(scale);
}
}
@@ -17,6 +17,7 @@
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
@@ -313,8 +314,7 @@ namespace AzToolsFramework
// if we do not yet have a valid texture id, request it using the entity icon path
if (m_entityIconTextureId == 0)
{
EditorRequestBus::BroadcastResult(
m_entityIconTextureId, &EditorRequests::GetIconTextureIdFromEntityIconPath, m_entityIconPath);
m_entityIconTextureId = EditorViewportIconDisplay::Get()->GetOrLoadIconForPath(m_entityIconPath);
}
return m_entityIconTextureId;
@@ -357,7 +357,7 @@ namespace AzToolsFramework
AZ::Transform TransformComponent::GetLocalScaleTM() const
{
return AZ::Transform::CreateScale(m_editorTransform.m_scale);
return AZ::Transform::CreateUniformScale(m_editorTransform.m_scale.GetMaxElement());
}
const AZ::Transform& TransformComponent::GetLocalTM()
@@ -677,100 +677,12 @@ namespace AzToolsFramework
return result;
}
void TransformComponent::SetScale(const AZ::Vector3& newScale)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetScale is deprecated, please use SetLocalScale");
AZ::Transform newWorldTransform = GetWorldTM();
AZ::Vector3 prevScale = newWorldTransform.ExtractScale();
if (!prevScale.IsClose(newScale))
{
newWorldTransform.MultiplyByScale(newScale);
SetWorldTM(newWorldTransform);
}
}
void TransformComponent::SetScaleX(float newScale)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetScaleX is deprecated, please use SetLocalScaleX");
AZ::Transform newWorldTransform = GetWorldTM();
AZ::Vector3 scale = newWorldTransform.ExtractScale();
scale.SetX(newScale);
newWorldTransform.MultiplyByScale(scale);
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetScaleY(float newScale)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetScaleY is deprecated, please use SetLocalScaleY");
AZ::Transform newWorldTransform = GetWorldTM();
AZ::Vector3 scale = newWorldTransform.ExtractScale();
scale.SetY(newScale);
newWorldTransform.MultiplyByScale(scale);
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetScaleZ(float newScale)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetScaleZ is deprecated, please use SetLocalScaleZ");
AZ::Transform newWorldTransform = GetWorldTM();
AZ::Vector3 scale = newWorldTransform.ExtractScale();
scale.SetZ(newScale);
newWorldTransform.MultiplyByScale(scale);
SetWorldTM(newWorldTransform);
}
AZ::Vector3 TransformComponent::GetScale()
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetScale is deprecated, please use GetLocalScale");
return GetWorldTM().GetScale();
}
float TransformComponent::GetScaleX()
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetScaleX is deprecated, please use GetLocalScale");
return GetWorldTM().GetScale().GetX();
}
float TransformComponent::GetScaleY()
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetScaleY is deprecated, please use GetLocalScale");
return GetWorldTM().GetScale().GetY();
}
float TransformComponent::GetScaleZ()
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetScaleZ is deprecated, please use GetLocalScale");
return GetWorldTM().GetScale().GetZ();
}
void TransformComponent::SetLocalScale(const AZ::Vector3& scale)
{
m_editorTransform.m_scale = scale;
TransformChanged();
}
void TransformComponent::SetLocalScaleX(float scaleX)
{
m_editorTransform.m_scale.SetX(scaleX);
TransformChanged();
}
void TransformComponent::SetLocalScaleY(float scaleY)
{
m_editorTransform.m_scale.SetY(scaleY);
TransformChanged();
}
void TransformComponent::SetLocalScaleZ(float scaleZ)
{
m_editorTransform.m_scale.SetZ(scaleZ);
TransformChanged();
}
AZ::Vector3 TransformComponent::GetLocalScale()
{
return m_editorTransform.m_scale;
@@ -781,6 +693,22 @@ namespace AzToolsFramework
return GetWorldTM().GetScale();
}
void TransformComponent::SetLocalUniformScale(float scale)
{
m_editorTransform.m_scale = AZ::Vector3(scale);
TransformChanged();
}
float TransformComponent::GetLocalUniformScale()
{
return m_editorTransform.m_scale.GetMaxElement();
}
float TransformComponent::GetWorldUniformScale()
{
return GetWorldTM().GetUniformScale();
}
const AZ::Transform& TransformComponent::GetParentWorldTM() const
{
auto parent = GetParentTransformComponent();
@@ -1183,12 +1111,6 @@ namespace AzToolsFramework
ModifyEditorTransform(m_editorTransform.m_rotate, data, parent);
}
void TransformComponent::ScaleBy(const AZ::Vector3& data)
{
//scale is always local
ModifyEditorTransform(m_editorTransform.m_scale, data, AZ::Transform::Identity());
}
AZ::EntityId TransformComponent::GetSliceEntityParentId()
{
return GetParentId();
@@ -130,24 +130,14 @@ namespace AzToolsFramework
AZ::Quaternion GetLocalRotationQuaternion() override;
// Scale Modifiers
void SetScale(const AZ::Vector3& newScale) override;
void SetScaleX(float newScale) override;
void SetScaleY(float newScale) override;
void SetScaleZ(float newScale) override;
AZ::Vector3 GetScale() override;
float GetScaleX() override;
float GetScaleY() override;
float GetScaleZ() override;
void SetLocalScale(const AZ::Vector3& scale) override;
void SetLocalScaleX(float scaleX) override;
void SetLocalScaleY(float scaleY) override;
void SetLocalScaleZ(float scaleZ) override;
AZ::Vector3 GetLocalScale() override;
AZ::Vector3 GetWorldScale() override;
void SetLocalUniformScale(float scale) override;
float GetLocalUniformScale() override;
float GetWorldUniformScale() override;
AZ::EntityId GetParentId() override;
AZ::TransformInterface* GetParent() override;
void SetParent(AZ::EntityId parentId) override;
@@ -161,7 +151,6 @@ namespace AzToolsFramework
// TransformComponentMessages::Bus
void TranslateBy(const AZ::Vector3&) override;
void RotateBy(const AZ::Vector3&) override; // euler in degrees
void ScaleBy(const AZ::Vector3&) override;
const EditorTransform& GetLocalEditorTransform() override;
void SetLocalEditorTransform(const EditorTransform& dest) override;
bool IsTransformLocked() override;
@@ -65,7 +65,6 @@ namespace AzToolsFramework
virtual void TranslateBy(const AZ::Vector3&) = 0;
virtual void RotateBy(const AZ::Vector3&) = 0;
virtual void ScaleBy(const AZ::Vector3&) = 0;
virtual bool IsTransformLocked() = 0;
};
@@ -83,7 +83,7 @@ namespace AzToolsFramework
protected:
QWidget* GetFirstInTabOrder() override;
QWidget* GetLastInTabOrder() override;
void UpdateTabOrder() override;
void UpdateTabOrder() override;
void onChildComboBoxValueChange(int comboBoxIndex) override;
@@ -93,7 +93,7 @@ namespace AzToolsFramework
void addElementImpl(const AZStd::pair<T, AZStd::string>& genericValue);
QLabel* m_warningLabel = nullptr;
QLabel* m_warningLabel = nullptr;
DHQComboBox* m_pComboBox;
AZStd::vector<AZStd::pair<T, AZStd::string>> m_values;
AZ::AttributeFunction <void(const T&)>* m_postChangeNotifyCB{};
@@ -131,6 +131,11 @@ namespace AzToolsFramework
template<typename T>
AzToolsFramework::PropertyHandlerBase* RegisterGenericComboBoxHandler()
{
if (!AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler())
{
return nullptr;
}
auto propertyHandler = aznew GenericComboBoxHandler<T>();
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, propertyHandler);
return propertyHandler;
@@ -21,6 +21,7 @@
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
AZ_CVAR(
bool, ed_visibility_showAggregateEntitySelectionBounds, false, nullptr, AZ::ConsoleFunctorFlags::Null,
@@ -232,10 +233,14 @@ namespace AzToolsFramework
return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f);
}();
debugDisplay.SetColor(iconHighlight);
// debugDisplay.DrawTextureLabel(
// iconTextureId, entityPosition, iconSize, iconSize,
// /*DisplayContext::ETextureIconFlags::TEXICON_ON_TOP=*/ 0x0008);
EditorViewportIconDisplay::Get()->DrawIcon({
viewportInfo.m_viewportId,
iconTextureId,
iconHighlight,
entityPosition,
EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace,
AZ::Vector2{iconSize, iconSize}
});
}
}
}
@@ -435,7 +435,7 @@ namespace AzToolsFramework
}
}
static void DestroyTransformModeSelectionCluster(const ViewportUi::ClusterId clusterId)
static void DestroyCluster(const ViewportUi::ClusterId clusterId)
{
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId,
@@ -483,6 +483,26 @@ namespace AzToolsFramework
return worldFromLocal.TransformPoint(CalculateCenterOffset(entityId, pivot));
}
void EditorTransformComponentSelection::UpdateSpaceCluster(const ReferenceFrame referenceFrame)
{
auto buttonIdFromFrameFn = [this](const ReferenceFrame referenceFrame) {
switch (referenceFrame)
{
case ReferenceFrame::Local:
return m_spaceCluster.m_localButtonId;
case ReferenceFrame::Parent:
return m_spaceCluster.m_parentButtonId;
case ReferenceFrame::World:
return m_spaceCluster.m_worldButtonId;
}
return m_spaceCluster.m_parentButtonId;
};
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, m_spaceCluster.m_spaceClusterId,
buttonIdFromFrameFn(referenceFrame));
}
namespace ETCS
{
PivotOrientationResult CalculatePivotOrientation(
@@ -789,13 +809,13 @@ namespace AzToolsFramework
EntityIdManipulators& entityIdManipulators,
OptionalFrame& pivotOverrideFrame,
ViewportInteraction::KeyboardModifiers& prevModifiers,
bool& transformChangedInternally)
bool& transformChangedInternally, SpaceCluster spaceCluster)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
entityIdManipulators.m_manipulators->SetLocalPosition(action.LocalPosition());
const ReferenceFrame referenceFrame = ReferenceFrameFromModifiers(action.m_modifiers);
const ReferenceFrame referenceFrame = spaceCluster.m_spaceLock ? spaceCluster.m_currentSpace : ReferenceFrameFromModifiers(action.m_modifiers);
if (action.m_modifiers.Ctrl())
{
@@ -1027,6 +1047,7 @@ namespace AzToolsFramework
EditorManipulatorCommandUndoRedoRequestBus::Handler::BusConnect(entityContextId);
CreateTransformModeSelectionCluster();
CreateSpaceSelectionCluster();
RegisterActions();
SetupBoxSelect();
RefreshSelectedEntityIdsAndRegenerateManipulators();
@@ -1037,7 +1058,9 @@ namespace AzToolsFramework
m_selectedEntityIds.clear();
DestroyManipulators(m_entityIdManipulators);
DestroyTransformModeSelectionCluster(m_transformModeClusterId);
DestroyCluster(m_transformModeClusterId);
DestroyCluster(m_spaceCluster.m_spaceClusterId);
UnregisterActions();
m_pivotOverrideFrame.Reset();
@@ -1274,8 +1297,8 @@ namespace AzToolsFramework
[this, prevModifiers, manipulatorEntityIds](const LinearManipulator::Action& action) mutable -> void
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators,
m_pivotOverrideFrame, prevModifiers, m_transformChangedInternally);
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
m_transformChangedInternally, m_spaceCluster);
});
translationManipulators->InstallLinearManipulatorMouseUpCallback(
@@ -1305,8 +1328,8 @@ namespace AzToolsFramework
[this, prevModifiers, manipulatorEntityIds](const PlanarManipulator::Action& action) mutable -> void
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators,
m_pivotOverrideFrame, prevModifiers, m_transformChangedInternally);
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
m_transformChangedInternally, m_spaceCluster);
});
translationManipulators->InstallPlanarManipulatorMouseUpCallback(
@@ -1335,8 +1358,8 @@ namespace AzToolsFramework
[this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable -> void
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators,
m_pivotOverrideFrame, prevModifiers, m_transformChangedInternally);
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
m_transformChangedInternally, m_spaceCluster);
});
translationManipulators->InstallSurfaceManipulatorMouseUpCallback(
@@ -1414,7 +1437,7 @@ namespace AzToolsFramework
[this, prevModifiers, sharedRotationState]
(const AngularManipulator::Action& action) mutable -> void
{
const ReferenceFrame referenceFrame = ReferenceFrameFromModifiers(action.m_modifiers);
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock ? m_spaceCluster.m_currentSpace : ReferenceFrameFromModifiers(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)
@@ -1474,7 +1497,7 @@ namespace AzToolsFramework
{
const AZ::Quaternion rotation = entityIdLookupIt->second.m_initial.GetRotation().GetNormalized();
const AZ::Vector3 position = entityIdLookupIt->second.m_initial.GetTranslation();
const AZ::Vector3 scale = entityIdLookupIt->second.m_initial.GetScale();
const float scale = entityIdLookupIt->second.m_initial.GetUniformScale();
const AZ::Vector3 centerOffset = CalculateCenterOffset(entityId, m_pivotMode);
@@ -1485,7 +1508,7 @@ namespace AzToolsFramework
AZ::Transform::CreateFromQuaternion(rotation) *
AZ::Transform::CreateTranslation(centerOffset) * offsetRotation *
AZ::Transform::CreateTranslation(-centerOffset) *
AZ::Transform::CreateScale(scale));
AZ::Transform::CreateUniformScale(scale));
}
break;
case ReferenceFrame::Parent:
@@ -1597,16 +1620,15 @@ namespace AzToolsFramework
}
const AZ::Transform initial = entityIdLookupIt->second.m_initial;
const AZ::Vector3 initialScale = initial.GetScale();
const float initialScale = initial.GetUniformScale();
const auto sumVectorElements = [](const AZ::Vector3& vec) {
return vec.GetX() + vec.GetY() + vec.GetZ();
};
const AZ::Vector3 uniformScale = AZ::Vector3(action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset()));
const AZ::Vector3 scale = (AZ::Vector3::CreateOne() +
(uniformScale / initialScale)).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale));
const AZ::Transform scaleTransform = AZ::Transform::CreateScale(scale);
const float uniformScale = action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset());
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())
{
@@ -1872,7 +1894,7 @@ namespace AzToolsFramework
CopyOrientationToSelectedEntitiesGroup(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetScale());
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesGroup(worldFromLocal.GetTranslation());
@@ -1901,7 +1923,7 @@ namespace AzToolsFramework
CopyOrientationToSelectedEntitiesIndividual(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetScale());
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesIndividual(worldFromLocal.GetTranslation());
@@ -2394,7 +2416,7 @@ namespace AzToolsFramework
ResetOrientationForSelectedEntitiesLocal();
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualLocal(AZ::Vector3::CreateOne());
CopyScaleToSelectedEntitiesIndividualLocal(1.0f);
break;
case Mode::Translation:
ResetTranslationForSelectedEntitiesLocal();
@@ -2420,7 +2442,7 @@ namespace AzToolsFramework
ResetOrientationForSelectedEntitiesLocal();
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(AZ::Vector3::CreateOne());
CopyScaleToSelectedEntitiesIndividualWorld(1.0f);
break;
case Mode::Translation:
// do nothing
@@ -2567,6 +2589,67 @@ namespace AzToolsFramework
m_transformModeSelectionHandler);
}
void EditorTransformComponentSelection::CreateSpaceSelectionCluster()
{
// create the cluster for switching spaces/reference frames
ViewportUi::ViewportUiRequestBus::EventResult(
m_spaceCluster.m_spaceClusterId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateCluster,
ViewportUi::Alignment::TopRight);
// create and register the buttons (strings correspond to icons even if the values appear different)
m_spaceCluster.m_worldButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "World");
m_spaceCluster.m_parentButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "Parent");
m_spaceCluster.m_localButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "Local");
auto onButtonClicked = [this](ViewportUi::ButtonId buttonId) {
if (buttonId == m_spaceCluster.m_localButtonId)
{
// Unlock
if (m_spaceCluster.m_spaceLock && m_spaceCluster.m_currentSpace == ReferenceFrame::Local)
{
m_spaceCluster.m_spaceLock = false;
}
else
{
m_spaceCluster.m_spaceLock = true;
m_spaceCluster.m_currentSpace = ReferenceFrame::Local;
}
}
else if (buttonId == m_spaceCluster.m_parentButtonId)
{
// Unlock
if (m_spaceCluster.m_spaceLock && m_spaceCluster.m_currentSpace == ReferenceFrame::Parent)
{
m_spaceCluster.m_spaceLock = false;
}
else
{
m_spaceCluster.m_spaceLock = true;
m_spaceCluster.m_currentSpace = ReferenceFrame::Parent;
}
}
else if (buttonId == m_spaceCluster.m_worldButtonId)
{
// Unlock
if (m_spaceCluster.m_spaceLock && m_spaceCluster.m_currentSpace == ReferenceFrame::World)
{
m_spaceCluster.m_spaceLock = false;
}
else
{
m_spaceCluster.m_spaceLock = true;
m_spaceCluster.m_currentSpace = ReferenceFrame::World;
}
}
};
m_spaceCluster.m_spaceSelectionHandler = AZ::Event<ViewportUi::ButtonId>::Handler(onButtonClicked);
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler,
m_spaceCluster.m_spaceClusterId, m_spaceCluster.m_spaceSelectionHandler);
}
EditorTransformComponentSelectionRequests::Mode EditorTransformComponentSelection::GetTransformMode()
{
return m_mode;
@@ -2940,7 +3023,7 @@ namespace AzToolsFramework
}
}
void EditorTransformComponentSelection::CopyScaleToSelectedEntitiesIndividualWorld(const AZ::Vector3& scale)
void EditorTransformComponentSelection::CopyScaleToSelectedEntitiesIndividualWorld(float scale)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -2955,7 +3038,7 @@ namespace AzToolsFramework
const auto transformsBefore = RecordTransformsBefore(manipulatorEntityIds.m_entityIds);
// update scale relative to initial
const AZ::Transform scaleTransform = AZ::Transform::CreateScale(scale);
const AZ::Transform scaleTransform = AZ::Transform::CreateUniformScale(scale);
for (AZ::EntityId entityId : manipulatorEntityIds.m_entityIds)
{
ScopedUndoBatch::MarkEntityDirty(entityId);
@@ -2964,7 +3047,7 @@ namespace AzToolsFramework
if (transformIt != transformsBefore.end())
{
AZ::Transform transformBefore = transformIt->second;
transformBefore.ExtractScale();
transformBefore.ExtractUniformScale();
AZ::Transform newWorldFromLocal = transformBefore * scaleTransform;
SetEntityWorldTransform(entityId, newWorldFromLocal);
@@ -2974,7 +3057,7 @@ namespace AzToolsFramework
RefreshUiAfterChange(manipulatorEntityIds.m_entityIds);
}
void EditorTransformComponentSelection::CopyScaleToSelectedEntitiesIndividualLocal(const AZ::Vector3& scale)
void EditorTransformComponentSelection::CopyScaleToSelectedEntitiesIndividualLocal(float scale)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -3020,9 +3103,9 @@ namespace AzToolsFramework
if (transformIt != transformsBefore.end())
{
AZ::Transform newWorldFromLocal = transformIt->second;
const AZ::Vector3 scale = newWorldFromLocal.GetScale();
const float scale = newWorldFromLocal.GetUniformScale();
newWorldFromLocal.SetRotation(orientation);
newWorldFromLocal *= AZ::Transform::CreateScale(scale);
newWorldFromLocal *= AZ::Transform::CreateUniformScale(scale);
SetEntityWorldTransform(entityId, newWorldFromLocal);
}
@@ -3278,7 +3361,10 @@ namespace AzToolsFramework
ViewportInteraction::BuildMouseButtons(
QGuiApplication::mouseButtons()), m_boxSelect.Active());
const ReferenceFrame referenceFrame = ReferenceFrameFromModifiers(modifiers);
const ReferenceFrame referenceFrame =
m_spaceCluster.m_spaceLock ? m_spaceCluster.m_currentSpace : ReferenceFrameFromModifiers(modifiers);
UpdateSpaceCluster(referenceFrame);
bool refresh = false;
if (referenceFrame != m_referenceFrame)
@@ -3669,7 +3755,7 @@ namespace AzToolsFramework
}
void EditorTransformComponentSelection::SetEntityLocalScale(
const AZ::EntityId entityId, const AZ::Vector3& localScale)
const AZ::EntityId entityId, const float localScale)
{
ETCS::SetEntityLocalScale(entityId, localScale, m_transformChangedInternally);
}
@@ -3722,11 +3808,11 @@ namespace AzToolsFramework
entityId, &AZ::TransformBus::Events::SetWorldTM, worldTransform);
}
void SetEntityLocalScale(AZ::EntityId entityId, const AZ::Vector3& localScale, bool& internal)
void SetEntityLocalScale(AZ::EntityId entityId, float localScale, bool& internal)
{
ScopeSwitch sw(internal);
AZ::TransformBus::Event(
entityId, &AZ::TransformBus::Events::SetLocalScale, localScale);
entityId, &AZ::TransformBus::Events::SetLocalUniformScale, localScale);
}
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation, bool& internal)
@@ -106,6 +106,17 @@ namespace AzToolsFramework
World, //!< World space (space aligned to world axes - identity).
};
struct SpaceCluster
{
ViewportUi::ClusterId m_spaceClusterId;
ViewportUi::ButtonId m_localButtonId;
ViewportUi::ButtonId m_parentButtonId;
ViewportUi::ButtonId m_worldButtonId;
AZ::Event<ViewportUi::ButtonId>::Handler m_spaceSelectionHandler;
ReferenceFrame m_currentSpace = ReferenceFrame::Parent;
bool m_spaceLock = false;
};
//! Entity selection/interaction handling.
//! Provide a suite of functionality for manipulating entities, primarily through their TransformComponent.
class EditorTransformComponentSelection
@@ -160,6 +171,7 @@ namespace AzToolsFramework
void RegenerateManipulators();
void CreateTransformModeSelectionCluster();
void CreateSpaceSelectionCluster();
void ClearManipulatorTranslationOverride();
void ClearManipulatorOrientationOverride();
@@ -214,8 +226,8 @@ namespace AzToolsFramework
void CopyOrientationToSelectedEntitiesIndividual(const AZ::Quaternion& orientation);
void CopyOrientationToSelectedEntitiesGroup(const AZ::Quaternion& orientation);
void ResetOrientationForSelectedEntitiesLocal();
void CopyScaleToSelectedEntitiesIndividualLocal(const AZ::Vector3& scale);
void CopyScaleToSelectedEntitiesIndividualWorld(const AZ::Vector3& scale);
void CopyScaleToSelectedEntitiesIndividualLocal(float scale);
void CopyScaleToSelectedEntitiesIndividualWorld(float scale);
// EditorManipulatorCommandUndoRedoRequestBus ...
void UndoRedoEntityManipulatorCommand(
@@ -250,7 +262,7 @@ namespace AzToolsFramework
void SetEntityWorldTranslation(AZ::EntityId entityId, const AZ::Vector3& worldTranslation);
void SetEntityLocalTranslation(AZ::EntityId entityId, const AZ::Vector3& localTranslation);
void SetEntityWorldTransform(AZ::EntityId entityId, const AZ::Transform& worldTransform);
void SetEntityLocalScale(AZ::EntityId entityId, const AZ::Vector3& localScale);
void SetEntityLocalScale(AZ::EntityId entityId, float localScale);
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation);
AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any).
@@ -285,6 +297,9 @@ namespace AzToolsFramework
AZ::Event<ViewportUi::ButtonId>::Handler m_transformModeSelectionHandler; //!< Event handler for the Viewport UI cluster.
AzFramework::ClickDetector m_clickDetector; //!< Detect different types of mouse click.
AzFramework::CursorState m_cursorState; //!< Track the mouse position and delta movement each frame.
SpaceCluster m_spaceCluster;
void UpdateSpaceCluster(ReferenceFrame referenceFrame);
};
//! The ETCS (EntityTransformComponentSelection) namespace contains functions and data used exclusively by
@@ -320,7 +335,7 @@ namespace AzToolsFramework
void SetEntityWorldTranslation(AZ::EntityId entityId, const AZ::Vector3& worldTranslation, bool& internal);
void SetEntityLocalTranslation(AZ::EntityId entityId, const AZ::Vector3& localTranslation, bool& internal);
void SetEntityWorldTransform(AZ::EntityId entityId, const AZ::Transform& worldTransform, bool& internal);
void SetEntityLocalScale(AZ::EntityId entityId, const AZ::Vector3& localScale, bool& internal);
void SetEntityLocalScale(AZ::EntityId entityId, float localScale, bool& internal);
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation, bool& internal);
} // namespace ETCS
} // namespace AzToolsFramework
@@ -101,10 +101,10 @@ namespace AzToolsFramework
virtual void ResetOrientationForSelectedEntitiesLocal() = 0;
/// Copy scale to each individual entity in local space without moving position.
virtual void CopyScaleToSelectedEntitiesIndividualLocal(const AZ::Vector3& scale) = 0;
virtual void CopyScaleToSelectedEntitiesIndividualLocal(float scale) = 0;
/// Copy scale to to each individual entity in world (absolute) space.
virtual void CopyScaleToSelectedEntitiesIndividualWorld(const AZ::Vector3& scale) = 0;
virtual void CopyScaleToSelectedEntitiesIndividualWorld(float scale) = 0;
protected:
~EditorTransformComponentSelectionRequests() = default;
@@ -46,6 +46,7 @@ set(FILES
API/EditorWindowRequestBus.h
API/EntityCompositionRequestBus.h
API/EntityCompositionNotificationBus.h
API/EditorViewportIconDisplayInterface.h
API/ViewPaneOptions.h
Application/Ticker.h
Application/Ticker.cpp