Merge branch 'main' into LYN-1767-AB
This commit is contained in:
@@ -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)
|
||||
@@ -110,14 +120,14 @@ namespace AzToolsFramework
|
||||
|
||||
/**
|
||||
* Query to see if a specific asset platform is enabled
|
||||
* @param platform the asset platform to check e.g. es3, ios, etc.
|
||||
* @param platform the asset platform to check e.g. android, ios, etc.
|
||||
* @return true if enabled, false otherwise
|
||||
*/
|
||||
virtual bool IsAssetPlatformEnabled(const char* platform) = 0;
|
||||
|
||||
/**
|
||||
* Get the total number of pending assets left to process for a specific asset platform
|
||||
* @param platform the asset platform to check e.g. es3, ios, etc.
|
||||
* @param platform the asset platform to check e.g. android, ios, etc.
|
||||
* @return -1 if the process fails, a positive number otherwise
|
||||
*/
|
||||
virtual int GetPendingAssetsForPlatform(const char* platform) = 0;
|
||||
@@ -302,7 +312,7 @@ namespace AzToolsFramework
|
||||
inline const char* GetHostAssetPlatform()
|
||||
{
|
||||
#if defined(AZ_PLATFORM_MAC)
|
||||
return "osx_gl";
|
||||
return "mac";
|
||||
#elif defined(AZ_PLATFORM_WINDOWS)
|
||||
return "pc";
|
||||
#elif defined(AZ_PLATFORM_LINUX)
|
||||
|
||||
@@ -52,6 +52,21 @@ namespace AzToolsFramework
|
||||
* Deletes all entities in the provided list, as well as their transform descendants.
|
||||
*/
|
||||
virtual void DeleteEntitiesAndAllDescendants(const EntityIdList& entities) = 0;
|
||||
|
||||
/**
|
||||
* Duplicate all currently-selected entities.
|
||||
*/
|
||||
virtual void DuplicateSelected() = 0;
|
||||
|
||||
/**
|
||||
* Duplicates the specified entity.
|
||||
*/
|
||||
virtual void DuplicateEntityById(AZ::EntityId entityId) = 0;
|
||||
|
||||
/**
|
||||
* Duplicates all specified entities.
|
||||
*/
|
||||
virtual void DuplicateEntities(const EntityIdList& entities) = 0;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+80
@@ -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.
|
||||
*/
|
||||
|
||||
+20
-2
@@ -43,7 +43,7 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorEntityManager::DeleteEntityById(AZ::EntityId entityId)
|
||||
{
|
||||
DeleteEntities({entityId});
|
||||
DeleteEntities(EntityIdList{ entityId });
|
||||
}
|
||||
|
||||
void EditorEntityManager::DeleteEntities(const EntityIdList& entities)
|
||||
@@ -53,12 +53,30 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorEntityManager::DeleteEntityAndAllDescendants(AZ::EntityId entityId)
|
||||
{
|
||||
DeleteEntitiesAndAllDescendants({entityId});
|
||||
DeleteEntitiesAndAllDescendants(EntityIdList{ entityId });
|
||||
}
|
||||
|
||||
void EditorEntityManager::DeleteEntitiesAndAllDescendants(const EntityIdList& entities)
|
||||
{
|
||||
m_prefabPublicInterface->DeleteEntitiesAndAllDescendantsInInstance(entities);
|
||||
}
|
||||
|
||||
void EditorEntityManager::DuplicateSelected()
|
||||
{
|
||||
EntityIdList selectedEntities;
|
||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities);
|
||||
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
|
||||
}
|
||||
|
||||
void EditorEntityManager::DuplicateEntityById(AZ::EntityId entityId)
|
||||
{
|
||||
DuplicateEntities(EntityIdList{ entityId });
|
||||
}
|
||||
|
||||
void EditorEntityManager::DuplicateEntities(const EntityIdList& entities)
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace AzToolsFramework
|
||||
void DeleteEntities(const EntityIdList& entities) override;
|
||||
void DeleteEntityAndAllDescendants(AZ::EntityId entityId) override;
|
||||
void DeleteEntitiesAndAllDescendants(const EntityIdList& entities) override;
|
||||
void DuplicateSelected() override;
|
||||
void DuplicateEntityById(AZ::EntityId entityId) override;
|
||||
void DuplicateEntities(const EntityIdList& entities) override;
|
||||
|
||||
private:
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+12
-1
@@ -81,9 +81,20 @@ namespace AzToolsFramework
|
||||
|
||||
m_ui->m_assetBrowserTreeViewWidget->SetName("AssetBrowserTreeView_" + name);
|
||||
|
||||
bool selectedAsset = false;
|
||||
|
||||
for (auto& assetId : selection.GetSelectedAssetIds())
|
||||
{
|
||||
m_ui->m_assetBrowserTreeViewWidget->SelectProduct(assetId);
|
||||
if (assetId.IsValid())
|
||||
{
|
||||
selectedAsset = true;
|
||||
m_ui->m_assetBrowserTreeViewWidget->SelectProduct(assetId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedAsset)
|
||||
{
|
||||
m_ui->m_assetBrowserTreeViewWidget->SelectFolder(selection.GetDefaultDirectory());
|
||||
}
|
||||
|
||||
setWindowTitle(tr("Pick %1").arg(m_selection.GetTitle()));
|
||||
|
||||
@@ -93,6 +93,16 @@ namespace AzToolsFramework
|
||||
m_selectedAssetIds.push_back(selectedAssetId);
|
||||
}
|
||||
|
||||
void AssetSelectionModel::SetDefaultDirectory(AZStd::string_view defaultDirectory)
|
||||
{
|
||||
m_defaultDirectory = defaultDirectory;
|
||||
}
|
||||
|
||||
AZStd::string_view AssetSelectionModel::GetDefaultDirectory() const
|
||||
{
|
||||
return m_defaultDirectory;
|
||||
}
|
||||
|
||||
AZStd::vector<const AssetBrowserEntry*>& AssetSelectionModel::GetResults()
|
||||
{
|
||||
return m_results;
|
||||
|
||||
@@ -47,6 +47,9 @@ namespace AzToolsFramework
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetSelectedAssetIds() const;
|
||||
void SetSelectedAssetIds(const AZStd::vector<AZ::Data::AssetId>& selectedAssetIds);
|
||||
void SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId);
|
||||
|
||||
void SetDefaultDirectory(AZStd::string_view defaultDirectory);
|
||||
AZStd::string_view GetDefaultDirectory() const;
|
||||
|
||||
AZStd::vector<const AssetBrowserEntry*>& GetResults();
|
||||
const AssetBrowserEntry* GetResult();
|
||||
@@ -72,6 +75,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::vector<AZ::Data::AssetId> m_selectedAssetIds;
|
||||
AZStd::vector<const AssetBrowserEntry*> m_results;
|
||||
AZStd::string m_defaultDirectory;
|
||||
|
||||
QString m_title;
|
||||
};
|
||||
|
||||
+45
-18
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
@@ -278,7 +279,20 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetBrowserTreeView::SelectEntry(const QModelIndex& idxParent, const AZStd::vector<AZStd::string>& entries, const uint32_t entryPathIndex)
|
||||
void AssetBrowserTreeView::SelectFolder(AZStd::string_view folderPath)
|
||||
{
|
||||
if (folderPath.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> entries;
|
||||
AZ::StringFunc::Tokenize(folderPath, entries, "/");
|
||||
|
||||
SelectEntry(QModelIndex(), entries, 0, true);
|
||||
}
|
||||
|
||||
bool AssetBrowserTreeView::SelectEntry(const QModelIndex& idxParent, const AZStd::vector<AZStd::string>& entries, const uint32_t entryPathIndex, bool useDisplayName)
|
||||
{
|
||||
if (entries.empty())
|
||||
{
|
||||
@@ -293,30 +307,43 @@ namespace AzToolsFramework
|
||||
auto rowIdx = model()->index(idx, 0, idxParent);
|
||||
auto rowEntry = GetEntryFromIndex<AssetBrowserEntry>(rowIdx);
|
||||
|
||||
// Check if this entry name matches the query
|
||||
if (rowEntry && AzFramework::StringFunc::Equal(entry.c_str(), rowEntry->GetName().c_str(), true))
|
||||
if (rowEntry)
|
||||
{
|
||||
// Final entry found - set it as the selected element
|
||||
if (entryPathIndex == entries.size() - 1)
|
||||
{
|
||||
selectionModel()->clear();
|
||||
selectionModel()->select(rowIdx, QItemSelectionModel::Select);
|
||||
setCurrentIndex(rowIdx);
|
||||
return true;
|
||||
}
|
||||
// Check if this entry name matches the query
|
||||
AZStd::string_view compareName = useDisplayName ? (const char*)(rowEntry->GetDisplayName().toUtf8()) : rowEntry->GetName().c_str();
|
||||
|
||||
// If this isn't the final entry, it needs to be a folder for the path to be valid (otherwise, early out)
|
||||
if (rowEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder)
|
||||
if (AzFramework::StringFunc::Equal(entry.c_str(), compareName, true))
|
||||
{
|
||||
// Folder found - if the final entry is found, expand this folder so the final entry is viewable in the Asset Browser (otherwise, early out)
|
||||
if (SelectEntry(rowIdx, entries, entryPathIndex + 1))
|
||||
// Final entry found - set it as the selected element
|
||||
if (entryPathIndex == entries.size() - 1)
|
||||
{
|
||||
expand(rowIdx);
|
||||
if (rowEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder)
|
||||
{
|
||||
// Expand the item itself if it is a folder
|
||||
expand(rowIdx);
|
||||
}
|
||||
|
||||
selectionModel()->clear();
|
||||
selectionModel()->select(rowIdx, QItemSelectionModel::Select);
|
||||
setCurrentIndex(rowIdx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this isn't the final entry, it needs to be a folder for the path to be valid (otherwise, early out)
|
||||
if (rowEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder)
|
||||
{
|
||||
// Folder found - if the final entry is found, expand this folder so the final entry is viewable in the Asset
|
||||
// Browser (otherwise, early out)
|
||||
if (SelectEntry(rowIdx, entries, entryPathIndex + 1, useDisplayName))
|
||||
{
|
||||
expand(rowIdx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -60,6 +60,8 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::vector<AssetBrowserEntry*> GetSelectedAssets() const;
|
||||
|
||||
void SelectFolder(AZStd::string_view folderPath);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetBrowserViewRequestBus
|
||||
void SelectProduct(AZ::Data::AssetId assetID) override;
|
||||
@@ -67,6 +69,7 @@ namespace AzToolsFramework
|
||||
void ClearFilter() override;
|
||||
|
||||
void Update() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -105,7 +108,7 @@ namespace AzToolsFramework
|
||||
QString m_name;
|
||||
|
||||
bool SelectProduct(const QModelIndex& idxParent, AZ::Data::AssetId assetID);
|
||||
bool SelectEntry(const QModelIndex& idxParent, const AZStd::vector<AZStd::string>& entryPathTokens, const uint32_t entryPathIndex = 0);
|
||||
bool SelectEntry(const QModelIndex& idxParent, const AZStd::vector<AZStd::string>& entryPathTokens, const uint32_t entryPathIndex = 0, bool useDisplayName = false);
|
||||
|
||||
//! Grab one entry from the source thumbnail list and update it
|
||||
void UpdateSCThumbnails();
|
||||
|
||||
@@ -483,6 +483,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
m_dirty = false;
|
||||
|
||||
AddRecentPath(targetFilePath);
|
||||
|
||||
SetStatusText(Status::assetCreated);
|
||||
|
||||
+2
@@ -56,5 +56,7 @@ namespace AzToolsFramework
|
||||
|
||||
virtual void StartPlayInEditor() = 0;
|
||||
virtual void StopPlayInEditor() = 0;
|
||||
|
||||
virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
+88
-14
@@ -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>
|
||||
@@ -55,7 +57,6 @@ namespace AzToolsFramework
|
||||
"Couldn't get prefab loader interface, it's a requirement for PrefabEntityOwnership system to work");
|
||||
|
||||
m_rootInstance = AZStd::unique_ptr<Prefab::Instance>(m_prefabSystemComponent->CreatePrefab({}, {}, "NewLevel.prefab"));
|
||||
|
||||
m_sliceOwnershipService.BusConnect(m_entityContextId);
|
||||
m_sliceOwnershipService.m_shouldAssertForLegacySlicesUsage = m_shouldAssertForLegacySlicesUsage;
|
||||
m_editorSliceOwnershipService.BusConnect();
|
||||
@@ -89,14 +90,17 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabEditorEntityOwnershipService::Reset()
|
||||
{
|
||||
Prefab::TemplateId templateId = m_rootInstance->GetTemplateId();
|
||||
if (templateId != Prefab::InvalidTemplateId)
|
||||
if (m_rootInstance)
|
||||
{
|
||||
m_rootInstance->SetTemplateId(Prefab::InvalidTemplateId);
|
||||
m_prefabSystemComponent->RemoveTemplate(templateId);
|
||||
Prefab::TemplateId templateId = m_rootInstance->GetTemplateId();
|
||||
if (templateId != Prefab::InvalidTemplateId)
|
||||
{
|
||||
m_rootInstance->SetTemplateId(Prefab::InvalidTemplateId);
|
||||
m_prefabSystemComponent->RemoveTemplate(templateId);
|
||||
}
|
||||
m_rootInstance->Reset();
|
||||
m_rootInstance->SetContainerEntityName("Level");
|
||||
}
|
||||
m_rootInstance->Reset();
|
||||
m_rootInstance->SetContainerEntityName("Level");
|
||||
|
||||
AzFramework::EntityOwnershipServiceNotificationBus::Event(
|
||||
m_entityContextId, &AzFramework::EntityOwnershipServiceNotificationBus::Events::OnEntityOwnershipServiceReset);
|
||||
@@ -200,7 +204,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_rootInstance->SetTemplateId(templateId);
|
||||
m_rootInstance->SetTemplateSourcePath(m_loaderInterface->GetRelativePathToProject(filename));
|
||||
m_rootInstance->SetTemplateSourcePath(m_loaderInterface->GenerateRelativePath(filename));
|
||||
m_rootInstance->SetContainerEntityName("Level");
|
||||
m_prefabSystemComponent->PropagateTemplateChanges(templateId);
|
||||
|
||||
@@ -218,16 +222,15 @@ namespace AzToolsFramework
|
||||
|
||||
bool PrefabEditorEntityOwnershipService::SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename)
|
||||
{
|
||||
AZ::IO::Path relativePath = m_loaderInterface->GetRelativePathToProject(filename);
|
||||
AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(filename);
|
||||
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 +239,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 +267,71 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename)
|
||||
{
|
||||
AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(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, templateFilename.c_str(),
|
||||
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, 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)
|
||||
@@ -311,7 +380,12 @@ namespace AzToolsFramework
|
||||
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::GetRootPrefabInstance()
|
||||
{
|
||||
AZ_Assert(m_rootInstance, "A valid root prefab instance couldn't be found in PrefabEditorEntityOwnershipService.");
|
||||
return *m_rootInstance;
|
||||
if (m_rootInstance)
|
||||
{
|
||||
return *m_rootInstance;
|
||||
}
|
||||
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData()
|
||||
|
||||
+2
@@ -170,6 +170,8 @@ namespace AzToolsFramework
|
||||
void StartPlayInEditor() override;
|
||||
void StopPlayInEditor() override;
|
||||
|
||||
void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) override;
|
||||
|
||||
protected:
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress GetOwningSlice() override;
|
||||
|
||||
+1
-1
@@ -614,7 +614,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::Quaternion oldEntityRotation;
|
||||
AZ::TransformBus::EventResult(oldEntityRotation, id, &AZ::TransformBus::Events::GetWorldRotationQuaternion);
|
||||
transformComponent->SetRotationQuaternion(oldEntityRotation);
|
||||
transformComponent->SetWorldRotationQuaternion(oldEntityRotation);
|
||||
|
||||
// Ensure the existing hierarchy is maintained
|
||||
AZ::EntityId oldParentEntityId;
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ namespace AzToolsFramework
|
||||
rayProportion, lineSegmentProportion, worldClosestPositionRay, worldClosestPositionLineSegment);
|
||||
|
||||
AZ::Transform worldFromLocalNormalized = worldFromLocal;
|
||||
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractScale() * nonUniformScale;
|
||||
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractUniformScale() * nonUniformScale;
|
||||
const AZ::Transform localFromWorldNormalized = worldFromLocalNormalized.GetInverse();
|
||||
|
||||
return { (localFromWorldNormalized.TransformPoint(worldClosestPositionLineSegment)) / scale };
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace AzToolsFramework
|
||||
? CalculateSnappedOffset(localTransform.GetTranslation(), axis, gridSize * scaleRecip)
|
||||
: AZ::Vector3::CreateZero();
|
||||
|
||||
const AZ::Vector3 localScale = localTransform.GetScale();
|
||||
const AZ::Vector3 localScale = AZ::Vector3(localTransform.GetUniformScale());
|
||||
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
|
||||
// calculate scale amount to snap, to align to round scale value
|
||||
const AZ::Vector3 scaleSnapOffset = snapping && !gridSnapAction.m_localSnapping
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace AzToolsFramework
|
||||
/// noise in the value returned when dealing with values far from the origin.
|
||||
inline float ScaleReciprocal(const AZ::Transform& transform)
|
||||
{
|
||||
return Round3(transform.GetScale().GetReciprocal().GetMinElement());
|
||||
return Round3(1.0f / transform.GetUniformScale());
|
||||
}
|
||||
|
||||
/// Find the reciprocal of the non-uniform scale.
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace AzToolsFramework
|
||||
AZ::Transform result;
|
||||
result.SetRotation(m_space.GetRotation() * localTransform.GetRotation());
|
||||
result.SetTranslation(m_space.TransformPoint(m_nonUniformScale * localTransform.GetTranslation()));
|
||||
result.SetScale(m_space.GetScale() * localTransform.GetScale());
|
||||
result.SetUniformScale(m_space.GetUniformScale() * localTransform.GetUniformScale());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -447,17 +447,14 @@ namespace AzToolsFramework
|
||||
m_radius * viewScale);
|
||||
|
||||
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
|
||||
|
||||
// show wireframe if the axis has been corrected/flipped
|
||||
// note: please see IRenderAuxGeom.h for the definition of e_FillModeWireframe and e_FillModeSolid.
|
||||
// it is not possible to include IRenderAuxGeom from here and we also don't want to introduce that dependency.
|
||||
// these legacy enums should be wrapped so set SetFillMode can be used in a type safe way, until then,
|
||||
// use the values directly until the API has been updated.
|
||||
const AZ::u32 prevFillMode = debugDisplay.SetFillMode(
|
||||
m_shouldCorrect ? /*e_FillModeWireframe =*/ 0x1 << 26 : /*e_FillModeSolid =*/ 0);
|
||||
|
||||
debugDisplay.DrawCone(coneBound.m_base, coneBound.m_axis, coneBound.m_radius, coneBound.m_height, false);
|
||||
debugDisplay.SetFillMode(prevFillMode);
|
||||
if (m_shouldCorrect)
|
||||
{
|
||||
debugDisplay.DrawWireCone(coneBound.m_base, coneBound.m_axis, coneBound.m_radius, coneBound.m_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugDisplay.DrawSolidCone(coneBound.m_base, coneBound.m_axis, coneBound.m_radius, coneBound.m_height, false);
|
||||
}
|
||||
|
||||
RefreshBoundInternal(managerId, manipulatorId, coneBound);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ namespace AzToolsFramework
|
||||
"PrefabLoaderInterface could not be found. It is required to load Prefab Instances");
|
||||
|
||||
// Make sure we have a relative path
|
||||
instance->m_templateSourcePath = loaderInterface->GetRelativePathToProject(instance->m_templateSourcePath);
|
||||
instance->m_templateSourcePath = loaderInterface->GenerateRelativePath(instance->m_templateSourcePath);
|
||||
|
||||
TemplateId templateId = prefabSystemComponentInterface->GetTemplateIdFromFilePath(instance->GetTemplateSourcePath());
|
||||
|
||||
|
||||
+8
-12
@@ -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:
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace AzToolsFramework
|
||||
inline static const char* PatchesName = "Patches";
|
||||
inline static const char* SourceName = "Source";
|
||||
inline static const char* LinkIdName = "LinkId";
|
||||
inline static const char* EntityIdName = "Id";
|
||||
inline static const char* EntitiesName = "Entities";
|
||||
inline static const char* ContainerEntityName = "ContainerEntity";
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
@@ -41,7 +43,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);
|
||||
@@ -112,7 +114,7 @@ namespace AzToolsFramework
|
||||
return InvalidTemplateId;
|
||||
}
|
||||
|
||||
AZ::IO::Path relativePath = GetRelativePathToProject(originPath);
|
||||
AZ::IO::Path relativePath = GenerateRelativePath(originPath);
|
||||
|
||||
// Cyclical dependency detected if the prefab file is already part of the progressed
|
||||
// file path set.
|
||||
@@ -301,6 +303,45 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrefabLoader::SaveTemplateToFile(TemplateId templateId, AZ::IO::PathView absolutePath)
|
||||
{
|
||||
AZ_Assert(absolutePath.IsAbsolute(), "SaveTemplateToFile requires an absolute path for saving the initial prefab file.");
|
||||
|
||||
const auto& domAndFilepath = StoreTemplateIntoFileFormat(templateId);
|
||||
if (!domAndFilepath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that the absolute path provided to this matches the relative path saved in the template.
|
||||
// Otherwise, the saved prefab won't be able to be loaded.
|
||||
auto relativePath = GenerateRelativePath(absolutePath);
|
||||
if (relativePath != domAndFilepath->second)
|
||||
{
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
"PrefabLoader::SaveTemplateToFile - "
|
||||
"Failed to save template '%s' to location '%.*s'."
|
||||
"Error: Relative path '%.*s' for location didn't match template name.",
|
||||
domAndFilepath->second.c_str(), AZ_STRING_ARG(absolutePath.Native()), AZ_STRING_ARG(relativePath.Native()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto outcome = AzFramework::FileFunc::WriteJsonFile(domAndFilepath->first, absolutePath);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
"PrefabLoader::SaveTemplateToFile - "
|
||||
"Failed to save template '%s' to location '%.*s'."
|
||||
"Error: %s",
|
||||
domAndFilepath->second.c_str(), AZ_STRING_ARG(absolutePath.Native()), outcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrefabLoader::SaveTemplateToString(TemplateId templateId, AZStd::string& output)
|
||||
{
|
||||
const auto& domAndFilepath = StoreTemplateIntoFileFormat(templateId);
|
||||
@@ -385,21 +426,100 @@ namespace AzToolsFramework
|
||||
AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path).MakePreferred();
|
||||
if (pathWithOSSeparator.IsAbsolute())
|
||||
{
|
||||
// If an absolute path was passed in, just return it as-is.
|
||||
return path;
|
||||
}
|
||||
|
||||
return AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator);
|
||||
// A relative path was passed in, so try to turn it back into an absolute path.
|
||||
|
||||
AZ::IO::Path fullPath;
|
||||
|
||||
bool pathFound = false;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AZStd::string rootFolder;
|
||||
AZStd::string inputPath(path.Native());
|
||||
|
||||
// Given an input path that's expected to exist, try to look it up.
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
pathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
|
||||
inputPath.c_str(), assetInfo, rootFolder);
|
||||
|
||||
if (pathFound)
|
||||
{
|
||||
// The asset system provided us with a valid root folder and relative path, so return it.
|
||||
fullPath = AZ::IO::Path(rootFolder) / assetInfo.m_relativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If for some reason the Asset system couldn't provide a relative path, provide some fallback logic.
|
||||
|
||||
// Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow
|
||||
// the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside
|
||||
// a unit test, so just execute the fallback logic without an error.
|
||||
[[maybe_unused]] bool assetProcessorReady = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.",
|
||||
AZ_STRING_ARG(path.Native()));
|
||||
|
||||
// If a relative path was passed in, make it relative to the project root.
|
||||
fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator);
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
AZ::IO::Path PrefabLoader::GetRelativePathToProject(AZ::IO::PathView path)
|
||||
AZ::IO::Path PrefabLoader::GenerateRelativePath(AZ::IO::PathView path)
|
||||
{
|
||||
AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path.Native()).MakePreferred();
|
||||
if (!pathWithOSSeparator.IsAbsolute())
|
||||
bool pathFound = false;
|
||||
|
||||
AZStd::string relativePath;
|
||||
AZStd::string rootFolder;
|
||||
AZ::IO::Path finalPath;
|
||||
|
||||
// The asset system allows for paths to be relative to multiple root folders, using a priority system.
|
||||
// This request will make the input path relative to the most appropriate, highest-priority root folder.
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
pathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GenerateRelativeSourcePath, path.Native(),
|
||||
relativePath, rootFolder);
|
||||
|
||||
if (pathFound && !relativePath.empty())
|
||||
{
|
||||
return path;
|
||||
// A relative path was generated successfully, so return it.
|
||||
finalPath = relativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If for some reason the Asset system couldn't provide a relative path, provide some fallback logic.
|
||||
|
||||
// Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow
|
||||
// the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside
|
||||
// a unit test, so just execute the fallback logic without an error.
|
||||
[[maybe_unused]] bool assetProcessorReady = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady);
|
||||
|
||||
AZ_Error("Prefab", !assetProcessorReady,
|
||||
"Relative source path for '%.*s' could not be determined. Using project path as relative root.",
|
||||
AZ_STRING_ARG(path.Native()));
|
||||
|
||||
AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path.Native()).MakePreferred();
|
||||
|
||||
if (pathWithOSSeparator.IsAbsolute())
|
||||
{
|
||||
// If an absolute path was passed in, make it relative to the project path.
|
||||
finalPath = AZ::IO::Path(path.Native(), '/').MakePreferred().LexicallyRelative(m_projectPathWithSlashSeparator);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a relative path was passed in, just return it.
|
||||
finalPath = path;
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::IO::Path(path.Native(), '/').MakePreferred().LexicallyRelative(m_projectPathWithSlashSeparator);
|
||||
return finalPath;
|
||||
}
|
||||
|
||||
AZ::IO::Path PrefabLoaderInterface::GeneratePath()
|
||||
|
||||
@@ -72,6 +72,16 @@ namespace AzToolsFramework
|
||||
*/
|
||||
bool SaveTemplate(TemplateId templateId) override;
|
||||
|
||||
/**
|
||||
* Saves a Prefab Template to the provided absolute source path, which needs to match the relative path in the template.
|
||||
* Converts Prefab Template form into .prefab form by collapsing nested Template info
|
||||
* into a source path and patches.
|
||||
* @param templateId Id of the template to be saved
|
||||
* @param absolutePath Absolute path to save the file to
|
||||
* @return bool on whether the operation succeeded or not
|
||||
*/
|
||||
bool SaveTemplateToFile(TemplateId templateId, AZ::IO::PathView absolutePath) override;
|
||||
|
||||
/**
|
||||
* Saves a Prefab Template into the provided output string.
|
||||
* Converts Prefab Template form into .prefab form by collapsing nested Template info
|
||||
@@ -91,9 +101,11 @@ namespace AzToolsFramework
|
||||
//! The path will always have the correct separator for the current OS
|
||||
AZ::IO::Path GetFullPath(AZ::IO::PathView path) override;
|
||||
|
||||
//! Converts path into a relative path to the project, this will be the paths in .prefab file.
|
||||
//! The path will always have '/' separator.
|
||||
AZ::IO::Path GetRelativePathToProject(AZ::IO::PathView path) override;
|
||||
//! Converts path into a path that's relative to the highest-priority containing folder of all the folders registered
|
||||
//! with the engine.
|
||||
//! This path will be the path that appears in the .prefab file.
|
||||
//! The path will always use the '/' separator.
|
||||
AZ::IO::Path GenerateRelativePath(AZ::IO::PathView path) override;
|
||||
|
||||
//! Returns if the path is a valid path for a prefab
|
||||
static bool IsValidPrefabPath(AZ::IO::PathView path);
|
||||
|
||||
@@ -60,6 +60,16 @@ namespace AzToolsFramework
|
||||
*/
|
||||
virtual bool SaveTemplate(TemplateId templateId) = 0;
|
||||
|
||||
/**
|
||||
* Saves a Prefab Template to the provided absolute source path, which needs to match the relative path in the template.
|
||||
* Converts Prefab Template form into .prefab form by collapsing nested Template info
|
||||
* into a source path and patches.
|
||||
* @param templateId Id of the template to be saved
|
||||
* @param absolutePath Absolute path to save the file to
|
||||
* @return bool on whether the operation succeeded or not
|
||||
*/
|
||||
virtual bool SaveTemplateToFile(TemplateId templateId, AZ::IO::PathView absolutePath) = 0;
|
||||
|
||||
/**
|
||||
* Saves a Prefab Template into the provided output string.
|
||||
* Converts Prefab Template form into .prefab form by collapsing nested Template info
|
||||
@@ -74,9 +84,11 @@ namespace AzToolsFramework
|
||||
//! The path will always have the correct separator for the current OS
|
||||
virtual AZ::IO::Path GetFullPath(AZ::IO::PathView path) = 0;
|
||||
|
||||
//! Converts path into a relative path to the current project, this will be the paths in .prefab file.
|
||||
//! The path will always have '/' separator.
|
||||
virtual AZ::IO::Path GetRelativePathToProject(AZ::IO::PathView path) = 0;
|
||||
//! Converts path into a path that's relative to the highest-priority containing folder of all the folders registered
|
||||
//! with the engine.
|
||||
//! This path will be the path that appears in the .prefab file.
|
||||
//! The path will always use the '/' separator.
|
||||
virtual AZ::IO::Path GenerateRelativePath(AZ::IO::PathView path) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/JSON/stringbuffer.h>
|
||||
#include <AzCore/JSON/writer.h>
|
||||
#include <AzCore/Utils/TypeHash.h>
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
@@ -26,11 +26,14 @@
|
||||
#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>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
@@ -61,7 +64,7 @@ namespace AzToolsFramework
|
||||
m_prefabUndoCache.Destroy();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath)
|
||||
{
|
||||
EntityList inputEntityList, topLevelEntities;
|
||||
AZ::EntityId commonRootEntityId;
|
||||
@@ -73,6 +76,8 @@ namespace AzToolsFramework
|
||||
return findCommonRootOutcome;
|
||||
}
|
||||
|
||||
AZ_Assert(absolutePath.IsAbsolute(), "CreatePrefab requires an absolute path for saving the initial prefab file.");
|
||||
|
||||
InstanceOptionalReference instanceToCreate;
|
||||
{
|
||||
// Initialize Undo Batch object
|
||||
@@ -83,7 +88,8 @@ namespace AzToolsFramework
|
||||
commonRootInstanceDomBeforeCreate, commonRootEntityOwningInstance->get());
|
||||
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> instances;
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> instancePtrs;
|
||||
AZStd::vector<Instance*> instances;
|
||||
AZStd::unordered_map<Instance*, PrefabDom> nestedInstanceLinkPatchesMap;
|
||||
|
||||
// Retrieve all entities affected and identify Instances
|
||||
@@ -93,21 +99,38 @@ 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();
|
||||
}
|
||||
|
||||
// When we create a prefab with other prefab instances, we have to remove the existing links between the source and
|
||||
// target templates of the other instances.
|
||||
for (auto& nestedInstance : instances)
|
||||
{
|
||||
auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstance->GetLinkId());
|
||||
AZStd::unique_ptr<Instance> outInstance = commonRootEntityOwningInstance->get().DetachNestedInstance(nestedInstance->GetInstanceAlias());
|
||||
|
||||
if (linkRef.has_value())
|
||||
{
|
||||
PrefabDom oldLinkPatches;
|
||||
oldLinkPatches.CopyFrom(linkRef->get().GetLinkDom(), oldLinkPatches.GetAllocator());
|
||||
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);
|
||||
|
||||
nestedInstanceLinkPatchesMap.emplace(nestedInstance.get(), AZStd::move(oldLinkPatches));
|
||||
}
|
||||
PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches();
|
||||
AZ_Assert(
|
||||
linkPatches.has_value(), "Unable to get patches on link with id '%llu' during prefab creation.",
|
||||
detachingInstanceLinkId);
|
||||
|
||||
PrefabDom linkPatchesCopy;
|
||||
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
|
||||
nestedInstanceLinkPatchesMap.emplace(nestedInstance, AZStd::move(linkPatchesCopy));
|
||||
|
||||
RemoveLink(nestedInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
|
||||
RemoveLink(outInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
|
||||
|
||||
instancePtrs.emplace_back(AZStd::move(outInstance));
|
||||
}
|
||||
|
||||
PrefabUndoHelpers::UpdatePrefabInstance(
|
||||
@@ -123,7 +146,8 @@ namespace AzToolsFramework
|
||||
|
||||
// Create the Prefab
|
||||
instanceToCreate = prefabEditorEntityOwnershipInterface->CreatePrefab(
|
||||
entities, AZStd::move(instances), filePath, commonRootEntityOwningInstance);
|
||||
entities, AZStd::move(instancePtrs), m_prefabLoaderInterface->GenerateRelativePath(absolutePath),
|
||||
commonRootEntityOwningInstance);
|
||||
|
||||
if (!instanceToCreate)
|
||||
{
|
||||
@@ -167,6 +191,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
|
||||
@@ -188,36 +230,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
|
||||
{
|
||||
@@ -228,7 +257,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
// Save Template to file
|
||||
m_prefabLoaderInterface->SaveTemplate(instanceToCreate->get().GetTemplateId());
|
||||
m_prefabLoaderInterface->SaveTemplateToFile(instanceToCreate->get().GetTemplateId(), absolutePath);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
@@ -292,7 +321,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
//Detect whether this instantiation would produce a cyclical dependency
|
||||
auto relativePath = m_prefabLoaderInterface->GetRelativePathToProject(filePath);
|
||||
auto relativePath = m_prefabLoaderInterface->GenerateRelativePath(filePath);
|
||||
Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
|
||||
|
||||
if (templateId == InvalidTemplateId)
|
||||
@@ -388,7 +417,7 @@ namespace AzToolsFramework
|
||||
// Find common root and top level entities
|
||||
bool entitiesHaveCommonRoot = false;
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
entitiesHaveCommonRoot, &AzToolsFramework::ToolsApplicationRequests::FindCommonRootInactive, inputEntityList,
|
||||
commonRootEntityId, &topLevelEntities);
|
||||
|
||||
@@ -710,6 +739,143 @@ namespace AzToolsFramework
|
||||
return DeleteFromInstance(entityIds, true);
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::DuplicateEntitiesInInstance(const EntityIdList& entityIds)
|
||||
{
|
||||
if (entityIds.empty())
|
||||
{
|
||||
return AZ::Failure(AZStd::string("No entities to duplicate."));
|
||||
}
|
||||
|
||||
if (!EntitiesBelongToSameInstance(entityIds))
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Cannot duplicate multiple "
|
||||
"entities belonging to different instances with one operation."));
|
||||
}
|
||||
|
||||
// We've already verified the entities are all owned by the same instance,
|
||||
// so we can just retrieve our instance from the first entity in the list.
|
||||
InstanceOptionalReference commonEntityOwningInstance = GetOwnerInstanceByEntityId(entityIds[0]);
|
||||
AZ_Assert(
|
||||
commonEntityOwningInstance.has_value(),
|
||||
"Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided");
|
||||
|
||||
// This will cull out any entities that have ancestors in the list, since we will end up duplicating
|
||||
// the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances
|
||||
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIds);
|
||||
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
ScopedUndoBatch undoBatch("Duplicate Entities");
|
||||
|
||||
{
|
||||
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "DuplicateEntitiesInInstance::UndoCaptureAndDuplicateEntities");
|
||||
|
||||
// Take a snapshot of the instance DOM before we manipulate it
|
||||
Prefab::PrefabDom instanceDomBefore;
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonEntityOwningInstance->get());
|
||||
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
AZStd::vector<Instance*> instances;
|
||||
|
||||
// Gather all entities/instances in the hierarchy, but don't detach them because we are duplicating not deleting.
|
||||
EntityList inputEntityList = EntityIdSetToEntityList(duplicationSet);
|
||||
bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonEntityOwningInstance->get(), entities, instances);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Failed to retrieve entities and instances from the given list of entity ids for duplication"));
|
||||
}
|
||||
|
||||
// Make a copy of our before instance DOM where we will add our duplicated entities
|
||||
Prefab::PrefabDom instanceDomAfter;
|
||||
instanceDomAfter.CopyFrom(instanceDomBefore, instanceDomAfter.GetAllocator());
|
||||
|
||||
AZStd::unordered_map<EntityAlias, EntityAlias> oldAliasToNewAliasMap;
|
||||
AZStd::unordered_map<EntityAlias, QString> aliasToEntityDomMap;
|
||||
|
||||
for (AZ::Entity* entity : entities)
|
||||
{
|
||||
EntityAliasOptionalReference oldAliasRef = commonEntityOwningInstance->get().GetEntityAlias(entity->GetId());
|
||||
AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM");
|
||||
EntityAlias oldAlias = oldAliasRef.value();
|
||||
|
||||
// Give this the outer allocator so that the memory reference will be valid when
|
||||
// it gets used for AddMember
|
||||
Prefab::PrefabDom entityDomBefore(&instanceDomAfter.GetAllocator());
|
||||
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity);
|
||||
|
||||
// Keep track of the old alias <-> new alias mapping for this duplicated entity
|
||||
// so we can fixup references later
|
||||
EntityAlias newEntityAlias = Instance::GenerateEntityAlias();
|
||||
oldAliasToNewAliasMap.insert(AZStd::make_pair(oldAlias, newEntityAlias));
|
||||
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
entityDomBefore.Accept(writer);
|
||||
|
||||
// Store our duplicated Entity DOM with its new alias as a string
|
||||
// so that we can fixup entity alias references before adding it
|
||||
// to the Entities member of our instance DOM
|
||||
QString entityDomString(buffer.GetString());
|
||||
aliasToEntityDomMap.insert(AZStd::make_pair(newEntityAlias, entityDomString));
|
||||
}
|
||||
|
||||
auto entitiesIter = instanceDomAfter.FindMember(PrefabDomUtils::EntitiesName);
|
||||
AZ_Assert(entitiesIter != instanceDomAfter.MemberEnd(), "Instance DOM missing the Entities member.");
|
||||
|
||||
// Now that all the duplicated Entity DOMs have been created, we need to iterate
|
||||
// through them and replace any previous EntityAlias references with the new ones.
|
||||
// These are more than just parent entity references for nested entities, this will
|
||||
// also cover any EntityId references that were made in the components between them.
|
||||
for (auto aliasEntityPair : aliasToEntityDomMap)
|
||||
{
|
||||
EntityAlias newEntityAlias = aliasEntityPair.first;
|
||||
QString newEntityDomString = aliasEntityPair.second;
|
||||
|
||||
// Replace all of the old alias references with the new ones
|
||||
// We bookend the aliases with \" and also with a / as an extra precaution to prevent
|
||||
// inadvertently replacing a matching string vs. where an actual EntityId is expected
|
||||
// This will cover both cases where an alias could be used in a normal entity vs. an instance
|
||||
for (auto aliasMapIter : oldAliasToNewAliasMap)
|
||||
{
|
||||
ReplaceOldAliases(newEntityDomString, aliasMapIter.first, aliasMapIter.second);
|
||||
}
|
||||
|
||||
// Create the new Entity DOM from parsing the JSON string
|
||||
Prefab::PrefabDom entityDomAfter(&instanceDomAfter.GetAllocator());
|
||||
entityDomAfter.Parse(newEntityDomString.toUtf8().constData());
|
||||
|
||||
// Add the new Entity DOM to the Entities member of the instance
|
||||
rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), instanceDomAfter.GetAllocator());
|
||||
entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, instanceDomAfter.GetAllocator());
|
||||
}
|
||||
|
||||
PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity duplication");
|
||||
command->SetParent(undoBatch.GetUndoBatch());
|
||||
command->Capture(instanceDomBefore, instanceDomAfter, commonEntityOwningInstance->get().GetTemplateId());
|
||||
command->RunRedo();
|
||||
|
||||
EntityIdList duplicatedEntityIds;
|
||||
for (auto aliasMapIter : oldAliasToNewAliasMap)
|
||||
{
|
||||
EntityAlias newEntityAlias = aliasMapIter.second;
|
||||
|
||||
AliasPath absoluteEntityPath = commonEntityOwningInstance->get().GetAbsoluteInstanceAliasPath();
|
||||
absoluteEntityPath.Append(newEntityAlias);
|
||||
|
||||
AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath);
|
||||
duplicatedEntityIds.push_back(newEntityId);
|
||||
}
|
||||
|
||||
// Select the duplicated entities
|
||||
auto selectionUndo = aznew SelectionCommand(duplicatedEntityIds, "Select Duplicated Entities");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants)
|
||||
{
|
||||
if (entityIds.empty())
|
||||
@@ -737,17 +903,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
UndoSystem::URSequencePoint* currentUndoBatch = nullptr;
|
||||
ToolsApplicationRequests::Bus::BroadcastResult(currentUndoBatch, &ToolsApplicationRequests::Bus::Events::GetCurrentUndoBatch);
|
||||
|
||||
bool createdUndo = false;
|
||||
if (!currentUndoBatch)
|
||||
{
|
||||
createdUndo = true;
|
||||
ToolsApplicationRequests::Bus::BroadcastResult(
|
||||
currentUndoBatch, &ToolsApplicationRequests::Bus::Events::BeginUndoBatch, "Delete Selected");
|
||||
AZ_Assert(currentUndoBatch, "Failed to create new undo batch.");
|
||||
}
|
||||
ScopedUndoBatch undoBatch("Delete Selected");
|
||||
|
||||
// In order to undo DeleteSelected, we have to create a selection command which selects the current selection
|
||||
// and then add the deletion as children.
|
||||
@@ -775,7 +931,7 @@ namespace AzToolsFramework
|
||||
if (deleteDescendants)
|
||||
{
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> instances;
|
||||
AZStd::vector<Instance*> instances;
|
||||
|
||||
bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
|
||||
|
||||
@@ -786,13 +942,15 @@ namespace AzToolsFramework
|
||||
|
||||
for (AZ::Entity* entity : entities)
|
||||
{
|
||||
commonOwningInstance->get().DetachEntity(entity->GetId()).release();
|
||||
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, entity->GetId());
|
||||
}
|
||||
|
||||
for (auto& nestedInstance : instances)
|
||||
{
|
||||
RemoveLink(nestedInstance, commonOwningInstance->get().GetTemplateId(), currentUndoBatch);
|
||||
nestedInstance.reset();
|
||||
AZStd::unique_ptr<Instance> outInstance = commonOwningInstance->get().DetachNestedInstance(nestedInstance->GetInstanceAlias());
|
||||
RemoveLink(outInstance, commonOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
|
||||
outInstance.reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -804,7 +962,7 @@ namespace AzToolsFramework
|
||||
if (owningInstance->get().GetContainerEntityId() == entityId)
|
||||
{
|
||||
auto instancePtr = commonOwningInstance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias());
|
||||
RemoveLink(instancePtr, commonOwningInstance->get().GetTemplateId(), currentUndoBatch);
|
||||
RemoveLink(instancePtr, commonOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -822,17 +980,12 @@ namespace AzToolsFramework
|
||||
command->SetParent(selCommand);
|
||||
}
|
||||
|
||||
selCommand->SetParent(currentUndoBatch);
|
||||
selCommand->SetParent(undoBatch.GetUndoBatch());
|
||||
{
|
||||
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DeleteEntities:RunRedo");
|
||||
selCommand->RunRedo();
|
||||
}
|
||||
|
||||
if (createdUndo)
|
||||
{
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::EndUndoBatch);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
@@ -944,7 +1097,7 @@ namespace AzToolsFramework
|
||||
|
||||
bool PrefabPublicHandler::RetrieveAndSortPrefabEntitiesAndInstances(
|
||||
const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
|
||||
EntityList& outEntities, AZStd::vector<AZStd::unique_ptr<Instance>>& outInstances) const
|
||||
EntityList& outEntities, AZStd::vector<Instance*>& outInstances) const
|
||||
{
|
||||
if (inputEntities.size() == 0)
|
||||
{
|
||||
@@ -1028,14 +1181,14 @@ namespace AzToolsFramework
|
||||
|
||||
for (AZ::Entity* entity : entities)
|
||||
{
|
||||
outEntities.emplace_back(commonRootEntityOwningInstance.DetachEntity(entity->GetId()).release());
|
||||
outEntities.emplace_back(entity);
|
||||
}
|
||||
|
||||
outInstances.clear();
|
||||
outInstances.reserve(instances.size());
|
||||
for (Instance* instancePtr : instances)
|
||||
{
|
||||
outInstances.push_back(AZStd::move(commonRootEntityOwningInstance.DetachNestedInstance(instancePtr->GetInstanceAlias())));
|
||||
outInstances.push_back(instancePtr);
|
||||
}
|
||||
|
||||
return (outEntities.size() + outInstances.size()) > 0;
|
||||
@@ -1086,5 +1239,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;
|
||||
@@ -44,7 +46,7 @@ namespace AzToolsFramework
|
||||
void UnregisterPrefabPublicHandlerInterface();
|
||||
|
||||
// PrefabPublicInterface...
|
||||
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
|
||||
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath) override;
|
||||
PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
PrefabOperationResult SavePrefab(AZ::IO::Path filePath) override;
|
||||
PrefabEntityResult CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) override;
|
||||
@@ -60,11 +62,12 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabOperationResult DeleteEntitiesInInstance(const EntityIdList& entityIds) override;
|
||||
PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) override;
|
||||
PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) override;
|
||||
|
||||
private:
|
||||
PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants);
|
||||
bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
|
||||
EntityList& outEntities, AZStd::vector<AZStd::unique_ptr<Instance>>& outInstances) const;
|
||||
EntityList& outEntities, AZStd::vector<Instance*>& outInstances) const;
|
||||
|
||||
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
|
||||
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
|
||||
@@ -129,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);
|
||||
|
||||
@@ -46,10 +46,10 @@ namespace AzToolsFramework
|
||||
* Create a prefab out of the entities provided, at the path provided.
|
||||
* Automatically detects descendants of entities, and discerns between entities and child instances.
|
||||
* @param entityIds The entities that should form the new prefab (along with their descendants).
|
||||
* @param filePath The path for the new prefab file.
|
||||
* @param filePath The absolute path for the new prefab file.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
@@ -143,6 +143,13 @@ namespace AzToolsFramework
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) = 0;
|
||||
|
||||
/**
|
||||
* Duplicates all entities in the owning instance. Bails if the entities don't all belong to the same instance.
|
||||
* @param entities The entities to duplicate.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) = 0;
|
||||
};
|
||||
|
||||
} // namespace Prefab
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace AzToolsFramework
|
||||
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
|
||||
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity, bool shouldCreateLinks)
|
||||
{
|
||||
AZ::IO::Path relativeFilePath = m_prefabLoader.GetRelativePathToProject(filePath);
|
||||
AZ::IO::Path relativeFilePath = m_prefabLoader.GenerateRelativePath(filePath);
|
||||
if (GetTemplateIdFromFilePath(relativeFilePath) != InvalidTemplateId)
|
||||
{
|
||||
AZ_Error("Prefab", false,
|
||||
|
||||
+2
-3
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
@@ -73,8 +73,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
|
||||
uint32_t ProcessedObjectStore::BuildSubId(AZStd::string_view id)
|
||||
{
|
||||
AZ::Uuid subIdHash = AZ::Uuid::CreateData(id.data(), id.size());
|
||||
return azlossy_caster(subIdHash.GetHash());
|
||||
return AzFramework::SpawnableAssetHandler::BuildSubId(id);
|
||||
}
|
||||
|
||||
const AZStd::string& ProcessedObjectStore::GetId() const
|
||||
|
||||
@@ -24,17 +24,6 @@
|
||||
|
||||
namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
{
|
||||
|
||||
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom)
|
||||
{
|
||||
AzFramework::Spawnable spawnable;
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> referencedAssets;
|
||||
[[maybe_unused]] bool result = CreateSpawnable(spawnable, prefabDom, referencedAssets);
|
||||
AZ_Assert(result,
|
||||
"Failed to Load Prefab Instance from given Prefab DOM while Spawnable creation.");
|
||||
return spawnable;
|
||||
}
|
||||
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom)
|
||||
{
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> referencedAssets;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
{
|
||||
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom);
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom);
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-20
@@ -1,22 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace AzToolsFramework
|
||||
To use the EditorComponentAdapter, 3 classes are required:
|
||||
- a class that implements the functions required for TController (see below)
|
||||
- a configuration struct/class which extends AZ::ComponentConfig
|
||||
- A runtime component that will be generated by the editor comoinent on export
|
||||
- A runtime component that will be generated by the editor component on export
|
||||
|
||||
The concrete component extends the adapter and implements behavior which is unique to the component.
|
||||
|
||||
@@ -64,15 +64,15 @@ namespace AzToolsFramework
|
||||
the EditContext. TController can friend itself to the editor component to make this work if required.
|
||||
*/
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration = AZ::ComponentConfig>
|
||||
class EditorComponentAdapter
|
||||
: public EditorComponentBase
|
||||
class EditorComponentAdapter : public EditorComponentBase
|
||||
{
|
||||
public:
|
||||
|
||||
AZ_RTTI((EditorComponentAdapter, "{2F5A3669-FFE9-4CD7-B9E2-7FC8100CF1A2}", TController, TRuntimeComponent, TConfiguration), EditorComponentBase);
|
||||
AZ_RTTI(
|
||||
(EditorComponentAdapter, "{2F5A3669-FFE9-4CD7-B9E2-7FC8100CF1A2}", TController, TRuntimeComponent, TConfiguration),
|
||||
EditorComponentBase);
|
||||
|
||||
EditorComponentAdapter() = default;
|
||||
EditorComponentAdapter(const TConfiguration& configuration);
|
||||
explicit EditorComponentAdapter(const TConfiguration& configuration);
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||
@@ -86,7 +86,6 @@ namespace AzToolsFramework
|
||||
void BuildGameEntity(AZ::Entity* gameEntity) override;
|
||||
|
||||
protected:
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// AZ::Component overrides ...
|
||||
|
||||
+39
-30
@@ -1,14 +1,14 @@
|
||||
/*
|
||||
* 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 <AzFramework/Components/ComponentAdapterHelpers.h>
|
||||
|
||||
@@ -28,23 +28,21 @@ namespace AzToolsFramework
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<EditorComponentAdapter, EditorComponentBase>()
|
||||
->Version(1)
|
||||
->Field("Controller", &EditorComponentAdapter::m_controller)
|
||||
;
|
||||
serializeContext->Class<EditorComponentAdapter, EditorComponentBase>()->Version(1)->Field(
|
||||
"Controller", &EditorComponentAdapter::m_controller);
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorComponentAdapter>(
|
||||
"EditorComponentAdapter", "")
|
||||
// clang-format off
|
||||
editContext->Class<EditorComponentAdapter>("EditorComponentAdapter", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorComponentAdapter::m_controller, "Controller", "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorComponentAdapter::OnConfigurationChanged)
|
||||
;
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorComponentAdapter::OnConfigurationChanged);
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,27 +51,35 @@ namespace AzToolsFramework
|
||||
// Get*Services functions
|
||||
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetProvidedServices(
|
||||
AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
AzFramework::Components::GetProvidedServicesHelper<TController>(services, typename AZ::HasComponentProvidedServices<TController>::type());
|
||||
AzFramework::Components::GetProvidedServicesHelper<TController>(
|
||||
services, typename AZ::HasComponentProvidedServices<TController>::type());
|
||||
}
|
||||
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetRequiredServices(
|
||||
AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
AzFramework::Components::GetRequiredServicesHelper<TController>(services, typename AZ::HasComponentRequiredServices<TController>::type());
|
||||
AzFramework::Components::GetRequiredServicesHelper<TController>(
|
||||
services, typename AZ::HasComponentRequiredServices<TController>::type());
|
||||
}
|
||||
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetIncompatibleServices(
|
||||
AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
AzFramework::Components::GetIncompatibleServicesHelper<TController>(services, typename AZ::HasComponentIncompatibleServices<TController>::type());
|
||||
AzFramework::Components::GetIncompatibleServicesHelper<TController>(
|
||||
services, typename AZ::HasComponentIncompatibleServices<TController>::type());
|
||||
}
|
||||
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetDependentServices(
|
||||
AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
AzFramework::Components::GetDependentServicesHelper<TController>(services, typename AZ::HasComponentDependentServices<TController>::type());
|
||||
AzFramework::Components::GetDependentServicesHelper<TController>(
|
||||
services, typename AZ::HasComponentDependentServices<TController>::type());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -99,7 +105,8 @@ namespace AzToolsFramework
|
||||
|
||||
if (ShouldActivateController())
|
||||
{
|
||||
m_controller.Activate(GetEntityId());
|
||||
AzFramework::Components::ComponentActivateHelper<TController>::Activate(
|
||||
m_controller, AZ::EntityComponentIdPair(GetEntityId(), GetId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +129,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
|
||||
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::WriteOutConfig(
|
||||
AZ::ComponentConfig* outBaseConfig) const
|
||||
{
|
||||
if (auto config = azrtti_cast<TConfiguration*>(outBaseConfig))
|
||||
{
|
||||
@@ -139,7 +147,8 @@ namespace AzToolsFramework
|
||||
|
||||
if (ShouldActivateController())
|
||||
{
|
||||
m_controller.Activate(GetEntityId());
|
||||
AzFramework::Components::ComponentActivateHelper<TController>::Activate(
|
||||
m_controller, AZ::EntityComponentIdPair(GetEntityId(), GetId()));
|
||||
}
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::None;
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(worldFromLocal, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
worldFromLocal.ExtractScale();
|
||||
worldFromLocal.ExtractUniformScale();
|
||||
m_manipulators = AZStd::make_unique<ScaleManipulators>(worldFromLocal);
|
||||
m_manipulators->Register(g_mainManipulatorManagerId);
|
||||
m_manipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
|
||||
|
||||
+48
-195
@@ -32,7 +32,6 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponentBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformScalePropertyHandler.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorInspectorComponentBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorPendingCompositionBus.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
@@ -50,10 +49,10 @@ namespace AzToolsFramework
|
||||
{
|
||||
const AZ::u32 ParentEntityCRC = AZ_CRC("Parent Entity", 0x5b1b276c);
|
||||
|
||||
// Decompose a transform into euler angles in degrees, scale (along basis, any shear will be dropped), and translation.
|
||||
void DecomposeTransform(const AZ::Transform& transform, AZ::Vector3& translation, AZ::Vector3& rotation, AZ::Vector3& scale)
|
||||
// Decompose a transform into euler angles in degrees, uniform scale, and translation.
|
||||
void DecomposeTransform(const AZ::Transform& transform, AZ::Vector3& translation, AZ::Vector3& rotation, float& scale)
|
||||
{
|
||||
scale = transform.GetScale();
|
||||
scale = transform.GetUniformScale();
|
||||
translation = transform.GetTranslation();
|
||||
rotation = transform.GetRotation().GetEulerDegrees();
|
||||
}
|
||||
@@ -120,7 +119,7 @@ namespace AzToolsFramework
|
||||
// Decompose the old slice-relative transform and set it as a our editor transform,
|
||||
// since the entity is now our parent.
|
||||
EditorTransform editorTransform;
|
||||
DecomposeTransform(sliceRelTransform, editorTransform.m_translate, editorTransform.m_rotate, editorTransform.m_scale);
|
||||
DecomposeTransform(sliceRelTransform, editorTransform.m_translate, editorTransform.m_rotate, editorTransform.m_uniformScale);
|
||||
editorTransformElement.Convert<EditorTransform>(context);
|
||||
editorTransformElement.SetData(context, editorTransform);
|
||||
}
|
||||
@@ -170,6 +169,23 @@ namespace AzToolsFramework
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorTransformDataConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
|
||||
{
|
||||
if (classElement.GetVersion() < 3)
|
||||
{
|
||||
// version 3 replaces vector scale with uniform scale but does not yet delete the legacy scale data
|
||||
// in order to allow for migration
|
||||
AZ::Vector3 vectorScale;
|
||||
if (classElement.FindSubElementAndGetData<AZ::Vector3>(AZ_CRC_CE("Scale"), vectorScale))
|
||||
{
|
||||
const float uniformScale = vectorScale.GetMaxElement();
|
||||
classElement.AddElementWithData(context, "UniformScale", uniformScale);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace Internal
|
||||
|
||||
TransformComponent::TransformComponent()
|
||||
@@ -357,7 +373,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::Transform TransformComponent::GetLocalScaleTM() const
|
||||
{
|
||||
return AZ::Transform::CreateScale(m_editorTransform.m_scale);
|
||||
return AZ::Transform::CreateUniformScale(m_editorTransform.m_uniformScale);
|
||||
}
|
||||
|
||||
const AZ::Transform& TransformComponent::GetLocalTM()
|
||||
@@ -374,12 +390,13 @@ namespace AzToolsFramework
|
||||
// given a local transform, update local transform.
|
||||
void TransformComponent::SetLocalTM(const AZ::Transform& finalTx)
|
||||
{
|
||||
AZ::Vector3 tx, rot, scale;
|
||||
Internal::DecomposeTransform(finalTx, tx, rot, scale);
|
||||
AZ::Vector3 tx, rot;
|
||||
float uniformScale;
|
||||
Internal::DecomposeTransform(finalTx, tx, rot, uniformScale);
|
||||
|
||||
m_editorTransform.m_translate = tx;
|
||||
m_editorTransform.m_rotate = rot;
|
||||
m_editorTransform.m_scale = scale;
|
||||
m_editorTransform.m_uniformScale = uniformScale;
|
||||
|
||||
TransformChanged();
|
||||
}
|
||||
@@ -520,91 +537,13 @@ namespace AzToolsFramework
|
||||
return m_editorTransform.m_translate.GetZ();
|
||||
}
|
||||
|
||||
void TransformComponent::SetRotation(const AZ::Vector3& eulerAnglesRadians)
|
||||
void TransformComponent::SetWorldRotationQuaternion(const AZ::Quaternion& quaternion)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotation is deprecated, please use SetLocalRotation");
|
||||
AZ::Transform newWorldTransform = GetWorldTM();
|
||||
newWorldTransform.SetRotation(AZ::ConvertEulerRadiansToQuaternion(eulerAnglesRadians));
|
||||
SetWorldTM(newWorldTransform);
|
||||
}
|
||||
|
||||
void TransformComponent::SetRotationQuaternion(const AZ::Quaternion& quaternion)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationQuaternion is deprecated, please use SetLocalRotation");
|
||||
AZ::Transform newWorldTransform = GetWorldTM();
|
||||
newWorldTransform.SetRotation(quaternion);
|
||||
SetWorldTM(newWorldTransform);
|
||||
}
|
||||
|
||||
void TransformComponent::SetRotationX(float eulerAngleRadians)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationX is deprecated, please use SetLocalRotation");
|
||||
AZ::Transform newWorldTransform = GetWorldTM();
|
||||
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationX(eulerAngleRadians));
|
||||
SetWorldTM(newWorldTransform);
|
||||
}
|
||||
|
||||
void TransformComponent::SetRotationY(float eulerAngleRadians)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationY is deprecated, please use SetLocalRotation");
|
||||
AZ::Transform newWorldTransform = GetWorldTM();
|
||||
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationY(eulerAngleRadians));
|
||||
SetWorldTM(newWorldTransform);
|
||||
}
|
||||
|
||||
void TransformComponent::SetRotationZ(float eulerAngleRadians)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationZ is deprecated, please use SetLocalRotation");
|
||||
AZ::Transform newWorldTransform = GetWorldTM();
|
||||
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationZ(eulerAngleRadians));
|
||||
SetWorldTM(newWorldTransform);
|
||||
}
|
||||
|
||||
void TransformComponent::RotateByX(float eulerAngleRadians)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "RotateByX is deprecated, please use RotateAroundLocalX");
|
||||
SetWorldTM(GetWorldTM() * AZ::Transform::CreateRotationX(eulerAngleRadians));
|
||||
}
|
||||
|
||||
void TransformComponent::RotateByY(float eulerAngleRadians)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "RotateByY is deprecated, please use RotateAroundLocalY");
|
||||
SetWorldTM(GetWorldTM() * AZ::Transform::CreateRotationY(eulerAngleRadians));
|
||||
}
|
||||
|
||||
void TransformComponent::RotateByZ(float eulerAngleRadians)
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "RotateByZ is deprecated, please use RotateAroundLocalZ");
|
||||
SetWorldTM(GetWorldTM() * AZ::Transform::CreateRotationZ(eulerAngleRadians));
|
||||
}
|
||||
|
||||
AZ::Vector3 TransformComponent::GetRotationEulerRadians()
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetRotationEulerRadians is deprecated, please use GetWorldRotation");
|
||||
return GetWorldTM().GetRotation().GetEulerRadians();
|
||||
}
|
||||
|
||||
AZ::Quaternion TransformComponent::GetRotationQuaternion()
|
||||
{
|
||||
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetRotationQuaternion is deprecated, please use GetWorldRotationQuaternion");
|
||||
return GetWorldTM().GetRotation();
|
||||
}
|
||||
|
||||
float TransformComponent::GetRotationX()
|
||||
{
|
||||
return GetRotationEulerRadians().GetX();
|
||||
}
|
||||
|
||||
float TransformComponent::GetRotationY()
|
||||
{
|
||||
return GetRotationEulerRadians().GetY();
|
||||
}
|
||||
|
||||
float TransformComponent::GetRotationZ()
|
||||
{
|
||||
return GetRotationEulerRadians().GetZ();
|
||||
}
|
||||
|
||||
AZ::Vector3 TransformComponent::GetWorldRotation()
|
||||
{
|
||||
return GetWorldTM().GetRotation().GetEulerRadians();
|
||||
@@ -677,108 +616,26 @@ 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;
|
||||
AZ_WarningOnce("TransformComponent", false, "GetLocalScale is deprecated, please use GetLocalUniformScale instead");
|
||||
return m_editorTransform.m_legacyScale;
|
||||
}
|
||||
|
||||
AZ::Vector3 TransformComponent::GetWorldScale()
|
||||
void TransformComponent::SetLocalUniformScale(float scale)
|
||||
{
|
||||
return GetWorldTM().GetScale();
|
||||
m_editorTransform.m_uniformScale = scale;
|
||||
TransformChanged();
|
||||
}
|
||||
|
||||
float TransformComponent::GetLocalUniformScale()
|
||||
{
|
||||
return m_editorTransform.m_uniformScale;
|
||||
}
|
||||
|
||||
float TransformComponent::GetWorldUniformScale()
|
||||
{
|
||||
return GetWorldTM().GetUniformScale();
|
||||
}
|
||||
|
||||
const AZ::Transform& TransformComponent::GetParentWorldTM() const
|
||||
@@ -1183,12 +1040,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();
|
||||
@@ -1297,9 +1148,10 @@ namespace AzToolsFramework
|
||||
serializeContext->Class<EditorTransform>()->
|
||||
Field("Translate", &EditorTransform::m_translate)->
|
||||
Field("Rotate", &EditorTransform::m_rotate)->
|
||||
Field("Scale", &EditorTransform::m_scale)->
|
||||
Field("Scale", &EditorTransform::m_legacyScale)->
|
||||
Field("Locked", &EditorTransform::m_locked)->
|
||||
Version(2);
|
||||
Field("UniformScale", &EditorTransform::m_uniformScale)->
|
||||
Version(3, &Internal::EditorTransformDataConverter);
|
||||
|
||||
serializeContext->Class<Components::TransformComponent, EditorComponentBase>()->
|
||||
Field("Parent Entity", &TransformComponent::m_parentEntityId)->
|
||||
@@ -1358,7 +1210,7 @@ namespace AzToolsFramework
|
||||
Attribute(AZ::Edit::Attributes::Suffix, " deg")->
|
||||
Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)->
|
||||
Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushableOnSliceRoot)->
|
||||
DataElement(TransformScaleHandler, &EditorTransform::m_scale, "Scale", "Local Scale")->
|
||||
DataElement(AZ::Edit::UIHandlers::Default, &EditorTransform::m_uniformScale, "Uniform Scale", "Local Uniform Scale")->
|
||||
Attribute(AZ::Edit::Attributes::Step, 0.1f)->
|
||||
Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)
|
||||
;
|
||||
@@ -1386,7 +1238,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undo("Reset transform values");
|
||||
m_editorTransform.m_translate = AZ::Vector3::CreateZero();
|
||||
m_editorTransform.m_scale = AZ::Vector3::CreateOne();
|
||||
m_editorTransform.m_legacyScale = AZ::Vector3::CreateOne();
|
||||
m_editorTransform.m_uniformScale = 1.0f;
|
||||
m_editorTransform.m_rotate = AZ::Vector3::CreateZero();
|
||||
OnTransformChanged();
|
||||
SetDirty();
|
||||
|
||||
+5
-33
@@ -99,22 +99,7 @@ namespace AzToolsFramework
|
||||
float GetLocalZ() override;
|
||||
|
||||
// Rotation modifiers
|
||||
void SetRotation(const AZ::Vector3& eulerAnglesRadians) override;
|
||||
void SetRotationQuaternion(const AZ::Quaternion& quaternion) override;
|
||||
void SetRotationX(float eulerAngleRadians) override;
|
||||
void SetRotationY(float eulerAngleRadians) override;
|
||||
void SetRotationZ(float eulerAngleRadians) override;
|
||||
|
||||
void RotateByX(float eulerAngleRadians) override;
|
||||
void RotateByY(float eulerAngleRadians) override;
|
||||
void RotateByZ(float eulerAngleRadians) override;
|
||||
|
||||
AZ::Vector3 GetRotationEulerRadians() override;
|
||||
AZ::Quaternion GetRotationQuaternion() override;
|
||||
|
||||
float GetRotationX() override;
|
||||
float GetRotationY() override;
|
||||
float GetRotationZ() override;
|
||||
void SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) override;
|
||||
|
||||
AZ::Vector3 GetWorldRotation() override;
|
||||
AZ::Quaternion GetWorldRotationQuaternion() override;
|
||||
@@ -130,23 +115,11 @@ 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;
|
||||
@@ -161,7 +134,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;
|
||||
|
||||
+6
-5
@@ -30,7 +30,8 @@ namespace AzToolsFramework
|
||||
EditorTransform()
|
||||
{
|
||||
m_translate = AZ::Vector3::CreateZero();
|
||||
m_scale = AZ::Vector3::CreateOne();
|
||||
m_legacyScale = AZ::Vector3::CreateOne();
|
||||
m_uniformScale = 1.0f;
|
||||
m_rotate = AZ::Vector3::CreateZero();
|
||||
m_locked = false;
|
||||
}
|
||||
@@ -40,9 +41,10 @@ namespace AzToolsFramework
|
||||
return EditorTransform();
|
||||
}
|
||||
|
||||
AZ::Vector3 m_translate; //! Translation in engine units (meters)
|
||||
AZ::Vector3 m_scale;
|
||||
AZ::Vector3 m_rotate; //! Rotation in degrees
|
||||
AZ::Vector3 m_translate; //!< Translation in engine units (meters)
|
||||
AZ::Vector3 m_legacyScale; //!< Legacy vector scale value, retained only for migration.
|
||||
float m_uniformScale; //!< Single scale value applied uniformly.
|
||||
AZ::Vector3 m_rotate; //!< Rotation in degrees
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
@@ -65,7 +67,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;
|
||||
};
|
||||
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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_precompiled.h"
|
||||
#include <ToolsComponents/TransformScalePropertyHandler.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void RegisterTransformScaleHandler()
|
||||
{
|
||||
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew Components::TransformScalePropertyHandler());
|
||||
}
|
||||
|
||||
namespace Components
|
||||
{
|
||||
AZ::u32 TransformScalePropertyHandler::GetHandlerName(void) const
|
||||
{
|
||||
return TransformScaleHandler;
|
||||
}
|
||||
|
||||
QWidget* TransformScalePropertyHandler::CreateGUI(QWidget* parent)
|
||||
{
|
||||
AzQtComponents::DoubleSpinBox* newCtrl = new AzQtComponents::DoubleSpinBox(parent);
|
||||
connect(newCtrl, QOverload<double>::of(&AzQtComponents::DoubleSpinBox::valueChanged), newCtrl, [newCtrl]()
|
||||
{
|
||||
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, newCtrl);
|
||||
});
|
||||
|
||||
newCtrl->setMinimum(AZ::MinTransformScale);
|
||||
newCtrl->setMaximum(AZ::MaxTransformScale);
|
||||
|
||||
return newCtrl;
|
||||
}
|
||||
|
||||
void TransformScalePropertyHandler::ConsumeAttribute(AzQtComponents::DoubleSpinBox* GUI, AZ::u32 attrib,
|
||||
AzToolsFramework::PropertyAttributeReader* attrValue, [[maybe_unused]] const char* debugName)
|
||||
{
|
||||
if (attrib == AZ::Edit::Attributes::Suffix)
|
||||
{
|
||||
AZStd::string label;
|
||||
if (attrValue->Read<AZStd::string>(label))
|
||||
{
|
||||
GUI->setSuffix(label.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformScalePropertyHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, AzQtComponents::DoubleSpinBox* GUI,
|
||||
AZ::Vector3& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const float value = aznumeric_cast<float>(GUI->value());
|
||||
const float currentMaxElement = instance.GetMaxElement();
|
||||
if (currentMaxElement != 0.0f)
|
||||
{
|
||||
instance *= value / currentMaxElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = AZ::Vector3(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransformScalePropertyHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, AzQtComponents::DoubleSpinBox* GUI,
|
||||
const AZ::Vector3& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
QSignalBlocker signalBlocker(GUI);
|
||||
GUI->setValue(instance.GetMaxElement());
|
||||
return true;
|
||||
}
|
||||
} // namespace Components
|
||||
} // namespace AzToolsFramework
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzQtComponents/Components/Widgets/SpinBox.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#endif
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Components
|
||||
{
|
||||
static const AZ::Crc32 TransformScaleHandler = AZ_CRC_CE("TransformScale");
|
||||
|
||||
//! Handler to allow the scale field inside the Transform Component to be represented as a single value in
|
||||
//! the editor, but stored internally as a Vector3.
|
||||
//! The purpose for this is to prevent any new entities being created with non-uniform scale on the Transform
|
||||
//! Component, but preserve the data required for migrating any existing entities to use the Non-Uniform Scale
|
||||
//! Component, until all migration work is completed.
|
||||
//! The value shown in the editor will be the maximum value from the scale vector, and changing the value in
|
||||
//! the editor will update the vector so that its maximum value matches the newly edited value, but its
|
||||
//! components retain their existing proportion.
|
||||
//! For example, if the current vector scale is (2, 3, 4), the value in the editor will appear as 4. If the value
|
||||
//! in the editor is updated to 2, then the vector scale will update to (1, 1.5, 2), keeping the same proportion
|
||||
//! between the x, y and z components.
|
||||
class TransformScalePropertyHandler
|
||||
: public QObject
|
||||
, public AzToolsFramework::PropertyHandler<AZ::Vector3, AzQtComponents::DoubleSpinBox>
|
||||
{
|
||||
Q_OBJECT //AUTOMOC
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(TransformScalePropertyHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override;
|
||||
QWidget* CreateGUI(QWidget* parent) override;
|
||||
void ConsumeAttribute(AzQtComponents::DoubleSpinBox* GUI, AZ::u32 attrib,
|
||||
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
void WriteGUIValuesIntoProperty(size_t index, AzQtComponents::DoubleSpinBox* GUI,
|
||||
AZ::Vector3& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
bool ReadValuesIntoGUI(size_t index, AzQtComponents::DoubleSpinBox* GUI,
|
||||
const AZ::Vector3& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
};
|
||||
} // namespace Components
|
||||
} // namespace AzToolsFramework
|
||||
+11
@@ -63,6 +63,7 @@
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerDisplayOptionsMenu.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerCacheBus.h>
|
||||
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1409,6 +1410,16 @@ namespace AzToolsFramework
|
||||
{
|
||||
(void)name;
|
||||
QueueEntityUpdate(entityId);
|
||||
|
||||
bool isSelected = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(
|
||||
isSelected, &AzToolsFramework::ToolsApplicationRequests::IsSelected, entityId);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
// Ask the system to scroll to the entity in case it is off screen after the rename
|
||||
EntityOutlinerModelNotificationBus::Broadcast(&EntityOutlinerModelNotifications::QueueScrollToNewContent, entityId);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerListModel::OnEntityInfoUpdatedUnsavedChanges(AZ::EntityId entityId)
|
||||
|
||||
+7
-2
@@ -172,7 +172,7 @@ namespace AzToolsFramework
|
||||
|
||||
const int autoExpandDelayMilliseconds = 2500;
|
||||
m_gui->m_objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
m_gui->m_objectTree->setEditTriggers(QAbstractItemView::EditKeyPressed);
|
||||
SetDefaultTreeViewEditTriggers();
|
||||
m_gui->m_objectTree->setAutoExpandDelay(autoExpandDelayMilliseconds);
|
||||
m_gui->m_objectTree->setDragEnabled(true);
|
||||
m_gui->m_objectTree->setDropIndicatorShown(true);
|
||||
@@ -850,6 +850,11 @@ namespace AzToolsFramework
|
||||
addAction(m_actionGoToEntitiesInViewport);
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::SetDefaultTreeViewEditTriggers()
|
||||
{
|
||||
m_gui->m_objectTree->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed);
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::OnEntityPickModeStarted()
|
||||
{
|
||||
m_gui->m_objectTree->setDragEnabled(false);
|
||||
@@ -862,7 +867,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_gui->m_objectTree->setDragEnabled(true);
|
||||
m_gui->m_objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
m_gui->m_objectTree->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||||
SetDefaultTreeViewEditTriggers();
|
||||
m_inObjectPickMode = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,8 @@ namespace AzToolsFramework
|
||||
// to a given entity
|
||||
void QueueScrollToNewContent(const AZ::EntityId& entityId) override;
|
||||
|
||||
void SetDefaultTreeViewEditTriggers();
|
||||
|
||||
void ScrollToNewContent();
|
||||
bool m_scrollToNewContentQueued;
|
||||
bool m_scrollToSelectedEntity;
|
||||
|
||||
+1
-1
@@ -333,7 +333,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab(selectedEntities, s_prefabLoaderInterface->GetRelativePathToProject(prefabFilePath.data()));
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab(selectedEntities, prefabFilePath.data());
|
||||
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
|
||||
+7
-2
@@ -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;
|
||||
|
||||
+1
-2
@@ -140,8 +140,7 @@ namespace AzToolsFramework
|
||||
ProductAssetBrowserEntry* productEntry = static_cast<ProductAssetBrowserEntry*>(childEntry);
|
||||
AZStd::string assetName;
|
||||
AzFramework::StringFunc::Path::GetFileName(productEntry->GetFullPath().c_str(), assetName);
|
||||
m_assets.push_back({
|
||||
assetName, productEntry->GetFullPath(), productEntry->GetAssetId()
|
||||
m_assets.push_back({ productEntry->GetName(), productEntry->GetFullPath(), productEntry->GetAssetId()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+63
-5
@@ -769,6 +769,31 @@ namespace AzToolsFramework
|
||||
// Request the AssetBrowser Dialog and set a type filter
|
||||
AssetSelectionModel selection = GetAssetSelectionModel();
|
||||
selection.SetSelectedAssetId(m_selectedAssetID);
|
||||
|
||||
AZStd::string defaultDirectory;
|
||||
if (m_defaultDirectoryCallback)
|
||||
{
|
||||
m_defaultDirectoryCallback->Invoke(m_editNotifyTarget, defaultDirectory);
|
||||
selection.SetDefaultDirectory(defaultDirectory);
|
||||
}
|
||||
|
||||
if (m_hideProductFilesInAssetPicker)
|
||||
{
|
||||
FilterConstType displayFilter = selection.GetDisplayFilter();
|
||||
|
||||
EntryTypeFilter* productsFilter = new EntryTypeFilter();
|
||||
productsFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Product);
|
||||
|
||||
InverseFilter* noProductsFilter = new InverseFilter();
|
||||
noProductsFilter->SetFilter(FilterConstType(productsFilter));
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(FilterConstType(displayFilter));
|
||||
compFilter->AddFilter(FilterConstType(noProductsFilter));
|
||||
|
||||
selection.SetDisplayFilter(FilterConstType(compFilter));
|
||||
}
|
||||
|
||||
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget());
|
||||
if (selection.IsValid())
|
||||
{
|
||||
@@ -928,11 +953,16 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
const AZ::Data::AssetId assetID = GetCurrentAssetID();
|
||||
m_currentAssetHint = "";
|
||||
|
||||
if (!m_unnamedType)
|
||||
const AZStd::string& folderPath = GetFolderSelection();
|
||||
if (!folderPath.empty())
|
||||
{
|
||||
m_currentAssetHint = folderPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
const AZ::Data::AssetId assetID = GetCurrentAssetID();
|
||||
m_currentAssetHint = "";
|
||||
|
||||
AZ::Outcome<AssetSystem::JobInfoContainer> jobOutcome = AZ::Failure();
|
||||
AssetSystemJobRequestBus::BroadcastResult(jobOutcome, &AssetSystemJobRequestBus::Events::GetAssetJobsInfoByAssetID, assetID, false, false);
|
||||
|
||||
@@ -946,7 +976,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (!jobs.empty())
|
||||
{
|
||||
// The default behavior is show to the source filename.
|
||||
// The default behavior is to show the source filename.
|
||||
assetPath = jobs[0].m_sourceFile;
|
||||
|
||||
AZStd::string errorLog;
|
||||
@@ -1080,6 +1110,11 @@ namespace AzToolsFramework
|
||||
m_editNotifyCallback = editNotifyCallback;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetDefaultDirectoryCallback(DefaultDirectoryCallbackType* callback)
|
||||
{
|
||||
m_defaultDirectoryCallback = callback;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetClearNotifyCallback(ClearCallbackType* clearNotifyCallback)
|
||||
{
|
||||
m_clearNotifyCallback = clearNotifyCallback;
|
||||
@@ -1159,6 +1194,16 @@ namespace AzToolsFramework
|
||||
return m_showProductAssetName;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetHideProductFilesInAssetPicker(bool hide)
|
||||
{
|
||||
m_hideProductFilesInAssetPicker = hide;
|
||||
}
|
||||
|
||||
bool PropertyAssetCtrl::GetHideProductFilesInAssetPicker() const
|
||||
{
|
||||
return m_hideProductFilesInAssetPicker;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetShowThumbnail(bool enable)
|
||||
{
|
||||
m_showThumbnail = enable;
|
||||
@@ -1214,6 +1259,11 @@ namespace AzToolsFramework
|
||||
GUI->SetTitle(title.c_str());
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC_CE("DefaultStartingDirectoryCallback"))
|
||||
{
|
||||
// This is assumed to be an Asset Browser path to a specific folder to be used as a default by the asset picker if provided
|
||||
GUI->SetDefaultDirectoryCallback(azdynamic_cast<PropertyAssetCtrl::DefaultDirectoryCallbackType*>(attrValue->GetAttribute()));
|
||||
}
|
||||
else if (attrib == AZ_CRC("EditCallback", 0xb74f2ee1))
|
||||
{
|
||||
PropertyAssetCtrl::EditCallbackType* func = azdynamic_cast<PropertyAssetCtrl::EditCallbackType*>(attrValue->GetAttribute());
|
||||
@@ -1279,6 +1329,14 @@ namespace AzToolsFramework
|
||||
GUI->SetShowProductAssetName(showProductAssetName);
|
||||
}
|
||||
}
|
||||
else if(attrib == AZ::Edit::Attributes::HideProductFilesInAssetPicker)
|
||||
{
|
||||
bool hideProductFilesInAssetPicker = false;
|
||||
if (attrValue->Read<bool>(hideProductFilesInAssetPicker))
|
||||
{
|
||||
GUI->SetHideProductFilesInAssetPicker(hideProductFilesInAssetPicker);
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ::Edit::Attributes::ClearNotify)
|
||||
{
|
||||
PropertyAssetCtrl::ClearCallbackType* func = azdynamic_cast<PropertyAssetCtrl::ClearCallbackType*>(attrValue->GetAttribute());
|
||||
|
||||
+10
@@ -68,6 +68,7 @@ namespace AzToolsFramework
|
||||
// This is meant to be used with the "EditCallback" Attribute
|
||||
using EditCallbackType = AZ::Edit::AttributeFunction<void(const AZ::Data::AssetId&, const AZ::Data::AssetType&)>;
|
||||
using ClearCallbackType = AZ::Edit::AttributeFunction<void()>;
|
||||
using DefaultDirectoryCallbackType = AZ::Edit::AttributeFunction<void(AZStd::string&)>;
|
||||
|
||||
PropertyAssetCtrl(QWidget *pParent = NULL, QString optionalValidDragDropExtensions = QString());
|
||||
virtual ~PropertyAssetCtrl();
|
||||
@@ -119,6 +120,7 @@ namespace AzToolsFramework
|
||||
EditCallbackType* m_editNotifyCallback = nullptr;
|
||||
ClearCallbackType* m_clearNotifyCallback = nullptr;
|
||||
QString m_optionalValidDragDropExtensions;
|
||||
DefaultDirectoryCallbackType* m_defaultDirectoryCallback = nullptr;
|
||||
|
||||
//! The number of characters after which the autocompleter dropdown will be shown.
|
||||
// Prevents showing too many options.
|
||||
@@ -156,6 +158,10 @@ namespace AzToolsFramework
|
||||
//! Assets can be either source or product assets generated from source assets. By default, source assets are shown in the property asset. You can override that with this flag.
|
||||
bool m_showProductAssetName = true;
|
||||
|
||||
//! Assets can be either source or product assets generated from source assets.
|
||||
//! By default the asset picker shows both on an AZ::Asset<> property. You can hide product assets with this flag.
|
||||
bool m_hideProductFilesInAssetPicker = false;
|
||||
|
||||
bool m_showThumbnail = false;
|
||||
bool m_showThumbnailDropDownButton = false;
|
||||
EditCallbackType* m_thumbnailCallback = nullptr;
|
||||
@@ -196,6 +202,7 @@ namespace AzToolsFramework
|
||||
void SetEditNotifyTarget(void* editNotifyTarget);
|
||||
void SetEditNotifyCallback(EditCallbackType* editNotifyCallback); // This is meant to be used with the "EditCallback" Attribute
|
||||
void SetClearNotifyCallback(ClearCallbackType* clearNotifyCallback); // This is meant to be used with the "ClearNotify" Attribute
|
||||
void SetDefaultDirectoryCallback(DefaultDirectoryCallbackType* callback); // This is meant to be used with the "DefaultStartingDirectoryCallback" Attribute
|
||||
void SetEditButtonEnabled(bool enabled);
|
||||
void SetEditButtonVisible(bool visible);
|
||||
void SetEditButtonIcon(const QIcon& icon);
|
||||
@@ -208,6 +215,9 @@ namespace AzToolsFramework
|
||||
void SetShowProductAssetName(bool enable);
|
||||
bool GetShowProductAssetName() const;
|
||||
|
||||
void SetHideProductFilesInAssetPicker(bool hide);
|
||||
bool GetHideProductFilesInAssetPicker() const;
|
||||
|
||||
void SetShowThumbnail(bool enable);
|
||||
bool GetShowThumbnail() const;
|
||||
void SetShowThumbnailDropDownButton(bool enable);
|
||||
|
||||
-3
@@ -16,7 +16,6 @@
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIdContainer.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrlTypes.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformScalePropertyHandler.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -38,7 +37,6 @@ namespace AzToolsFramework
|
||||
void RegisterButtonPropertyHandlers();
|
||||
void RegisterMultiLineEditHandler();
|
||||
void RegisterCrcHandler();
|
||||
void RegisterTransformScaleHandler();
|
||||
void ReflectPropertyEditor(AZ::ReflectContext* context);
|
||||
|
||||
namespace Components
|
||||
@@ -192,7 +190,6 @@ namespace AzToolsFramework
|
||||
RegisterVectorHandlers();
|
||||
RegisterButtonPropertyHandlers();
|
||||
RegisterMultiLineEditHandler();
|
||||
RegisterTransformScaleHandler();
|
||||
|
||||
// GenericComboBoxHandlers
|
||||
RegisterGenericComboBoxHandler<AZ::Crc32>();
|
||||
|
||||
+7
-1
@@ -138,7 +138,7 @@ namespace UnitTest
|
||||
if (!GetApplication())
|
||||
{
|
||||
// Create & Start a new ToolsApplication if there's no existing one
|
||||
m_app = AZStd::make_unique<ToolsTestApplication>("ToolsApplication");
|
||||
m_app = CreateTestApplication();
|
||||
m_app->Start(AzFramework::Application::Descriptor());
|
||||
}
|
||||
|
||||
@@ -216,6 +216,12 @@ namespace UnitTest
|
||||
TestEditorActions m_editorActions;
|
||||
ToolsApplicationMessageHandler m_messageHandler; // used to suppress trace messages in test output
|
||||
|
||||
// Override this if your test fixture needs to use a custom TestApplication
|
||||
virtual AZStd::unique_ptr<ToolsTestApplication> CreateTestApplication()
|
||||
{
|
||||
return AZStd::make_unique<ToolsTestApplication>("ToolsApplication");
|
||||
}
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<ToolsTestApplication> m_app;
|
||||
};
|
||||
|
||||
@@ -165,15 +165,18 @@ namespace AzToolsFramework
|
||||
virtual bool AngleSnappingEnabled() = 0;
|
||||
/// Return the angle snapping/step size.
|
||||
virtual float AngleStep() = 0;
|
||||
/// Transform a point in world space to screen space coordinates.
|
||||
/// Transform a point in world space to screen space coordinates in Qt Widget space.
|
||||
/// Multiply by DeviceScalingFactor to get the position in viewport pixel space.
|
||||
virtual AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) = 0;
|
||||
/// Transform a point in screen space coordinates to a vector in world space based on clip space depth.
|
||||
/// Transform a point from Qt widget screen space to world space based on the given clip space depth.
|
||||
/// Depth specifies a relative camera depth to project in the range of [0.f, 1.f].
|
||||
/// Returns the world space position if successful.
|
||||
virtual AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) = 0;
|
||||
/// Casts a point in screen space to a ray in world space originating from the viewport camera frustum's near plane.
|
||||
/// Returns a ray containing the ray's origin and a direction normal, if successful.
|
||||
virtual AZStd::optional<ProjectedViewportRay> ViewportScreenToWorldRay(const AzFramework::ScreenPoint& screenPosition) = 0;
|
||||
/// Gets the DPI scaling factor that translates Qt widget space into viewport pixel space.
|
||||
virtual float DeviceScalingFactor() = 0;
|
||||
|
||||
protected:
|
||||
~ViewportInteractionRequests() = default;
|
||||
|
||||
+9
-4
@@ -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}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+115
-34
@@ -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,14 +809,12 @@ namespace AzToolsFramework
|
||||
EntityIdManipulators& entityIdManipulators,
|
||||
OptionalFrame& pivotOverrideFrame,
|
||||
ViewportInteraction::KeyboardModifiers& prevModifiers,
|
||||
bool& transformChangedInternally)
|
||||
bool& transformChangedInternally, const AZStd::optional<ReferenceFrame> spaceLock)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
entityIdManipulators.m_manipulators->SetLocalPosition(action.LocalPosition());
|
||||
|
||||
const ReferenceFrame referenceFrame = ReferenceFrameFromModifiers(action.m_modifiers);
|
||||
|
||||
if (action.m_modifiers.Ctrl())
|
||||
{
|
||||
// moving with ctrl - setting override
|
||||
@@ -806,6 +824,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
else
|
||||
{
|
||||
const ReferenceFrame referenceFrame = spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
|
||||
|
||||
// note: used for parent and world depending on the current reference frame
|
||||
const auto pivotOrientation =
|
||||
ETCS::CalculateSelectionPivotOrientation(
|
||||
@@ -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.m_spaceLock);
|
||||
});
|
||||
|
||||
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.m_spaceLock);
|
||||
});
|
||||
|
||||
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.m_spaceLock);
|
||||
});
|
||||
|
||||
translationManipulators->InstallSurfaceManipulatorMouseUpCallback(
|
||||
@@ -1414,8 +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.value_or(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)
|
||||
// so we don't lose the orientation when adding/removing entities from the selection
|
||||
@@ -1474,7 +1496,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 +1507,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 +1619,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 +1893,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 +1922,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 +2415,7 @@ namespace AzToolsFramework
|
||||
ResetOrientationForSelectedEntitiesLocal();
|
||||
break;
|
||||
case Mode::Scale:
|
||||
CopyScaleToSelectedEntitiesIndividualLocal(AZ::Vector3::CreateOne());
|
||||
CopyScaleToSelectedEntitiesIndividualLocal(1.0f);
|
||||
break;
|
||||
case Mode::Translation:
|
||||
ResetTranslationForSelectedEntitiesLocal();
|
||||
@@ -2420,7 +2441,7 @@ namespace AzToolsFramework
|
||||
ResetOrientationForSelectedEntitiesLocal();
|
||||
break;
|
||||
case Mode::Scale:
|
||||
CopyScaleToSelectedEntitiesIndividualWorld(AZ::Vector3::CreateOne());
|
||||
CopyScaleToSelectedEntitiesIndividualWorld(1.0f);
|
||||
break;
|
||||
case Mode::Translation:
|
||||
// do nothing
|
||||
@@ -2567,6 +2588,64 @@ 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.has_value() && m_spaceCluster.m_spaceLock.value() == ReferenceFrame::Local)
|
||||
{
|
||||
m_spaceCluster.m_spaceLock = AZStd::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spaceCluster.m_spaceLock = ReferenceFrame::Local;
|
||||
}
|
||||
}
|
||||
else if (buttonId == m_spaceCluster.m_parentButtonId)
|
||||
{
|
||||
// Unlock
|
||||
if (m_spaceCluster.m_spaceLock.has_value() && m_spaceCluster.m_spaceLock.value() == ReferenceFrame::Parent)
|
||||
{
|
||||
m_spaceCluster.m_spaceLock = AZStd::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spaceCluster.m_spaceLock = ReferenceFrame::Parent;
|
||||
}
|
||||
}
|
||||
else if (buttonId == m_spaceCluster.m_worldButtonId)
|
||||
{
|
||||
// Unlock
|
||||
if (m_spaceCluster.m_spaceLock.has_value() && m_spaceCluster.m_spaceLock.value() == ReferenceFrame::World)
|
||||
{
|
||||
m_spaceCluster.m_spaceLock = AZStd::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spaceCluster.m_spaceLock = 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 +3019,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::CopyScaleToSelectedEntitiesIndividualWorld(const AZ::Vector3& scale)
|
||||
void EditorTransformComponentSelection::CopyScaleToSelectedEntitiesIndividualWorld(float scale)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
@@ -2955,7 +3034,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 +3043,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 +3053,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 +3099,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 +3357,9 @@ namespace AzToolsFramework
|
||||
ViewportInteraction::BuildMouseButtons(
|
||||
QGuiApplication::mouseButtons()), m_boxSelect.Active());
|
||||
|
||||
const ReferenceFrame referenceFrame = ReferenceFrameFromModifiers(modifiers);
|
||||
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(modifiers));
|
||||
|
||||
UpdateSpaceCluster(referenceFrame);
|
||||
|
||||
bool refresh = false;
|
||||
if (referenceFrame != m_referenceFrame)
|
||||
@@ -3669,7 +3750,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 +3803,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)
|
||||
|
||||
+25
-4
@@ -106,6 +106,22 @@ namespace AzToolsFramework
|
||||
World, //!< World space (space aligned to world axes - identity).
|
||||
};
|
||||
|
||||
//! Grouping of viewport ui related state for controlling the current reference space of the Editor.
|
||||
struct SpaceCluster
|
||||
{
|
||||
SpaceCluster() = default;
|
||||
// disable copying and moving (implicit)
|
||||
SpaceCluster(const SpaceCluster&) = delete;
|
||||
SpaceCluster& operator=(const SpaceCluster&) = delete;
|
||||
|
||||
ViewportUi::ClusterId m_spaceClusterId; //!< The id identifying the reference space cluster.
|
||||
ViewportUi::ButtonId m_localButtonId; //!< Local reference space button id.
|
||||
ViewportUi::ButtonId m_parentButtonId; //!< Parent reference space button id.
|
||||
ViewportUi::ButtonId m_worldButtonId; //!< World reference space button id.
|
||||
AZ::Event<ViewportUi::ButtonId>::Handler m_spaceSelectionHandler; //!< Callback for when a space cluster button is pressed.
|
||||
AZStd::optional<ReferenceFrame> m_spaceLock; //!< Locked reference frame to use if set.
|
||||
};
|
||||
|
||||
//! Entity selection/interaction handling.
|
||||
//! Provide a suite of functionality for manipulating entities, primarily through their TransformComponent.
|
||||
class EditorTransformComponentSelection
|
||||
@@ -160,6 +176,7 @@ namespace AzToolsFramework
|
||||
void RegenerateManipulators();
|
||||
|
||||
void CreateTransformModeSelectionCluster();
|
||||
void CreateSpaceSelectionCluster();
|
||||
|
||||
void ClearManipulatorTranslationOverride();
|
||||
void ClearManipulatorOrientationOverride();
|
||||
@@ -214,8 +231,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,9 +267,12 @@ 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);
|
||||
|
||||
// Responsible for keeping the space cluster in sync with the current reference frame.
|
||||
void UpdateSpaceCluster(ReferenceFrame referenceFrame);
|
||||
|
||||
AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any).
|
||||
AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display.
|
||||
AZ::EntityId m_editorCameraComponentEntityId; //!< The EditorCameraComponent EntityId if it is set.
|
||||
@@ -285,6 +305,7 @@ 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; //!< Related viewport ui state for controlling the current reference space.
|
||||
};
|
||||
|
||||
//! The ETCS (EntityTransformComponentSelection) namespace contains functions and data used exclusively by
|
||||
@@ -320,7 +341,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
|
||||
|
||||
+2
-2
@@ -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
|
||||
@@ -292,8 +293,6 @@ set(FILES
|
||||
ToolsComponents/TransformComponent.h
|
||||
ToolsComponents/TransformComponent.cpp
|
||||
ToolsComponents/TransformComponentBus.h
|
||||
ToolsComponents/TransformScalePropertyHandler.cpp
|
||||
ToolsComponents/TransformScalePropertyHandler.h
|
||||
ToolsComponents/ScriptEditorComponent.cpp
|
||||
ToolsComponents/ScriptEditorComponent.h
|
||||
ToolsComponents/ToolsAssetCatalogComponent.cpp
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzFramework/Asset/AssetRegistry.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/Asset/AssetCatalog.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
@@ -62,6 +63,12 @@ namespace UnitTest
|
||||
m_assetSeedManager = new AzToolsFramework::AssetSeedManager();
|
||||
m_assetRegistry = new AzFramework::AssetRegistry();
|
||||
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_application->Start(AzFramework::Application::Descriptor());
|
||||
|
||||
for (int idx = 0; idx < s_totalAssets; idx++)
|
||||
@@ -75,7 +82,7 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
m_testPlatforms[0] = AzFramework::PlatformId::PC;
|
||||
m_testPlatforms[1] = AzFramework::PlatformId::ES3;
|
||||
m_testPlatforms[1] = AzFramework::PlatformId::ANDROID_ID;
|
||||
|
||||
int platformCount = 0;
|
||||
for(auto thisPlatform : m_testPlatforms)
|
||||
@@ -163,20 +170,20 @@ namespace UnitTest
|
||||
AzFramework::AssetCatalog assetCatalog(useRequestBus);
|
||||
|
||||
AZStd::string pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC);
|
||||
AZStd::string es3CatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ES3);
|
||||
AZStd::string androidCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
if (!assetCatalog.SaveCatalog(pcCatalogFile.c_str(), m_assetRegistry))
|
||||
{
|
||||
GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to save the asset catalog (PC) file.\n").c_str());
|
||||
}
|
||||
|
||||
if (!assetCatalog.SaveCatalog(es3CatalogFile.c_str(), m_assetRegistry))
|
||||
if (!assetCatalog.SaveCatalog(androidCatalogFile.c_str(), m_assetRegistry))
|
||||
{
|
||||
GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to save the asset catalog (ES3) file.\n").c_str());
|
||||
GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to save the asset catalog (ANDROID) file.\n").c_str());
|
||||
}
|
||||
|
||||
m_pcCatalog = new AzToolsFramework::PlatformAddressedAssetCatalog(AzFramework::PlatformId::PC);
|
||||
m_es3Catalog = new AzToolsFramework::PlatformAddressedAssetCatalog(AzFramework::PlatformId::ES3);
|
||||
m_androidCatalog = new AzToolsFramework::PlatformAddressedAssetCatalog(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
const AZStd::string engroot = AZ::Test::GetEngineRootPath();
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str());
|
||||
@@ -220,21 +227,21 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
auto pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC);
|
||||
auto es3CatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ES3);
|
||||
auto androidCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID);
|
||||
if (fileIO->Exists(pcCatalogFile.c_str()))
|
||||
{
|
||||
fileIO->Remove(pcCatalogFile.c_str());
|
||||
}
|
||||
|
||||
if (fileIO->Exists(es3CatalogFile.c_str()))
|
||||
if (fileIO->Exists(androidCatalogFile.c_str()))
|
||||
{
|
||||
fileIO->Remove(es3CatalogFile.c_str());
|
||||
fileIO->Remove(androidCatalogFile.c_str());
|
||||
}
|
||||
|
||||
delete m_assetSeedManager;
|
||||
delete m_assetRegistry;
|
||||
delete m_pcCatalog;
|
||||
delete m_es3Catalog;
|
||||
delete m_androidCatalog;
|
||||
m_application->Stop();
|
||||
delete m_application;
|
||||
}
|
||||
@@ -335,10 +342,10 @@ namespace UnitTest
|
||||
m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_PC);
|
||||
|
||||
// Step we are testing
|
||||
m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ES3);
|
||||
m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
// Verification
|
||||
AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ES3;
|
||||
AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID;
|
||||
for (const auto& seedInfo : m_assetSeedManager->GetAssetSeedList())
|
||||
{
|
||||
EXPECT_EQ(seedInfo.m_platformFlags, expectedPlatformFlags);
|
||||
@@ -351,14 +358,14 @@ namespace UnitTest
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC);
|
||||
m_assetSeedManager->AddSeedAsset(assets[1], AzFramework::PlatformFlags::Platform_PC);
|
||||
|
||||
m_es3Catalog->UnregisterAsset(assets[2]);
|
||||
m_androidCatalog->UnregisterAsset(assets[2]);
|
||||
m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_PC);
|
||||
|
||||
// Step we are testing
|
||||
m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ES3);
|
||||
m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
// Verification
|
||||
AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ES3;
|
||||
AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID;
|
||||
for (const auto& seedInfo : m_assetSeedManager->GetAssetSeedList())
|
||||
{
|
||||
if (seedInfo.m_assetId == assets[2])
|
||||
@@ -376,14 +383,14 @@ namespace UnitTest
|
||||
{
|
||||
// Setup
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
m_assetSeedManager->AddSeedAsset(assets[1], AzFramework::PlatformFlags::Platform_PC);
|
||||
m_assetSeedManager->AddSeedAsset(assets[1], AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[1], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_PC);
|
||||
m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
|
||||
// Step we are testing
|
||||
m_assetSeedManager->RemovePlatformFromAllSeeds(AzFramework::PlatformId::ES3);
|
||||
m_assetSeedManager->RemovePlatformFromAllSeeds(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
// Verification
|
||||
for (const auto& seedInfo : m_assetSeedManager->GetAssetSeedList())
|
||||
@@ -507,8 +514,8 @@ namespace UnitTest
|
||||
|
||||
void DependencyValidation_MultipleAssetSeeds_MultiplePlatformFlags_ListValid()
|
||||
{
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[5], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
m_assetSeedManager->AddSeedAsset(assets[5], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
|
||||
AzToolsFramework::AssetFileInfoList assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);
|
||||
|
||||
@@ -524,7 +531,7 @@ namespace UnitTest
|
||||
|
||||
assetList.m_fileInfoList.clear();
|
||||
|
||||
m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);
|
||||
|
||||
@@ -540,7 +547,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(Search(assetList, assets[8]));
|
||||
|
||||
assetList.m_fileInfoList.clear();
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[5], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[5], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);
|
||||
|
||||
@@ -555,7 +562,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(Search(assetList, assets[8]));
|
||||
|
||||
// Removing the android flag from the asset should still produce the same result
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ES3);
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);
|
||||
|
||||
@@ -569,7 +576,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(Search(assetList, assets[7]));
|
||||
EXPECT_TRUE(Search(assetList, assets[8]));
|
||||
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ES3);
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
EXPECT_EQ(assetList.m_fileInfoList.size(), 5);
|
||||
EXPECT_TRUE(Search(assetList, assets[0]));
|
||||
@@ -579,8 +586,8 @@ namespace UnitTest
|
||||
EXPECT_TRUE(Search(assetList, assets[4]));
|
||||
|
||||
// Adding the android flag again to the asset
|
||||
m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ES3);
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ES3);
|
||||
m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
EXPECT_EQ(assetList.m_fileInfoList.size(), 8);
|
||||
EXPECT_TRUE(Search(assetList, assets[0]));
|
||||
@@ -766,7 +773,7 @@ namespace UnitTest
|
||||
AzFramework::AssetRegistry* m_assetRegistry;
|
||||
ToolsTestApplication* m_application;
|
||||
AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog;
|
||||
AzToolsFramework::PlatformAddressedAssetCatalog* m_es3Catalog;
|
||||
AzToolsFramework::PlatformAddressedAssetCatalog* m_androidCatalog;
|
||||
AZ::IO::FileIOStream m_fileStreams[s_totalTestPlatforms][s_totalAssets];
|
||||
AzFramework::PlatformId m_testPlatforms[s_totalTestPlatforms];
|
||||
AZStd::string m_assetsPath[s_totalAssets];
|
||||
@@ -929,7 +936,7 @@ namespace UnitTest
|
||||
TEST_F(AssetSeedManagerTest, AddSeedAssetForValidPlatforms_AllPlatformsValid_SeedAddedForEveryInputPlatform)
|
||||
{
|
||||
using namespace AzFramework;
|
||||
PlatformFlags validPlatforms = PlatformFlags::Platform_PC | PlatformFlags::Platform_ES3;
|
||||
PlatformFlags validPlatforms = PlatformFlags::Platform_PC | PlatformFlags::Platform_ANDROID;
|
||||
AZStd::pair<AZ::Data::AssetId, PlatformFlags> result = m_assetSeedManager->AddSeedAssetForValidPlatforms(TestDynamicSliceAssetPath, validPlatforms);
|
||||
|
||||
// Verify the function outputs
|
||||
@@ -946,8 +953,8 @@ namespace UnitTest
|
||||
TEST_F(AssetSeedManagerTest, AddSeedAssetForValidPlatforms_SomePlatformsValid_SeedAddedForEveryValidPlatform)
|
||||
{
|
||||
using namespace AzFramework;
|
||||
PlatformFlags validPlatforms = PlatformFlags::Platform_PC | PlatformFlags::Platform_ES3;
|
||||
PlatformFlags inputPlatforms = validPlatforms | PlatformFlags::Platform_OSX;
|
||||
PlatformFlags validPlatforms = PlatformFlags::Platform_PC | PlatformFlags::Platform_ANDROID;
|
||||
PlatformFlags inputPlatforms = validPlatforms | PlatformFlags::Platform_MAC;
|
||||
AZStd::pair<AZ::Data::AssetId, PlatformFlags> result = m_assetSeedManager->AddSeedAssetForValidPlatforms(TestDynamicSliceAssetPath, inputPlatforms);
|
||||
|
||||
// Verify the function outputs
|
||||
@@ -964,7 +971,7 @@ namespace UnitTest
|
||||
TEST_F(AssetSeedManagerTest, AddSeedAssetForValidPlatforms_NoPlatformsValid_NoSeedAdded)
|
||||
{
|
||||
using namespace AzFramework;
|
||||
PlatformFlags inputPlatforms = PlatformFlags::Platform_OSX;
|
||||
PlatformFlags inputPlatforms = PlatformFlags::Platform_MAC;
|
||||
AZStd::pair<AZ::Data::AssetId, PlatformFlags> result = m_assetSeedManager->AddSeedAssetForValidPlatforms(TestDynamicSliceAssetPath, inputPlatforms);
|
||||
|
||||
// Verify the function outputs
|
||||
@@ -978,30 +985,30 @@ namespace UnitTest
|
||||
|
||||
TEST_F(AssetSeedManagerTest, Valid_Seed_Remove_ForAllPlatform_OK)
|
||||
{
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[0].ToString<AZStd::string>(), AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[0].ToString<AZStd::string>(), AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
const AzFramework::AssetSeedList& seedList = m_assetSeedManager->GetAssetSeedList();
|
||||
|
||||
EXPECT_EQ(seedList.size(), 0);
|
||||
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
|
||||
m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList();
|
||||
EXPECT_EQ(secondSeedList.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(AssetSeedManagerTest, Valid_Seed_Remove_ForSpecificPlatform_OK)
|
||||
{
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[0].ToString<AZStd::string>(), AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[0].ToString<AZStd::string>(), AzFramework::PlatformFlags::Platform_MAC);
|
||||
const AzFramework::AssetSeedList& seedList = m_assetSeedManager->GetAssetSeedList();
|
||||
|
||||
EXPECT_EQ(seedList.size(), 1);
|
||||
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
|
||||
m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC);
|
||||
const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList();
|
||||
@@ -1010,14 +1017,14 @@ namespace UnitTest
|
||||
|
||||
TEST_F(AssetSeedManagerTest, Invalid_NotRemove_SeedForAllPlatform_Ok)
|
||||
{
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[1].ToString<AZStd::string>(), AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[1].ToString<AZStd::string>(), AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
const AzFramework::AssetSeedList& seedList = m_assetSeedManager->GetAssetSeedList();
|
||||
|
||||
EXPECT_EQ(seedList.size(), 1);
|
||||
|
||||
m_assetSeedManager->RemoveSeedAsset("asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
|
||||
m_assetSeedManager->RemoveSeedAsset("asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_MAC);
|
||||
const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList();
|
||||
EXPECT_EQ(secondSeedList.size(), 1);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace UnitTests
|
||||
MOCK_METHOD0(GetAbsoluteDevGameFolderPath, const char* ());
|
||||
MOCK_METHOD0(GetAbsoluteDevRootFolderPath, const char* ());
|
||||
MOCK_METHOD2(GetRelativeProductPathFromFullSourceOrProductPath, bool(const AZStd::string& fullPath, AZStd::string& relativeProductPath));
|
||||
MOCK_METHOD3(GenerateRelativeSourcePath,
|
||||
bool(const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder));
|
||||
MOCK_METHOD2(GetFullSourcePathFromRelativeProductPath, bool(const AZStd::string& relPath, AZStd::string& fullSourcePath));
|
||||
MOCK_METHOD5(GetAssetInfoById, bool(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, AZStd::string& rootFilePath));
|
||||
MOCK_METHOD3(GetSourceInfoBySourcePath, bool(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder));
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogManager.h>
|
||||
#include <AzFramework/Asset/AssetRegistry.h>
|
||||
@@ -49,6 +51,14 @@ namespace UnitTest
|
||||
using namespace AZ::Data;
|
||||
m_application = new ToolsTestApplication("AddressedAssetCatalogManager"); // Shorter name because Setting Registry
|
||||
// specialization are 32 characters max.
|
||||
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_application->Start(AzFramework::Application::Descriptor());
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
@@ -174,13 +184,13 @@ namespace UnitTest
|
||||
TEST_F(PlatformAddressedAssetCatalogManagerTest, PlatformAddressedAssetCatalogManager_CatalogExistsChecks_Success)
|
||||
{
|
||||
|
||||
EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ES3), true);
|
||||
AZStd::string es3CatalogPath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ES3);
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(es3CatalogPath.c_str()))
|
||||
EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ANDROID_ID), true);
|
||||
AZStd::string androidCatalogPath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID);
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(androidCatalogPath.c_str()))
|
||||
{
|
||||
AZ::IO::FileIOBase::GetInstance()->Remove(es3CatalogPath.c_str());
|
||||
AZ::IO::FileIOBase::GetInstance()->Remove(androidCatalogPath.c_str());
|
||||
}
|
||||
EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ES3), false);
|
||||
EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ANDROID_ID), false);
|
||||
}
|
||||
|
||||
class PlatformAddressedAssetCatalogMessageTest : public AzToolsFramework::PlatformAddressedAssetCatalog
|
||||
@@ -241,7 +251,7 @@ namespace UnitTest
|
||||
AzFramework::AssetSystem::NetworkAssetUpdateInterface* notificationInterface = AZ::Interface<AzFramework::AssetSystem::NetworkAssetUpdateInterface>::Get();
|
||||
EXPECT_NE(notificationInterface, nullptr);
|
||||
|
||||
auto* mockCatalog = new ::testing::NiceMock<PlatformAddressedAssetCatalogMessageTest>(AzFramework::PlatformId::ES3);
|
||||
auto* mockCatalog = new ::testing::NiceMock<PlatformAddressedAssetCatalogMessageTest>(AzFramework::PlatformId::ANDROID_ID);
|
||||
AZStd::unique_ptr< ::testing::NiceMock<PlatformAddressedAssetCatalogMessageTest>> catalogHolder;
|
||||
catalogHolder.reset(mockCatalog);
|
||||
|
||||
@@ -249,7 +259,7 @@ namespace UnitTest
|
||||
EXPECT_CALL(*mockCatalog, AssetChanged(testing::_)).Times(0);
|
||||
notificationInterface->AssetChanged(testMessage);
|
||||
|
||||
testMessage.m_platform = "es3";
|
||||
testMessage.m_platform = "android";
|
||||
EXPECT_CALL(*mockCatalog, AssetChanged(testing::_)).Times(1);
|
||||
notificationInterface->AssetChanged(testMessage);
|
||||
|
||||
@@ -260,7 +270,7 @@ namespace UnitTest
|
||||
EXPECT_CALL(*mockCatalog, AssetRemoved(testing::_)).Times(0);
|
||||
notificationInterface->AssetRemoved(testMessage);
|
||||
|
||||
testMessage.m_platform = "es3";
|
||||
testMessage.m_platform = "android";
|
||||
EXPECT_CALL(*mockCatalog, AssetRemoved(testing::_)).Times(1);
|
||||
notificationInterface->AssetRemoved(testMessage);
|
||||
}
|
||||
|
||||
+2
-1
@@ -34,7 +34,8 @@ namespace Benchmark
|
||||
{
|
||||
state.PauseTiming();
|
||||
|
||||
auto spawnable = ::AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(prefabDom);
|
||||
AzFramework::Spawnable spawnable;
|
||||
AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(spawnable, prefabDom);
|
||||
|
||||
state.ResumeTiming();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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/TransformComponent.h>
|
||||
|
||||
#include <Prefab/PrefabTestComponent.h>
|
||||
#include <Prefab/PrefabTestDomUtils.h>
|
||||
#include <Prefab/PrefabTestFixture.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using PrefabDuplicateTest = PrefabTestFixture;
|
||||
|
||||
TEST_F(PrefabDuplicateTest, PrefabDuplicate_DuplicateSingleEntitySucceeds)
|
||||
{
|
||||
AZStd::string entityName("Same Name");
|
||||
AZ::Entity* entity1 = CreateEntity(entityName.c_str());
|
||||
entity1->Deactivate();
|
||||
entity1->CreateComponent<PrefabTestComponent>();
|
||||
entity1->Activate();
|
||||
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, AzToolsFramework::EntityList{ entity1 });
|
||||
AZStd::unique_ptr<Instance> newInstance = m_prefabSystemComponent->CreatePrefab(
|
||||
{ entity1 },
|
||||
{},
|
||||
PrefabMockFilePath);
|
||||
|
||||
// We've created a prefab with a single Entity, so there should only be one EntityAlias in our instance
|
||||
EXPECT_EQ(newInstance->GetEntityAliases().size(), 1);
|
||||
|
||||
// Duplicate the Entity and trigger the UpdateTemplateInstancesInQueue so the changes get propagated
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(AzToolsFramework::EntityIdList{ entity1->GetId() });
|
||||
m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
|
||||
|
||||
// We duplicated a single Entity, so there should now be two EntityAliases
|
||||
EXPECT_EQ(newInstance->GetEntityAliases().size(), 2);
|
||||
|
||||
newInstance->GetConstEntities([&](const AZ::Entity& entity)
|
||||
{
|
||||
// Both of the entities should have the same name
|
||||
EXPECT_EQ(entity.GetName(), entityName);
|
||||
|
||||
// Both of the entities should have the PrefabTestComponent we added
|
||||
auto testComponent = entity.FindComponent<PrefabTestComponent>();
|
||||
EXPECT_NE(nullptr, testComponent);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(PrefabDuplicateTest, PrefabDuplicate_DuplicateMultipleEntitiesAndFixesReferences)
|
||||
{
|
||||
AZ::Entity* parentEntity = CreateEntity("Parent Entity");
|
||||
|
||||
AZ::Entity* childEntity = CreateEntity("Child Entity");
|
||||
childEntity->Deactivate();
|
||||
auto newComponent = childEntity->CreateComponent<PrefabTestComponent>();
|
||||
childEntity->Activate();
|
||||
|
||||
// Set the EntityId reference property on our PrefabTestComponent so we can
|
||||
// verify that arbitrary EntityId's are fixed up properly
|
||||
newComponent->m_entityIdProperty = parentEntity->GetId();
|
||||
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, AzToolsFramework::EntityList{ parentEntity, childEntity });
|
||||
|
||||
AZStd::unique_ptr<Instance> newInstance = m_prefabSystemComponent->CreatePrefab(
|
||||
{ parentEntity, childEntity },
|
||||
{},
|
||||
PrefabMockFilePath);
|
||||
|
||||
// We've created a prefab with two entities, so there should be two EntityAliases in our instance
|
||||
EXPECT_EQ(newInstance->GetEntityAliases().size(), 2);
|
||||
|
||||
// Duplicate the entities and trigger the UpdateTemplateInstancesInQueue so the changes get propagated
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(AzToolsFramework::EntityIdList{ parentEntity->GetId(), childEntity->GetId() });
|
||||
m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
|
||||
|
||||
// We duplicated two entities, so there should now be four EntityAliases
|
||||
EXPECT_EQ(newInstance->GetEntityAliases().size(), 4);
|
||||
|
||||
AzToolsFramework::EntityIdList parentEntityIds;
|
||||
newInstance->GetConstEntities([&](const AZ::Entity& entity)
|
||||
{
|
||||
// Gather the parent EntityIds by tracking which entities don't have a PrefabTestComponent
|
||||
auto testComponent = entity.FindComponent<PrefabTestComponent>();
|
||||
if (!testComponent)
|
||||
{
|
||||
parentEntityIds.push_back(entity.GetId());
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// There should only be two parents
|
||||
EXPECT_EQ(parentEntityIds.size(), 2);
|
||||
|
||||
// Verify that the EntityId reference on the PrefabTestComponent on the children correspond
|
||||
// to unique entities, which will verify that the EntityIds are fixed up on duplicate
|
||||
newInstance->GetConstEntities([&](const AZ::Entity& entity)
|
||||
{
|
||||
// Only the child entities have a PrefabTestComponent
|
||||
auto testComponent = entity.FindComponent<PrefabTestComponent>();
|
||||
if (testComponent)
|
||||
{
|
||||
auto it = AZStd::find(parentEntityIds.begin(), parentEntityIds.end(), testComponent->m_entityIdProperty);
|
||||
EXPECT_NE(it, parentEntityIds.end());
|
||||
|
||||
// Erase when we find it so that the matches will be unique
|
||||
parentEntityIds.erase(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Verify we matched each of the parent EntityIds
|
||||
EXPECT_EQ(parentEntityIds.size(), 0);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,17 @@
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
PrefabTestToolsApplication::PrefabTestToolsApplication(AZStd::string appName)
|
||||
: ToolsTestApplication(AZStd::move(appName))
|
||||
{
|
||||
}
|
||||
|
||||
bool PrefabTestToolsApplication::IsPrefabSystemEnabled() const
|
||||
{
|
||||
// Make sure our prefab tests always run with prefabs enabled
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrefabTestFixture::SetUpEditorFixtureImpl()
|
||||
{
|
||||
// Acquire the system entity
|
||||
@@ -32,6 +43,9 @@ namespace UnitTest
|
||||
m_prefabLoaderInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabLoaderInterface>::Get();
|
||||
EXPECT_TRUE(m_prefabLoaderInterface);
|
||||
|
||||
m_prefabPublicInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabPublicInterface>::Get();
|
||||
EXPECT_TRUE(m_prefabPublicInterface);
|
||||
|
||||
m_instanceUpdateExecutorInterface = AZ::Interface<AzToolsFramework::Prefab::InstanceUpdateExecutorInterface>::Get();
|
||||
EXPECT_TRUE(m_instanceUpdateExecutorInterface);
|
||||
|
||||
@@ -41,6 +55,11 @@ namespace UnitTest
|
||||
GetApplication()->RegisterComponentDescriptor(PrefabTestComponent::CreateDescriptor());
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<ToolsTestApplication> PrefabTestFixture::CreateTestApplication()
|
||||
{
|
||||
return AZStd::make_unique<PrefabTestToolsApplication>("PrefabTestApplication");
|
||||
}
|
||||
|
||||
AZ::Entity* PrefabTestFixture::CreateEntity(const char* entityName, const bool shouldActivate)
|
||||
{
|
||||
// Circumvent the EntityContext system and generate a new entity with a transformcomponent
|
||||
|
||||
@@ -31,6 +31,16 @@ namespace UnitTest
|
||||
using namespace AzToolsFramework::Prefab;
|
||||
using namespace PrefabTestUtils;
|
||||
|
||||
class PrefabTestToolsApplication
|
||||
: public ToolsTestApplication
|
||||
{
|
||||
public:
|
||||
PrefabTestToolsApplication(AZStd::string appName);
|
||||
|
||||
// Make sure our prefab tests always run with prefabs enabled
|
||||
bool IsPrefabSystemEnabled() const override;
|
||||
};
|
||||
|
||||
class PrefabTestFixture
|
||||
: public ToolsApplicationFixture,
|
||||
public UnitTest::TraceBusRedirector
|
||||
@@ -45,6 +55,8 @@ namespace UnitTest
|
||||
|
||||
void SetUpEditorFixtureImpl() override;
|
||||
|
||||
AZStd::unique_ptr<ToolsTestApplication> CreateTestApplication() override;
|
||||
|
||||
AZ::Entity* CreateEntity(const char* entityName, const bool shouldActivate = true);
|
||||
|
||||
void CompareInstances(const Instance& instanceA, const Instance& instanceB, bool shouldCompareLinkIds = true,
|
||||
@@ -57,6 +69,7 @@ namespace UnitTest
|
||||
|
||||
PrefabSystemComponent* m_prefabSystemComponent = nullptr;
|
||||
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
|
||||
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
InstanceUpdateExecutorInterface* m_instanceUpdateExecutorInterface = nullptr;
|
||||
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
|
||||
};
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace UnitTest
|
||||
|
||||
//Create Spawnable
|
||||
auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(instance->GetTemplateId());
|
||||
auto spawnable = ::AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(prefabDom);
|
||||
AzFramework::Spawnable spawnable;
|
||||
AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(spawnable, prefabDom);
|
||||
|
||||
EXPECT_EQ(spawnable.GetEntities().size() - 1, normalEntityCount); // 1 for container entity
|
||||
const auto& spawnableEntities = spawnable.GetEntities();
|
||||
@@ -84,7 +85,8 @@ namespace UnitTest
|
||||
|
||||
//Create Spawnable
|
||||
auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(thirdInstance->GetTemplateId());
|
||||
auto spawnable = ::AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(prefabDom);
|
||||
AzFramework::Spawnable spawnable;
|
||||
AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(spawnable, prefabDom);
|
||||
|
||||
EXPECT_EQ(spawnable.GetEntities().size() - 1, normalEntityCount); // 1 for container entity
|
||||
const auto& spawnableEntities = spawnable.GetEntities();
|
||||
|
||||
@@ -483,6 +483,9 @@ namespace UnitTest
|
||||
{
|
||||
AUTO_RESULT_IF_SETTING_TRUE(UnitTest::prefabSystemSetting, true)
|
||||
|
||||
// Swallow deprecation warnings from the Transform component as they are not relevant to this test
|
||||
UnitTest::ErrorHandler errorHandler("GetScale is deprecated");
|
||||
|
||||
// Create a parent entity with a transform component
|
||||
AZ::Entity* parentEntity = aznew AZ::Entity("TestParentEntity");
|
||||
parentEntity->CreateComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ namespace UnitTest
|
||||
|
||||
// Set the new entity's transform to non zero values
|
||||
// This helps validate in comparison tests that the transform values of created entities persist during slice operations
|
||||
entityTransform->SetLocalScale(AZ::Vector3(5, 5, 5));
|
||||
entityTransform->SetLocalUniformScale(5);
|
||||
entityTransform->SetLocalRotation(AZ::Vector3RadToDeg(AZ::Vector3(90, 90, 90)));
|
||||
entityTransform->SetLocalTranslation(AZ::Vector3(100, 100, 100));
|
||||
|
||||
|
||||
+3
@@ -149,6 +149,9 @@ namespace UnitTest
|
||||
const char* GetAbsoluteDevGameFolderPath() override { return ""; }
|
||||
const char* GetAbsoluteDevRootFolderPath() override { return ""; }
|
||||
bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) override { return false; }
|
||||
bool GenerateRelativeSourcePath(
|
||||
[[maybe_unused]] const AZStd::string& sourcePath, [[maybe_unused]] AZStd::string& relativePath,
|
||||
[[maybe_unused]] AZStd::string& watchFolder) override { return false; }
|
||||
bool GetFullSourcePathFromRelativeProductPath([[maybe_unused]] const AZStd::string& relPath, [[maybe_unused]] AZStd::string& fullSourcePath) override { return false; }
|
||||
bool GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& assetId, [[maybe_unused]] const AZ::Data::AssetType& assetType, [[maybe_unused]] const AZStd::string& platformName, [[maybe_unused]] AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] AZStd::string& rootFilePath) override { return false; }
|
||||
bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override;
|
||||
|
||||
@@ -610,15 +610,15 @@ namespace AzToolsFramework
|
||||
m_layerEntity.m_layer->ClearUnsavedChanges();
|
||||
|
||||
// Change the scale of the child entity so it registers as an unsaved change on the layer.
|
||||
AZ::Vector3 scale(-1.0f,0.0f,0.0f);
|
||||
float scale = 0.0f;
|
||||
AZ::TransformBus::EventResult(
|
||||
scale,
|
||||
childEntity->GetId(),
|
||||
&AZ::TransformBus::Events::GetLocalScale);
|
||||
scale.SetX(scale.GetX() + 1.0f);
|
||||
&AZ::TransformBus::Events::GetLocalUniformScale);
|
||||
scale += 1.0f;
|
||||
AZ::TransformBus::Event(
|
||||
childEntity->GetId(),
|
||||
&AZ::TransformBus::Events::SetLocalScale,
|
||||
&AZ::TransformBus::Events::SetLocalUniformScale,
|
||||
scale);
|
||||
|
||||
bool hasUnsavedChanges = false;
|
||||
|
||||
+8
-8
@@ -52,19 +52,19 @@ namespace AzToolsFramework
|
||||
TransformTestEntityHierarchy hierarchy = BuildTestHierarchy();
|
||||
|
||||
// Set scale to parent entity
|
||||
const AZ::Vector3 parentScale(2.0f, 1.0f, 3.0f);
|
||||
AZ::TransformBus::Event(hierarchy.m_parentId, &AZ::TransformInterface::SetLocalScale, parentScale);
|
||||
const float parentScale = 2.0f;
|
||||
AZ::TransformBus::Event(hierarchy.m_parentId, &AZ::TransformInterface::SetLocalUniformScale, parentScale);
|
||||
|
||||
// Set scale to child entity
|
||||
const AZ::Vector3 childScale(5.0f, 6.0f, 10.0f);
|
||||
AZ::TransformBus::Event(hierarchy.m_childId, &AZ::TransformInterface::SetLocalScale, childScale);
|
||||
const float childScale = 5.0f;
|
||||
AZ::TransformBus::Event(hierarchy.m_childId, &AZ::TransformInterface::SetLocalUniformScale, childScale);
|
||||
|
||||
const AZ::Vector3 expectedScale = childScale * parentScale;
|
||||
const float expectedScale = childScale * parentScale;
|
||||
|
||||
AZ::Vector3 childWorldScale = AZ::Vector3::CreateOne();
|
||||
AZ::TransformBus::EventResult(childWorldScale, hierarchy.m_childId, &AZ::TransformBus::Events::GetWorldScale);
|
||||
float childWorldScale = 1.0f;
|
||||
AZ::TransformBus::EventResult(childWorldScale, hierarchy.m_childId, &AZ::TransformBus::Events::GetWorldUniformScale);
|
||||
|
||||
EXPECT_THAT(childWorldScale, UnitTest::IsClose(expectedScale));
|
||||
EXPECT_NEAR(childWorldScale, expectedScale, AZ::Constants::Tolerance);
|
||||
}
|
||||
|
||||
TEST_F(EditorTransformComponentTest, TransformTests_GetChildren_DirectChildrenMatchHierarchy)
|
||||
|
||||
@@ -54,6 +54,7 @@ set(FILES
|
||||
Prefab/Spawnable/SpawnableMetaDataTests.cpp
|
||||
Prefab/MockPrefabFileIOActionValidator.cpp
|
||||
Prefab/MockPrefabFileIOActionValidator.h
|
||||
Prefab/PrefabDuplicateTests.cpp
|
||||
Prefab/PrefabEntityAliasTests.cpp
|
||||
Prefab/PrefabInstanceToTemplatePropagatorTests.cpp
|
||||
Prefab/PrefabInstantiateTests.cpp
|
||||
|
||||
Reference in New Issue
Block a user