Merge branch 'main' into LYN-1767-AB
This commit is contained in:
+5
@@ -12,6 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
@@ -46,6 +47,10 @@ namespace AzToolsFramework
|
||||
|
||||
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
|
||||
|
||||
//! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
|
||||
//! /return The vector of Assets generated by Prefab processing
|
||||
virtual const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() = 0;
|
||||
|
||||
virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
|
||||
virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
|
||||
|
||||
|
||||
+5
@@ -314,6 +314,11 @@ namespace AzToolsFramework
|
||||
return *m_rootInstance;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData()
|
||||
{
|
||||
return m_playInEditorData.m_assets;
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::OnEntityRemoved(AZ::EntityId entityId)
|
||||
{
|
||||
AzFramework::SliceEntityRequestBus::MultiHandler::BusDisconnect(entityId);
|
||||
|
||||
+2
@@ -195,6 +195,8 @@ namespace AzToolsFramework
|
||||
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) override;
|
||||
|
||||
Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OnEntityRemoved(AZ::EntityId entityId);
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace AzToolsFramework
|
||||
~LinearManipulator() = default;
|
||||
|
||||
/// A Manipulator must only be created and managed through a shared_ptr.
|
||||
/// @note worldFromLocal should not contain scale.
|
||||
static AZStd::shared_ptr<LinearManipulator> MakeShared(const AZ::Transform& worldFromLocal);
|
||||
|
||||
/// Unchanging data set once for the linear manipulator.
|
||||
|
||||
@@ -80,6 +80,12 @@ namespace AzToolsFramework
|
||||
|
||||
void Instance::SetTemplateId(const TemplateId& templateId)
|
||||
{
|
||||
// If we aren't changing the template Id, there's no need to unregister / re-register
|
||||
if (templateId == m_templateId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If this instance's templateId is valid, we should be able to unregister this instance from
|
||||
// Template to Instance mapping successfully.
|
||||
if (m_templateId != InvalidTemplateId &&
|
||||
|
||||
+23
-8
@@ -72,10 +72,18 @@ namespace AzToolsFramework
|
||||
|
||||
for (auto instance : findInstancesResult->get())
|
||||
{
|
||||
m_instancesUpdateQueue.emplace(instance);
|
||||
m_instancesUpdateQueue.emplace_back(instance);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceUpdateExecutor::RemoveTemplateInstanceFromQueue(const Instance* instance)
|
||||
{
|
||||
AZStd::erase_if(m_instancesUpdateQueue, [instance](Instance* entry)
|
||||
{
|
||||
return entry == instance;
|
||||
});
|
||||
}
|
||||
|
||||
bool InstanceUpdateExecutor::UpdateTemplateInstancesInQueue()
|
||||
{
|
||||
bool isUpdateSuccessful = true;
|
||||
@@ -97,9 +105,16 @@ namespace AzToolsFramework
|
||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, EntityIdList());
|
||||
|
||||
for (int i = 0; i < instanceCountToUpdateInBatch; ++i)
|
||||
// Process all instances in the queue, capped to the batch size.
|
||||
// Even though we potentially initialized the batch size to the queue, it's possible for the queue size to shrink
|
||||
// during instance processing if the instance gets deleted and it was queued multiple times. To handle this, we
|
||||
// make sure to end the loop once the queue is empty, regardless of what the initial size was.
|
||||
for (int i = 0; (i < instanceCountToUpdateInBatch) && !m_instancesUpdateQueue.empty(); ++i)
|
||||
{
|
||||
Instance* instanceToUpdate = m_instancesUpdateQueue.front();
|
||||
m_instancesUpdateQueue.pop_front();
|
||||
AZ_Assert(instanceToUpdate != nullptr, "Invalid instance on update queue.");
|
||||
|
||||
TemplateId instanceTemplateId = instanceToUpdate->GetTemplateId();
|
||||
if (currentTemplateId != instanceTemplateId)
|
||||
{
|
||||
@@ -115,19 +130,21 @@ namespace AzToolsFramework
|
||||
|
||||
// Remove the instance from update queue if its corresponding template couldn't be found
|
||||
isUpdateSuccessful = false;
|
||||
m_instancesUpdateQueue.pop();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto findInstancesResult = m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId)->get();
|
||||
auto findInstancesResult = m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId);
|
||||
AZ_Assert(
|
||||
findInstancesResult.has_value(), "Prefab Instances corresponding to template with id %llu couldn't be found.",
|
||||
instanceTemplateId);
|
||||
|
||||
if (findInstancesResult.find(instanceToUpdate) == findInstancesResult.end())
|
||||
if (findInstancesResult == AZStd::nullopt ||
|
||||
findInstancesResult->get().find(instanceToUpdate) == findInstancesResult->get().end())
|
||||
{
|
||||
// Since nested instances get reconstructed during propagation, remove any nested instance that no longer
|
||||
// maps to a template.
|
||||
isUpdateSuccessful = false;
|
||||
m_instancesUpdateQueue.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -148,8 +165,6 @@ namespace AzToolsFramework
|
||||
|
||||
isUpdateSuccessful = false;
|
||||
}
|
||||
|
||||
m_instancesUpdateQueue.pop();
|
||||
}
|
||||
|
||||
for (auto entityIdIterator = selectedEntityIds.begin(); entityIdIterator != selectedEntityIds.end(); entityIdIterator++)
|
||||
|
||||
+3
-2
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace AzToolsFramework
|
||||
|
||||
void AddTemplateInstancesToQueue(TemplateId instanceTemplateId) override;
|
||||
bool UpdateTemplateInstancesInQueue() override;
|
||||
virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) override;
|
||||
|
||||
void RegisterInstanceUpdateExecutorInterface();
|
||||
void UnregisterInstanceUpdateExecutorInterface();
|
||||
@@ -45,7 +46,7 @@ namespace AzToolsFramework
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
TemplateInstanceMapperInterface* m_templateInstanceMapperInterface = nullptr;
|
||||
int m_instanceCountToUpdateInBatch = 0;
|
||||
AZStd::queue<Instance*> m_instancesUpdateQueue;
|
||||
AZStd::deque<Instance*> m_instancesUpdateQueue;
|
||||
bool m_updatingTemplateInstancesInQueue { false };
|
||||
};
|
||||
}
|
||||
|
||||
+3
@@ -31,6 +31,9 @@ namespace AzToolsFramework
|
||||
|
||||
// Update Instances in the waiting queue.
|
||||
virtual bool UpdateTemplateInstancesInQueue() = 0;
|
||||
|
||||
// Remove an Instance from the waiting queue.
|
||||
virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -71,6 +72,12 @@ namespace AzToolsFramework
|
||||
|
||||
bool TemplateInstanceMapper::UnregisterInstance(Instance& instance)
|
||||
{
|
||||
// The InstanceUpdateExecutor queries the TemplateInstanceMapper for a list of instances related to a template.
|
||||
// Consequently, if an instance gets unregistered for a template, we need to notify the InstanceUpdateExecutor as well
|
||||
// so that it clears any internal associations that it might have in its queue.
|
||||
AZ_Assert(AZ::Interface<InstanceUpdateExecutorInterface>::Get() != nullptr, "InstanceUpdateExecutor doesn't exist");
|
||||
AZ::Interface<InstanceUpdateExecutorInterface>::Get()->RemoveTemplateInstanceFromQueue(&instance);
|
||||
|
||||
auto found = m_templateIdToInstancesMap.find(instance.GetTemplateId());
|
||||
return found != m_templateIdToInstancesMap.end() &&
|
||||
found->second.erase(&instance) != 0;
|
||||
|
||||
@@ -182,16 +182,16 @@ namespace AzToolsFramework
|
||||
else
|
||||
{
|
||||
AZ::JsonSerializationResult::ResultCode applyPatchResult = AZ::JsonSerialization::ApplyPatch(
|
||||
linkedInstanceDom,
|
||||
sourceTemplateDomCopy,
|
||||
targetTemplatePrefabDom.GetAllocator(),
|
||||
sourceTemplatePrefabDom,
|
||||
patchesReference->get(),
|
||||
AZ::JsonMergeApproach::JsonPatch);
|
||||
linkedInstanceDom.CopyFrom(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator());
|
||||
if (applyPatchResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
|
||||
{
|
||||
AZ_Error("Prefab", false,
|
||||
"Link::UpdateTarget - "
|
||||
"ApplyPatches failed for Prefab DOM from source Template '%u' and target Template '%u'.",
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
"Link::UpdateTarget - ApplyPatches failed for Prefab DOM from source Template '%u' and target Template '%u'.",
|
||||
m_sourceTemplateId, m_targetTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -199,6 +199,43 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetTemplateSourcePaths(const PrefabDomValue& prefabDom, AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths)
|
||||
{
|
||||
PrefabDomValueConstReference findSourceResult = PrefabDomUtils::FindPrefabDomValue(prefabDom, PrefabDomUtils::SourceName);
|
||||
if (!findSourceResult.has_value() || !(findSourceResult->get().IsString()) ||
|
||||
findSourceResult->get().GetStringLength() == 0)
|
||||
{
|
||||
AZ_Assert(
|
||||
false,
|
||||
"PrefabDomUtils::GetDependentTemplatePath - Source value of prefab in the provided DOM is not a valid string.");
|
||||
return;
|
||||
}
|
||||
|
||||
templateSourcePaths.emplace(findSourceResult->get().GetString());
|
||||
PrefabDomValueConstReference instancesReference = GetInstancesValue(prefabDom);
|
||||
if (instancesReference.has_value())
|
||||
{
|
||||
const PrefabDomValue& instances = instancesReference->get();
|
||||
|
||||
for (PrefabDomValue::ConstMemberIterator instanceIterator = instances.MemberBegin();
|
||||
instanceIterator != instances.MemberEnd(); ++instanceIterator)
|
||||
{
|
||||
GetTemplateSourcePaths(instanceIterator->value, templateSourcePaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom)
|
||||
{
|
||||
PrefabDomValueConstReference findInstancesResult = FindPrefabDomValue(prefabDom, PrefabDomUtils::InstancesName);
|
||||
if (!findInstancesResult.has_value() || !(findInstancesResult->get().IsObject()))
|
||||
{
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
return findInstancesResult->get();
|
||||
}
|
||||
|
||||
void PrintPrefabDomValue(
|
||||
[[maybe_unused]] const AZStd::string_view printMessage,
|
||||
[[maybe_unused]] const PrefabDomValue& prefabDomValue)
|
||||
|
||||
@@ -100,6 +100,20 @@ namespace AzToolsFramework
|
||||
.Append(instanceName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a set of all the template source paths in the given dom.
|
||||
* @param prefabDom The DOM to get the template source paths from.
|
||||
* @param[out] templateSourcePaths The set of template source paths to populate.
|
||||
*/
|
||||
void GetTemplateSourcePaths(const PrefabDomValue& prefabDom, AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths);
|
||||
|
||||
/**
|
||||
* Gets the instances DOM value from the given prefab DOM.
|
||||
*
|
||||
* @return the instances DOM value or AZStd::nullopt if it instances can't be found.
|
||||
*/
|
||||
PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom);
|
||||
|
||||
/**
|
||||
* Prints the contents of the given prefab DOM value to the debug output console in a readable format.
|
||||
* @param printMessage The message that will be printed before printing the PrefabDomValue
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> instances;
|
||||
AZStd::unordered_map<Instance*, PrefabDom> nestedInstanceLinkPatchesMap;
|
||||
|
||||
// Retrieve all entities affected and identify Instances
|
||||
if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances))
|
||||
@@ -96,6 +97,16 @@ namespace AzToolsFramework
|
||||
// target templates of the other instances.
|
||||
for (auto& nestedInstance : instances)
|
||||
{
|
||||
auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstance->GetLinkId());
|
||||
|
||||
if (linkRef.has_value())
|
||||
{
|
||||
PrefabDom oldLinkPatches;
|
||||
oldLinkPatches.CopyFrom(linkRef->get().GetLinkDom(), oldLinkPatches.GetAllocator());
|
||||
|
||||
nestedInstanceLinkPatchesMap.emplace(nestedInstance.get(), AZStd::move(oldLinkPatches));
|
||||
}
|
||||
|
||||
RemoveLink(nestedInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
|
||||
}
|
||||
|
||||
@@ -122,11 +133,17 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
|
||||
|
||||
// Parent the entities to the container entity. Parenting the container entities of the instances passed to createPrefab
|
||||
// will be done during the creation of links below.
|
||||
for (AZ::Entity* topLevelEntity : entities)
|
||||
// Apply the correct transform to the container for the new instance, and store the patch for use when creating the link.
|
||||
PrefabDom patch = ApplyContainerTransformAndGeneratePatch(containerEntityId, commonRootEntityId, topLevelEntities);
|
||||
|
||||
// Parent the non-container top level entities to the container entity.
|
||||
// Parenting the top level container entities will be done during the creation of links.
|
||||
for (AZ::Entity* topLevelEntity : topLevelEntities)
|
||||
{
|
||||
AZ::TransformBus::Event(topLevelEntity->GetId(), &AZ::TransformBus::Events::SetParent, containerEntityId);
|
||||
if (!IsInstanceContainerEntity(topLevelEntity->GetId()))
|
||||
{
|
||||
AZ::TransformBus::Event(topLevelEntity->GetId(), &AZ::TransformBus::Events::SetParent, containerEntityId);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the template of the instance since the entities are modified since the template creation.
|
||||
@@ -138,21 +155,55 @@ namespace AzToolsFramework
|
||||
|
||||
instanceToCreate->get().GetNestedInstances([&](AZStd::unique_ptr<Instance>& nestedInstance) {
|
||||
AZ_Assert(nestedInstance, "Invalid nested instance found in the new prefab created.");
|
||||
|
||||
EntityOptionalReference nestedInstanceContainerEntity = nestedInstance->GetContainerEntity();
|
||||
AZ_Assert(
|
||||
nestedInstanceContainerEntity, "Invalid container entity found for the nested instance used in prefab creation.");
|
||||
|
||||
AZ::EntityId nestedInstanceContainerEntityId = nestedInstanceContainerEntity->get().GetId();
|
||||
PrefabDom previousPatch;
|
||||
|
||||
// Retrieve the previous patch if it exists
|
||||
if (nestedInstanceLinkPatchesMap.contains(nestedInstance.get()))
|
||||
{
|
||||
previousPatch = AZStd::move(nestedInstanceLinkPatchesMap[nestedInstance.get()]);
|
||||
}
|
||||
|
||||
// These link creations shouldn't be undone because that would put the template in a non-usable state if a user
|
||||
// chooses to instantiate the template after undoing the creation.
|
||||
CreateLink(
|
||||
{&nestedInstanceContainerEntity->get()}, *nestedInstance, instanceToCreate->get().GetTemplateId(),
|
||||
undoBatch.GetUndoBatch(), containerEntityId, false);
|
||||
CreateLink(*nestedInstance, instanceToCreate->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(previousPatch), false);
|
||||
|
||||
// If this nested instance's container is a top level entity in the new prefab, re-parent it and apply the change.
|
||||
if (AZStd::find(topLevelEntities.begin(), topLevelEntities.end(), &nestedInstanceContainerEntity->get()) != topLevelEntities.end())
|
||||
{
|
||||
Prefab::PrefabDom containerEntityDomBefore;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *nestedInstanceContainerEntity);
|
||||
|
||||
AZ::TransformBus::Event(nestedInstanceContainerEntityId, &AZ::TransformBus::Events::SetParent, containerEntityId);
|
||||
|
||||
PrefabDom containerEntityDomAfter;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *nestedInstanceContainerEntity);
|
||||
|
||||
PrefabDom reparentPatch;
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
// Create a link between the templates of the newly created instance and the instance it's being parented under.
|
||||
CreateLink(
|
||||
topLevelEntities, instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(),
|
||||
undoBatch.GetUndoBatch(), commonRootEntityId);
|
||||
instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
|
||||
AZStd::move(patch));
|
||||
|
||||
for (AZ::Entity* topLevelEntity : topLevelEntities)
|
||||
{
|
||||
@@ -182,6 +233,40 @@ namespace AzToolsFramework
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabDom PrefabPublicHandler::ApplyContainerTransformAndGeneratePatch(AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities)
|
||||
{
|
||||
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
|
||||
AZ_Assert(containerEntity, "Invalid container entity passed to ApplyContainerTransformAndGeneratePatch.");
|
||||
|
||||
// Generate the transform for the container entity out of the top level entities, and set it
|
||||
// This step needs to be done before anything is parented to the container, else children position will be wrong
|
||||
Prefab::PrefabDom containerEntityDomBefore;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
|
||||
|
||||
AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
|
||||
AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
|
||||
|
||||
// Set container entity to be child of common root
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, parentEntityId);
|
||||
|
||||
// Set the transform (translation, rotation) of the container entity
|
||||
GenerateContainerEntityTransform(childEntities, containerEntityTranslation, containerEntityRotation);
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
|
||||
|
||||
PrefabDom containerEntityDomAfter;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
|
||||
|
||||
PrefabDom patch;
|
||||
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
|
||||
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
|
||||
|
||||
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
|
||||
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
|
||||
|
||||
return AZStd::move(patch);
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(
|
||||
AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
|
||||
{
|
||||
@@ -210,27 +295,32 @@ namespace AzToolsFramework
|
||||
auto relativePath = m_prefabLoaderInterface->GetRelativePathToProject(filePath);
|
||||
Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
|
||||
|
||||
// If the template isn't currently loaded, there's no way for it to be in the hierarchy so we just skip the check.
|
||||
if (templateId != Prefab::InvalidTemplateId && IsPrefabInInstanceAncestorHierarchy(templateId, instanceToParentUnder->get()))
|
||||
if (templateId == InvalidTemplateId)
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string::format(
|
||||
"Instantiate Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).",
|
||||
relativePath.Native().c_str(),
|
||||
instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str()
|
||||
)
|
||||
);
|
||||
// Load the template from the file
|
||||
templateId = m_prefabLoaderInterface->LoadTemplateFromFile(filePath);
|
||||
AZ_Assert(templateId != InvalidTemplateId, "Template with source path %s couldn't be loaded correctly.", filePath);
|
||||
}
|
||||
|
||||
|
||||
const PrefabDom& templateDom = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
AZStd::unordered_set<AZ::IO::Path> templatePaths;
|
||||
PrefabDomUtils::GetTemplateSourcePaths(templateDom, templatePaths);
|
||||
|
||||
if (IsCyclicalDependencyFound(instanceToParentUnder->get(), templatePaths))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Instantiate Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).",
|
||||
relativePath.Native().c_str(), instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str()));
|
||||
}
|
||||
|
||||
{
|
||||
// Initialize Undo Batch object
|
||||
ScopedUndoBatch undoBatch("Instantiate Prefab");
|
||||
|
||||
PrefabDom instanceToParentUnderDomBeforeCreate;
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(
|
||||
instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
|
||||
|
||||
// Instantiate the Prefab
|
||||
PrefabDom instanceToParentUnderDomBeforeCreate;
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
|
||||
|
||||
auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(relativePath, instanceToParentUnder);
|
||||
|
||||
if (!instanceToCreate)
|
||||
@@ -242,12 +332,32 @@ namespace AzToolsFramework
|
||||
PrefabUndoHelpers::UpdatePrefabInstance(
|
||||
instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch());
|
||||
|
||||
CreateLink({}, instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(),
|
||||
undoBatch.GetUndoBatch(), parent);
|
||||
// Create Link with correct container patches
|
||||
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
|
||||
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
|
||||
AZ_Assert(containerEntity, "Invalid container entity detected in InstantiatePrefab.");
|
||||
|
||||
// Apply position
|
||||
Prefab::PrefabDom containerEntityDomBefore;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
|
||||
|
||||
// Set container entity's parent
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, parent);
|
||||
|
||||
// Set the position of the container entity
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetWorldTranslation, position);
|
||||
|
||||
PrefabDom containerEntityDomAfter;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
|
||||
|
||||
// Generate patch to be stored in the link
|
||||
PrefabDom patch;
|
||||
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
|
||||
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
|
||||
|
||||
CreateLink(instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(patch));
|
||||
|
||||
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
|
||||
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
@@ -296,17 +406,17 @@ namespace AzToolsFramework
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
bool PrefabPublicHandler::IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance)
|
||||
bool PrefabPublicHandler::IsCyclicalDependencyFound(
|
||||
InstanceOptionalConstReference instance, const AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths)
|
||||
{
|
||||
InstanceOptionalConstReference currentInstance = instance;
|
||||
|
||||
while (currentInstance.has_value())
|
||||
{
|
||||
if (currentInstance->get().GetTemplateId() == prefabTemplateId)
|
||||
if (templateSourcePaths.contains(currentInstance->get().GetTemplateSourcePath()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
currentInstance = currentInstance->get().GetParentInstance();
|
||||
}
|
||||
|
||||
@@ -314,33 +424,9 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
void PrefabPublicHandler::CreateLink(
|
||||
const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
|
||||
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId, const bool isUndoRedoSupportNeeded)
|
||||
Instance& sourceInstance, TemplateId targetTemplateId,
|
||||
UndoSystem::URSequencePoint* undoBatch, PrefabDom patch, const bool isUndoRedoSupportNeeded)
|
||||
{
|
||||
AZ::EntityId containerEntityId = sourceInstance.GetContainerEntityId();
|
||||
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
|
||||
Prefab::PrefabDom containerEntityDomBefore;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
|
||||
|
||||
AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
|
||||
AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
|
||||
|
||||
// Set the transform (translation, rotation) of the container entity
|
||||
GenerateContainerEntityTransform(topLevelEntities, containerEntityTranslation, containerEntityRotation);
|
||||
|
||||
// Set container entity to be child of common root
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, commonRootEntityId);
|
||||
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
|
||||
|
||||
PrefabDom containerEntityDomAfter;
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
|
||||
|
||||
PrefabDom patch;
|
||||
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
|
||||
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
|
||||
|
||||
LinkId linkId;
|
||||
if (isUndoRedoSupportNeeded)
|
||||
{
|
||||
@@ -356,9 +442,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
sourceInstance.SetLinkId(linkId);
|
||||
|
||||
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
|
||||
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
|
||||
}
|
||||
|
||||
void PrefabPublicHandler::RemoveLink(
|
||||
@@ -636,11 +719,18 @@ namespace AzToolsFramework
|
||||
|
||||
if (!EntitiesBelongToSameInstance(entityIds))
|
||||
{
|
||||
return AZ::Failure(AZStd::string("DeleteEntitiesAndAllDescendantsInInstance - Deletion Error. Cannot delete multiple "
|
||||
"entities belonging to different instances with one operation."));
|
||||
return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation."));
|
||||
}
|
||||
|
||||
InstanceOptionalReference instance = GetOwnerInstanceByEntityId(entityIds[0]);
|
||||
AZ::EntityId firstEntityIdToDelete = entityIds[0];
|
||||
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete);
|
||||
|
||||
// If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
|
||||
// cannot delete an instance from itself.
|
||||
if (commonOwningInstance->get().GetContainerEntityId() == firstEntityIdToDelete)
|
||||
{
|
||||
commonOwningInstance = commonOwningInstance->get().GetParentInstance();
|
||||
}
|
||||
|
||||
// Retrieve entityList from entityIds
|
||||
EntityList inputEntityList = EntityIdListToEntityList(entityIds);
|
||||
@@ -680,14 +770,14 @@ namespace AzToolsFramework
|
||||
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DeleteEntities:UndoCaptureAndPurgeEntities");
|
||||
|
||||
Prefab::PrefabDom instanceDomBefore;
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, instance->get());
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonOwningInstance->get());
|
||||
|
||||
if (deleteDescendants)
|
||||
{
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> instances;
|
||||
|
||||
bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, instance->get(), entities, instances);
|
||||
bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
@@ -701,6 +791,7 @@ namespace AzToolsFramework
|
||||
|
||||
for (auto& nestedInstance : instances)
|
||||
{
|
||||
RemoveLink(nestedInstance, commonOwningInstance->get().GetTemplateId(), currentUndoBatch);
|
||||
nestedInstance.reset();
|
||||
}
|
||||
}
|
||||
@@ -712,22 +803,22 @@ namespace AzToolsFramework
|
||||
// If this is the container entity, it actually represents the instance so get its owner
|
||||
if (owningInstance->get().GetContainerEntityId() == entityId)
|
||||
{
|
||||
auto instancePtr = instance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias());
|
||||
instancePtr.reset();
|
||||
auto instancePtr = commonOwningInstance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias());
|
||||
RemoveLink(instancePtr, commonOwningInstance->get().GetTemplateId(), currentUndoBatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
instance->get().DetachEntity(entityId);
|
||||
commonOwningInstance->get().DetachEntity(entityId);
|
||||
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Prefab::PrefabDom instanceDomAfter;
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, instance->get());
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, commonOwningInstance->get());
|
||||
|
||||
PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance deletion");
|
||||
command->Capture(instanceDomBefore, instanceDomAfter, instance->get().GetTemplateId());
|
||||
command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId());
|
||||
command->SetParent(selCommand);
|
||||
}
|
||||
|
||||
@@ -995,5 +1086,5 @@ namespace AzToolsFramework
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
@@ -68,20 +68,32 @@ namespace AzToolsFramework
|
||||
|
||||
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
|
||||
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
|
||||
|
||||
/**
|
||||
* Applies the correct transform changes to the container entity based on the parent and child entities provided, and returns an appropriate patch.
|
||||
* The container will be parented to parentId, moved to the average transform of the future direct children and its cache will be updated.
|
||||
* This helper function won't support undo/redo, update the templates or create any links. All that needs to be done by the caller.
|
||||
*
|
||||
* \param containerEntityId The container to apply the changes to.
|
||||
* \param parentEntityId The id of the entity the container should be parented to.
|
||||
* \param childEntities A list of entities that will subsequently be parented to this container.
|
||||
* \return The PrefabDom containing the patches that should be stored in the parent link.
|
||||
*/
|
||||
PrefabDom ApplyContainerTransformAndGeneratePatch(
|
||||
AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities);
|
||||
|
||||
/**
|
||||
* Creates a link between the templates of an instance and its parent.
|
||||
*
|
||||
* \param topLevelEntities The list of entities that are immediate children to the container entity of the instance.
|
||||
* \param sourceInstance The instance that corresponds to the source template of the link.
|
||||
* \param targetInstance The id of the target template.
|
||||
* \param undoBatch The undo batch to set as parent for this create link action.
|
||||
* \param commonRootEntityId The id of the entity that the source instance should be parented under.
|
||||
* \param patch The patch to store in the newly created link dom.
|
||||
* \param isUndoRedoSupportNeeded The flag indicating whether the link should be created with undo/redo support or not.
|
||||
*/
|
||||
void CreateLink(
|
||||
const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
|
||||
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId, const bool isUndoRedoSupportNeeded = true);
|
||||
Instance& sourceInstance, TemplateId targetTemplateId, UndoSystem::URSequencePoint* undoBatch,
|
||||
PrefabDom patch, const bool isUndoRedoSupportNeeded = true);
|
||||
|
||||
/**
|
||||
* Removes the link between template of the sourceInstance and the template corresponding to targetTemplateId.
|
||||
@@ -107,13 +119,15 @@ namespace AzToolsFramework
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, EntityList& inputEntityList, EntityList& topLevelEntities,
|
||||
AZ::EntityId& commonRootEntityId, InstanceOptionalReference& commonRootEntityOwningInstance);
|
||||
|
||||
/* Detects whether an instance of prefabTemplateId is present in the hierarchy of ancestors of instance.
|
||||
/* Checks whether the template source path of any of the ancestors in the instance hierarchy matches with one of the
|
||||
* paths provided in a set.
|
||||
*
|
||||
* \param prefabTemplateId The template id to test for
|
||||
* \param instance The instance whose ancestor hierarchy prefabTemplateId will be tested against.
|
||||
* \return true if an instance of the template of id prefabTemplateId could be found in the ancestor hierarchy of instance, false otherwise.
|
||||
* \param instance The instance whose ancestor hierarchy the provided set of template source paths will be tested against.
|
||||
* \param templateSourcePaths The template source paths provided to be checked against the instance ancestor hierarchy.
|
||||
* \return true if any of the template source paths could be found in the ancestor hierarchy of instance, false otherwise.
|
||||
*/
|
||||
bool IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance);
|
||||
bool IsCyclicalDependencyFound(
|
||||
InstanceOptionalConstReference instance, const AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths);
|
||||
|
||||
static Instance* GetParentInstance(Instance* instance);
|
||||
static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant);
|
||||
@@ -129,5 +143,5 @@ namespace AzToolsFramework
|
||||
|
||||
uint64_t m_newEntityCounter = 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+29
-18
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -32,12 +32,13 @@ namespace AzToolsFramework
|
||||
serializeContext->Class<EditorNonUniformScaleComponent, EditorComponentBase>()
|
||||
->Version(1)
|
||||
->Field("NonUniformScale", &EditorNonUniformScaleComponent::m_scale)
|
||||
;
|
||||
->Field("ComponentMode", &EditorNonUniformScaleComponent::m_componentModeDelegate);
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorNonUniformScaleComponent>("Non-uniform Scale",
|
||||
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
|
||||
editContext
|
||||
->Class<EditorNonUniformScaleComponent>(
|
||||
"Non-uniform Scale", "Non-uniform scale for this entity only (does not propagate through hierarchy)")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::FixedComponentListIndex, 1)
|
||||
->Attribute(AZ::Edit::Attributes::RemoveableByUser, true)
|
||||
@@ -50,7 +51,10 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Edit::Attributes::Max, AZ::MaxTransformScale)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorNonUniformScaleComponent::OnScaleChanged)
|
||||
;
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_componentModeDelegate, "Component Mode",
|
||||
"Non-uniform Scale Component Mode")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,10 +78,16 @@ namespace AzToolsFramework
|
||||
void EditorNonUniformScaleComponent::Activate()
|
||||
{
|
||||
AZ::NonUniformScaleRequestBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
// ComponentMode
|
||||
m_componentModeDelegate.ConnectWithSingleComponentMode<EditorNonUniformScaleComponent, NonUniformScaleComponentMode>(
|
||||
AZ::EntityComponentIdPair(GetEntityId(), GetId()), nullptr);
|
||||
}
|
||||
|
||||
void EditorNonUniformScaleComponent::Deactivate()
|
||||
{
|
||||
m_componentModeDelegate.Disconnect();
|
||||
|
||||
AZ::NonUniformScaleRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -96,7 +106,8 @@ namespace AzToolsFramework
|
||||
else
|
||||
{
|
||||
AZ::Vector3 clampedScale = scale.GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale));
|
||||
AZ_Warning("Editor Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s",
|
||||
AZ_Warning(
|
||||
"Editor Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s",
|
||||
AZ::ToString(scale).c_str(), AZ::ToString(clampedScale).c_str(), GetEntity()->GetName().c_str());
|
||||
m_scale = clampedScale;
|
||||
}
|
||||
|
||||
+6
@@ -13,6 +13,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.h>
|
||||
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
|
||||
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
|
||||
#include <AzCore/Component/NonUniformScaleBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -52,6 +55,9 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::Vector3 m_scale = AZ::Vector3::CreateOne();
|
||||
AZ::NonUniformScaleChangedEvent m_scaleChangedEvent;
|
||||
|
||||
//! Responsible for detecting ComponentMode activation and creating a concrete ComponentMode.
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeDelegate m_componentModeDelegate;
|
||||
};
|
||||
} // namespace Components
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/NonUniformScaleBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzFramework/Viewport/ViewportColors.h>
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Components
|
||||
{
|
||||
NonUniformScaleComponentMode::NonUniformScaleComponentMode(
|
||||
const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType)
|
||||
: EditorBaseComponentMode(entityComponentIdPair, componentType)
|
||||
{
|
||||
m_entityComponentIdPair = entityComponentIdPair;
|
||||
|
||||
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(worldFromLocal, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
worldFromLocal.ExtractScale();
|
||||
m_manipulators = AZStd::make_unique<ScaleManipulators>(worldFromLocal);
|
||||
m_manipulators->Register(g_mainManipulatorManagerId);
|
||||
m_manipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
|
||||
const float axisLength = 2.0f;
|
||||
m_manipulators->ConfigureView(
|
||||
axisLength, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
|
||||
AzFramework::ViewportColors::ZAxisColor);
|
||||
|
||||
auto mouseDownCallback = [this](const LinearManipulator::Action& action) {
|
||||
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
|
||||
|
||||
AZ::NonUniformScaleRequestBus::EventResult(
|
||||
nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
|
||||
|
||||
m_initialScale = nonUniformScale + action.m_start.m_scaleSnapOffset;
|
||||
|
||||
AZ::NonUniformScaleRequestBus::Event(
|
||||
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, m_initialScale);
|
||||
};
|
||||
|
||||
m_manipulators->InstallAxisLeftMouseDownCallback(mouseDownCallback);
|
||||
|
||||
m_manipulators->InstallAxisMouseMoveCallback([this](const LinearManipulator::Action& action) {
|
||||
const AZ::Vector3 scaleMultiplier =
|
||||
(AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale));
|
||||
|
||||
AZ::NonUniformScaleRequestBus::Event(
|
||||
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale,
|
||||
(scaleMultiplier * m_initialScale).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale)));
|
||||
});
|
||||
|
||||
m_manipulators->InstallUniformLeftMouseDownCallback(mouseDownCallback);
|
||||
|
||||
m_manipulators->InstallUniformMouseMoveCallback([this](const LinearManipulator::Action& action) {
|
||||
const auto sumVectorElements = [](const AZ::Vector3& vec) { return vec.GetX() + vec.GetY() + vec.GetZ(); };
|
||||
|
||||
const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement();
|
||||
const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement();
|
||||
const float scaleMultiplier = AZ::GetClamp(
|
||||
1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier,
|
||||
maxScaleMultiplier);
|
||||
|
||||
AZ::NonUniformScaleRequestBus::Event(
|
||||
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale);
|
||||
});
|
||||
}
|
||||
|
||||
NonUniformScaleComponentMode::~NonUniformScaleComponentMode()
|
||||
{
|
||||
if (m_manipulators)
|
||||
{
|
||||
m_manipulators->Unregister();
|
||||
}
|
||||
m_manipulators.reset();
|
||||
}
|
||||
|
||||
void NonUniformScaleComponentMode::Refresh()
|
||||
{
|
||||
}
|
||||
} // namespace Components
|
||||
} // namespace AzToolsFramework
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 <AzToolsFramework/ComponentMode/EditorBaseComponentMode.h>
|
||||
#include <AzToolsFramework/Manipulators/ScaleManipulators.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Components
|
||||
{
|
||||
class NonUniformScaleComponentMode : public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(NonUniformScaleComponentMode, AZ::SystemAllocator, 0)
|
||||
|
||||
NonUniformScaleComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType);
|
||||
NonUniformScaleComponentMode(const NonUniformScaleComponentMode&) = delete;
|
||||
NonUniformScaleComponentMode& operator=(const NonUniformScaleComponentMode&) = delete;
|
||||
NonUniformScaleComponentMode(NonUniformScaleComponentMode&&) = delete;
|
||||
NonUniformScaleComponentMode& operator=(NonUniformScaleComponentMode&&) = delete;
|
||||
~NonUniformScaleComponentMode();
|
||||
|
||||
// EditorBaseComponentMode overrides ...
|
||||
void Refresh() override;
|
||||
|
||||
private:
|
||||
AZ::EntityComponentIdPair m_entityComponentIdPair;
|
||||
AZStd::unique_ptr<ScaleManipulators> m_manipulators;
|
||||
AZ::Vector3 m_initialScale;
|
||||
};
|
||||
} // namespace Components
|
||||
} // namespace AzToolsFramework
|
||||
+24
-2
@@ -162,6 +162,12 @@ namespace AzToolsFramework
|
||||
classElement.RemoveElementByName(AZ_CRC("InterpolateScale", 0x9d00b831));
|
||||
}
|
||||
|
||||
if (classElement.GetVersion() < 10)
|
||||
{
|
||||
// The "Sync Enabled" flag is no longer needed.
|
||||
classElement.RemoveElementByName(AZ_CRC_CE("Sync Enabled"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace Internal
|
||||
@@ -254,7 +260,7 @@ namespace AzToolsFramework
|
||||
m_localTransformDirty = true;
|
||||
m_worldTransformDirty = true;
|
||||
|
||||
if (GetEntity())
|
||||
if (const AZ::Entity* entity = GetEntity())
|
||||
{
|
||||
SetDirty();
|
||||
|
||||
@@ -273,6 +279,22 @@ namespace AzToolsFramework
|
||||
{
|
||||
boundsUnion->OnTransformUpdated(GetEntity());
|
||||
}
|
||||
// Fire a property changed notification for this component
|
||||
if (const AZ::Component* component = entity->FindComponent<Components::TransformComponent>())
|
||||
{
|
||||
PropertyEditorEntityChangeNotificationBus::Event(
|
||||
GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, component->GetId());
|
||||
}
|
||||
|
||||
// Refresh the property editor if we're selected
|
||||
bool selected = false;
|
||||
ToolsApplicationRequestBus::BroadcastResult(
|
||||
selected, &AzToolsFramework::ToolsApplicationRequests::IsSelected, GetEntityId());
|
||||
if (selected)
|
||||
{
|
||||
ToolsApplicationEvents::Bus::Broadcast(
|
||||
&ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,7 +1311,7 @@ namespace AzToolsFramework
|
||||
Field("IsStatic", &TransformComponent::m_isStatic)->
|
||||
Field("InterpolatePosition", &TransformComponent::m_interpolatePosition)->
|
||||
Field("InterpolateRotation", &TransformComponent::m_interpolateRotation)->
|
||||
Version(9, &Internal::TransformComponentDataConverter);
|
||||
Version(10, &Internal::TransformComponentDataConverter);
|
||||
|
||||
if (AZ::EditContext* ptrEdit = serializeContext->GetEditContext())
|
||||
{
|
||||
|
||||
+48
-64
@@ -93,28 +93,12 @@ namespace AzToolsFramework
|
||||
EditorContextMenuBus::Handler::BusConnect();
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Register(this);
|
||||
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
if (prefabWipFeaturesEnabled)
|
||||
{
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
|
||||
}
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
|
||||
}
|
||||
|
||||
PrefabIntegrationManager::~PrefabIntegrationManager()
|
||||
{
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
if (prefabWipFeaturesEnabled)
|
||||
{
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Unregister(this);
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusDisconnect();
|
||||
EditorContextMenuBus::Handler::BusDisconnect();
|
||||
@@ -137,66 +121,63 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu) const
|
||||
{
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
AzToolsFramework::EntityIdList selectedEntities;
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
selectedEntities, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
|
||||
|
||||
if (prefabWipFeaturesEnabled)
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
// Create Prefab
|
||||
{
|
||||
// Create Prefab
|
||||
if (!selectedEntities.empty())
|
||||
{
|
||||
if (!selectedEntities.empty())
|
||||
// Hide if the only selected entity is the Level Container
|
||||
if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
|
||||
{
|
||||
// Hide if the only selected entity is the Level Container
|
||||
if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
|
||||
bool layerInSelection = false;
|
||||
|
||||
for (AZ::EntityId entityId : selectedEntities)
|
||||
{
|
||||
bool layerInSelection = false;
|
||||
|
||||
for (AZ::EntityId entityId : selectedEntities)
|
||||
{
|
||||
if (!layerInSelection)
|
||||
{
|
||||
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
||||
layerInSelection, entityId,
|
||||
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
||||
|
||||
if (layerInSelection)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layers can't be in prefabs.
|
||||
if (!layerInSelection)
|
||||
{
|
||||
QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
|
||||
createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
|
||||
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
||||
layerInSelection, entityId,
|
||||
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
||||
|
||||
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
|
||||
ContextMenu_CreatePrefab(selectedEntities);
|
||||
});
|
||||
if (layerInSelection)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layers can't be in prefabs.
|
||||
if (!layerInSelection)
|
||||
{
|
||||
QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
|
||||
createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
|
||||
|
||||
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
|
||||
ContextMenu_CreatePrefab(selectedEntities);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate Prefab
|
||||
{
|
||||
QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab..."));
|
||||
instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene."));
|
||||
|
||||
QObject::connect(
|
||||
instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiatePrefab(); });
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
// Instantiate Prefab
|
||||
{
|
||||
QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab..."));
|
||||
instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene."));
|
||||
|
||||
QObject::connect(
|
||||
instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiatePrefab(); });
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
bool itemWasShown = false;
|
||||
|
||||
// Edit/Save Prefab
|
||||
@@ -403,9 +384,12 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::EntityIdList selectedEntityIds;
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationRequests::DeleteEntitiesAndAllDescendants, selectedEntityIds);
|
||||
PrefabOperationResult deleteSelectedResult =
|
||||
s_prefabPublicInterface->DeleteEntitiesAndAllDescendantsInInstance(selectedEntityIds);
|
||||
if (!deleteSelectedResult.IsSuccess())
|
||||
{
|
||||
WarnUserOfError("Delete selected entities error", deleteSelectedResult.GetError());
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::GenerateSuggestedFilenameFromEntities(const EntityIdList& entityIds, AZStd::string& outName)
|
||||
|
||||
+28
@@ -27,6 +27,7 @@ AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") // 4244: con
|
||||
#include <QtGui/QTextLayout>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QMessageBox>
|
||||
#include <QStylePainter>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
static const int LabelColumnStretch = 2;
|
||||
@@ -121,6 +122,19 @@ namespace AzToolsFramework
|
||||
setLayout(m_mainLayout);
|
||||
}
|
||||
|
||||
void PropertyRowWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
|
||||
if (CanBeReordered())
|
||||
{
|
||||
const QPen linePen(QColor(0x3B3E3F));
|
||||
p.setPen(linePen);
|
||||
int indent = m_treeDepth * m_treeIndentation;
|
||||
p.drawLine(event->rect().topLeft() + QPoint(indent, 0), event->rect().topRight());
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::HasChildWidgetAlready() const
|
||||
{
|
||||
return m_childWidget != nullptr;
|
||||
@@ -1661,6 +1675,20 @@ namespace AzToolsFramework
|
||||
m_nameLabel->setFilter(m_currentFilterString);
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::CanChildrenBeReordered() const
|
||||
{
|
||||
return m_containerEditable;
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::CanBeReordered() const
|
||||
{
|
||||
if (!m_parentRow)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_parentRow->CanChildrenBeReordered();
|
||||
}
|
||||
}
|
||||
|
||||
#include "UI/PropertyEditor/moc_PropertyRowWidget.cpp"
|
||||
|
||||
+5
@@ -44,6 +44,7 @@ namespace AzToolsFramework
|
||||
Q_PROPERTY(bool hasChildRows READ HasChildRows);
|
||||
Q_PROPERTY(bool isTopLevel READ IsTopLevel);
|
||||
Q_PROPERTY(int getLevel READ GetLevel);
|
||||
Q_PROPERTY(bool canBeReordered READ CanBeReordered);
|
||||
Q_PROPERTY(bool appendDefaultLabelToName READ GetAppendDefaultLabelToName WRITE AppendDefaultLabelToName)
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PropertyRowWidget, AZ::SystemAllocator, 0)
|
||||
@@ -126,6 +127,7 @@ namespace AzToolsFramework
|
||||
void SetSelectionEnabled(bool selectionEnabled);
|
||||
void SetSelected(bool selected);
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
/// Apply tooltip to widget and some of its children.
|
||||
void SetDescription(const QString& text);
|
||||
@@ -146,6 +148,9 @@ namespace AzToolsFramework
|
||||
QLabel* GetNameLabel() { return m_nameLabel; }
|
||||
void SetIndentSize(int w);
|
||||
void SetAsCustom(bool custom) { m_custom = custom; }
|
||||
|
||||
bool CanChildrenBeReordered() const;
|
||||
bool CanBeReordered() const;
|
||||
protected:
|
||||
int CalculateLabelWidth() const;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
@@ -304,4 +305,24 @@ namespace AzToolsFramework
|
||||
|
||||
return entityContextId;
|
||||
}
|
||||
|
||||
//! Maps a mouse interaction event to a ClickDetector event.
|
||||
//! @note Function only cares about up or down events, all other events are mapped to Nil (ignored).
|
||||
inline AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction(
|
||||
const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left())
|
||||
{
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Down;
|
||||
}
|
||||
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Up;
|
||||
}
|
||||
}
|
||||
return AzFramework::ClickDetector::ClickEvent::Nil;
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+9
-4
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -27,8 +28,11 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
|
||||
m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
|
||||
|
||||
const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction);
|
||||
const auto clickOutcome = m_clickDetector.DetectClick(selectClickEvent, m_cursorState.CursorDelta());
|
||||
if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Move)
|
||||
{
|
||||
if (m_leftMouseDown)
|
||||
{
|
||||
@@ -58,8 +62,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
|
||||
if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Release)
|
||||
{
|
||||
if (m_leftMouseUp)
|
||||
{
|
||||
@@ -77,6 +80,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
m_cursorState.Update();
|
||||
|
||||
if (m_boxSelectRegion)
|
||||
{
|
||||
debugDisplay.DepthTestOff();
|
||||
|
||||
+21
-17
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzFramework/Viewport/CursorState.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
#include <QRect>
|
||||
@@ -26,49 +28,49 @@ namespace AzFramework
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
/// Utility to provide box select (click and drag) support for viewport types.
|
||||
/// Users can override the mouse event callbacks and display scene function to customize behavior.
|
||||
//! Utility to provide box select (click and drag) support for viewport types.
|
||||
//! Users can override the mouse event callbacks and display scene function to customize behavior.
|
||||
class EditorBoxSelect
|
||||
{
|
||||
public:
|
||||
EditorBoxSelect() = default;
|
||||
|
||||
/// Return if a box select action is currently taking place.
|
||||
//! Return if a box select action is currently taking place.
|
||||
bool Active() const { return m_boxSelectRegion.has_value(); }
|
||||
|
||||
/// Update the box select for various mouse events.
|
||||
/// Call HandleMouseInteraction from type/system implementing MouseViewportRequests interface.
|
||||
//! Update the box select for various mouse events.
|
||||
//! Call HandleMouseInteraction from type/system implementing MouseViewportRequests interface.
|
||||
void HandleMouseInteraction(
|
||||
const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
|
||||
|
||||
/// Responsible for drawing the 2d box representing the selection in screen space.
|
||||
//! Responsible for drawing the 2d box representing the selection in screen space.
|
||||
void Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
|
||||
|
||||
/// Custom drawing behavior to happen during a box select.
|
||||
//! Custom drawing behavior to happen during a box select.
|
||||
void DisplayScene(
|
||||
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
|
||||
|
||||
/// Set the left mouse down callback.
|
||||
//! Set the left mouse down callback.
|
||||
void InstallLeftMouseDown(
|
||||
const AZStd::function<void(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)>& leftMouseDown);
|
||||
/// Set the mouse move callback.
|
||||
//! Set the mouse move callback.
|
||||
void InstallMouseMove(
|
||||
const AZStd::function<void(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)>& mouseMove);
|
||||
/// Set the left mouse up callback.
|
||||
//! Set the left mouse up callback.
|
||||
void InstallLeftMouseUp(
|
||||
const AZStd::function<void()>& leftMouseUp);
|
||||
/// Set the display scene callback.
|
||||
//! Set the display scene callback.
|
||||
void InstallDisplayScene(
|
||||
const AZStd::function<void(
|
||||
const AzFramework::ViewportInfo& viewportInfo,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay)>& displayScene);
|
||||
|
||||
/// Return the box select region.
|
||||
/// If a box selection is being made, return the current rectangle representing the area.
|
||||
/// If there is currently no active box select, then the Maybe type will be empty (there will be no region/area).
|
||||
//! Return the box select region.
|
||||
//! If a box selection is being made, return the current rectangle representing the area.
|
||||
//! If there is currently no active box select, then the Maybe type will be empty (there will be no region/area).
|
||||
const AZStd::optional<QRect>& BoxRegion() const { return m_boxSelectRegion; }
|
||||
|
||||
/// Return the active modifiers from the previous frame.
|
||||
//! Return the active modifiers from the previous frame.
|
||||
ViewportInteraction::KeyboardModifiers PreviousModifiers() const { return m_previousModifiers; }
|
||||
|
||||
private:
|
||||
@@ -79,7 +81,9 @@ namespace AzToolsFramework
|
||||
AZStd::function<void(
|
||||
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)> m_displayScene;
|
||||
|
||||
AZStd::optional<QRect> m_boxSelectRegion; ///< Maybe/optional value to store box select region while active.
|
||||
ViewportInteraction::KeyboardModifiers m_previousModifiers; ///< Modifier keys active on the previous frame.
|
||||
AZStd::optional<QRect> m_boxSelectRegion; //!< Maybe/optional value to store box select region while active.
|
||||
ViewportInteraction::KeyboardModifiers m_previousModifiers; //!< Modifier keys active on the previous frame.
|
||||
AzFramework::ClickDetector m_clickDetector; //!< Utility type to detect if a mouse click or move has occurred.
|
||||
AzFramework::CursorState m_cursorState; //!< Utility type to track the current cursor position (and movement/delta).
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-16
@@ -1782,22 +1782,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_cachedEntityIdUnderCursor = m_editorHelpers->HandleMouseInteraction(cameraState, mouseInteraction);
|
||||
|
||||
const AzFramework::ClickDetector::ClickEvent selectClickEvent = [&mouseInteraction] {
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left())
|
||||
{
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Down;
|
||||
}
|
||||
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Up;
|
||||
}
|
||||
}
|
||||
return AzFramework::ClickDetector::ClickEvent::Nil;
|
||||
}();
|
||||
|
||||
const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction);
|
||||
m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
|
||||
const auto clickOutcome = m_clickDetector.DetectClick(selectClickEvent, m_cursorState.CursorDelta());
|
||||
|
||||
|
||||
@@ -303,6 +303,8 @@ set(FILES
|
||||
ToolsComponents/AzToolsFrameworkConfigurationSystemComponent.cpp
|
||||
ToolsComponents/EditorNonUniformScaleComponent.h
|
||||
ToolsComponents/EditorNonUniformScaleComponent.cpp
|
||||
ToolsComponents/EditorNonUniformScaleComponentMode.h
|
||||
ToolsComponents/EditorNonUniformScaleComponentMode.cpp
|
||||
ToolsMessaging/EntityHighlightBus.h
|
||||
UI/Docking/DockWidgetUtils.cpp
|
||||
UI/Docking/DockWidgetUtils.h
|
||||
|
||||
@@ -237,4 +237,23 @@ namespace UnitTest
|
||||
EXPECT_THAT(cameraTransform, IsClose(cameraTransformFromView));
|
||||
EXPECT_THAT(cameraView, IsClose(cameraViewFromTransform));
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, FovCanBeRetrievedFromProjectionMatrix)
|
||||
{
|
||||
using ::testing::FloatNear;
|
||||
|
||||
auto cameraState = AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AZ::Vector2(800.0f, 600.0f));
|
||||
|
||||
{
|
||||
const float fovRadians = AZ::DegToRad(45.0f);
|
||||
AzFramework::SetCameraClippingVolume(cameraState, 0.1f, 100.0f, fovRadians);
|
||||
EXPECT_THAT(AzFramework::RetrieveFov(AzFramework::CameraProjection(cameraState)), FloatNear(fovRadians, 0.001f));
|
||||
}
|
||||
|
||||
{
|
||||
const float fovRadians = AZ::DegToRad(90.0f);
|
||||
AzFramework::SetCameraClippingVolume(cameraState, 0.1f, 100.0f, fovRadians);
|
||||
EXPECT_THAT(AzFramework::RetrieveFov(AzFramework::CameraProjection(cameraState)), FloatNear(fovRadians, 0.001f));
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
Reference in New Issue
Block a user