diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts
index a7d29e2dbc..5cafabaf60 100644
--- a/Assets/Editor/Translation/scriptcanvas_en_us.ts
+++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts
@@ -14679,6 +14679,25 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
+
+ Method: NetBindComponent
+
+ NETBINDCOMPONENT_ISNETENTITYROLEAUTHORITY_TOOLTIP
+ Returns true if this network entity is an authoritative proxy on a server (full authority); otherwise false.
+
+
+ NETBINDCOMPONENT_ISNETENTITYROLEAUTONOMOUS_TOOLTIP
+ Returns true if this network entity is an autonomous proxy on a client (can execute local prediction) or if this network entity is an authoritative proxy on a server but has autonomous privileges (ie: a host who is also a player); otherwise false.
+
+
+ NETBINDCOMPONENT_ISNETENTITYROLECLIENT_TOOLTIP
+ Returns true if this network entity is a simulated proxy on a client; otherwise false.
+
+
+ NETBINDCOMPONENT_ISNETENTITYROLESERVER_TOOLTIP
+ Returns true if this network entity is a simulated proxy on a server (ie: a different server may own this entity, but the entity has been replicated to this server; otherwise false.
+
+
Method: Math
diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py
index 5d4218efd0..c195672760 100644
--- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py
+++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py
@@ -79,8 +79,6 @@ class TestBasicEditorWorkflows(EditorTestHelper):
grp_box = new_level_dlg.findChild(QtWidgets.QGroupBox, "STATIC_GROUP1")
level_name = grp_box.findChild(QtWidgets.QLineEdit, "LEVEL")
level_name.setText(self.args["level"])
- level_folders = grp_box.findChild(QtWidgets.QComboBox, "LEVEL_FOLDERS")
- level_folders.setCurrentText("Levels/")
button_box = new_level_dlg.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetTypeInfoBus.h b/Code/Framework/AzCore/AzCore/Asset/AssetTypeInfoBus.h
index 48115b53af..f49b3ff6e5 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetTypeInfoBus.h
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetTypeInfoBus.h
@@ -57,7 +57,13 @@ namespace AZ
//! Determines if a component can be created from the asset type
//! This will be called before attempting to create a component from an asset (drag&drop, etc)
//! You can use this to filter by subIds or do your own validation here if needed
- virtual bool CanCreateComponent(const AZ::Data::AssetId& /*assetId*/) const { return true; }
+ virtual bool CanCreateComponent([[maybe_unused]] const AZ::Data::AssetId& assetId) const { return true; }
+
+ //! Determines if other products conflict with the given one when multiple are generated from a source asset.
+ //! This will be called before attempting to create a component from an asset (drag&drop, etc)
+ //! You can use this to filter by conflicting product types or in case you want to skip for UX reasons.
+ //! @param[in] productAssetTypes Asset types of all generated products, including the one for our given type in this bus.
+ virtual bool HasConflictingProducts([[maybe_unused]] const AZStd::vector& productAssetTypes) const { return false; }
};
using AssetTypeInfoBus = AZ::EBus;
diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h b/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
index 9d7e58dd36..a46d8ad9d4 100644
--- a/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
+++ b/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
@@ -1206,7 +1206,7 @@ namespace JsonSerializationTests
if (this->m_features.m_enableInitializationTest)
{
auto instance = this->m_description.CreateDefaultInstance();
- typename TypeParam::Type compare = typename TypeParam::Type{};
+ AZStd::remove_cvref_t compare;
if (!this->m_description.AreEqual(*instance, compare))
{
auto serializer = this->m_description.CreateSerializer();
diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm
index 3eba9831b4..8b911c90e9 100644
--- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm
+++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm
@@ -75,6 +75,8 @@ namespace AzFramework
// Add a fullscreen button in the upper right of the title bar.
[m_nativeWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ m_nativeWindow.tabbingMode = NSWindowTabbingModeDisallowed;
+
// Make the window active
[m_nativeWindow makeKeyAndOrderFront:nil];
m_nativeWindow.title = m_windowTitle;
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp
index 0f58f06420..0d770d2d8e 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp
@@ -493,7 +493,30 @@ namespace AzQtComponents
}
}
break;
- }
+ case CE_MenuItem:
+ {
+ const QMenu* menu = qobject_cast(widget);
+ QAction* action = menu->activeAction();
+ if (action)
+ {
+ QMenu* subMenu = action->menu();
+ if (subMenu)
+ {
+ QVariant noHover = subMenu->property("noHover");
+ if (noHover.isValid() && noHover.toBool())
+ {
+ // First draw as standard to get the correct hover background for the complete control.
+ QProxyStyle::drawControl(element, option, painter, widget);
+ // Now draw the icon as non-hovered so control behaves as designed.
+ QStyleOptionMenuItem myOpt = *qstyleoption_cast(option);
+ myOpt.state &= ~QStyle::State_Selected;
+ return QProxyStyle::drawControl(element, &myOpt, painter, widget);
+ }
+ }
+ }
+ }
+ break;
+ }
return QProxyStyle::drawControl(element, option, painter, widget);
}
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg
new file mode 100644
index 0000000000..e782a7066a
--- /dev/null
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/menu.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/menu.svg
new file mode 100644
index 0000000000..e97da32e09
--- /dev/null
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/menu.svg
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg
index dfd21d157f..6f5608c092 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg
@@ -1,4 +1,4 @@
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc
index cc66558367..74610dca90 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc
@@ -28,5 +28,7 @@
Menu/script_canvas_editor.svg
Menu/trackview_editor.svg
Menu/ui_editor.svg
+ Menu/menu.svg
+ Menu/helpers.svg
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp
index 336b56653b..1172fc7162 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp
@@ -524,8 +524,6 @@ namespace AzToolsFramework
rootSpawnableIndex = m_playInEditorData.m_assets.size();
}
- LoadReferencedAssets(product.GetReferencedAssets());
-
AZ::Data::AssetInfo info;
info.m_assetId = product.GetAsset().GetId();
info.m_assetType = product.GetAssetType();
@@ -534,6 +532,19 @@ namespace AzToolsFramework
AZ::Data::AssetCatalogRequestBus::Broadcast(
&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, info.m_assetId, info);
m_playInEditorData.m_assets.emplace_back(product.ReleaseAsset().release(), AZ::Data::AssetLoadBehavior::Default);
+
+ // Ensure the product asset is registered with the AssetManager
+ // Hold on to the returned asset to keep ref count alive until we assign it the latest data
+ AZ::Data::Asset asset =
+ AZ::Data::AssetManager::Instance().FindOrCreateAsset(info.m_assetId, info.m_assetType, AZ::Data::AssetLoadBehavior::Default);
+
+ // Update the asset registered in the AssetManager with the data of our product from the Prefab Processor
+ AZ::Data::AssetManager::Instance().AssignAssetData(m_playInEditorData.m_assets.back());
+ }
+
+ for (auto& product : context.GetProcessedObjects())
+ {
+ LoadReferencedAssets(product.GetReferencedAssets());
}
// make sure that PRE_NOTIFY assets get their notify before we activate, so that we can preserve the order of
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
index 3d02e797cc..a5cd50b36e 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
@@ -922,8 +922,8 @@ namespace AzToolsFramework
return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided."));
}
- // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
- // cannot duplicate an instance from itself.
+ // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance
+ // This is because containers, despite representing the nested instance in the parent, are owned by the child.
if (commonOwningInstance->get().GetContainerEntityId() == firstEntityIdToDuplicate)
{
commonOwningInstance = commonOwningInstance->get().GetParentInstance();
@@ -967,17 +967,18 @@ namespace AzToolsFramework
// Duplicate any nested entities and instances as requested
AZStd::unordered_map newInstanceAliasToOldInstanceMap;
+ AZStd::unordered_map duplicateEntityAliasMap;
DuplicateNestedEntitiesInInstance(commonOwningInstance->get(),
- entities, instanceDomAfter, duplicatedEntityAndInstanceIds);
- DuplicateNestedInstancesInInstance(commonOwningInstance->get(),
- instances, instanceDomAfter, duplicatedEntityAndInstanceIds,
- newInstanceAliasToOldInstanceMap);
+ entities, instanceDomAfter, duplicatedEntityAndInstanceIds, duplicateEntityAliasMap);
PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication");
command->SetParent(undoBatch.GetUndoBatch());
command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId());
command->Redo();
+ DuplicateNestedInstancesInInstance(commonOwningInstance->get(),
+ instances, instanceDomAfter, duplicatedEntityAndInstanceIds, newInstanceAliasToOldInstanceMap);
+
// Create links for our duplicated instances (if any were duplicated)
for (auto [newInstanceAlias, oldInstance] : newInstanceAliasToOldInstanceMap)
{
@@ -995,8 +996,35 @@ namespace AzToolsFramework
PrefabDom linkPatchesCopy;
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
- m_prefabSystemComponentInterface->CreateLink(
- commonOwningInstance->get().GetTemplateId(), oldInstance->GetTemplateId(), newInstanceAlias, linkPatchesCopy);
+ // If the instance was duplicated as part of an ancestor's nested hierarchy, the container's parent patch
+ // will need to be refreshed to point to the new duplicated parent entity
+ auto oldInstanceContainerEntityId = oldInstance->GetContainerEntityId();
+ AZ_Assert(oldInstanceContainerEntityId.IsValid(), "Instance returned invalid Container Entity Id");
+
+ AZ::EntityId previousParentEntityId;
+ AZ::TransformBus::EventResult(previousParentEntityId, oldInstanceContainerEntityId, &AZ::TransformBus::Events::GetParentId);
+
+ if (previousParentEntityId.IsValid() && AZStd::find(duplicatedEntityAndInstanceIds.begin(), duplicatedEntityAndInstanceIds.end(), previousParentEntityId))
+ {
+ auto oldParentAlias = commonOwningInstance->get().GetEntityAlias(previousParentEntityId);
+ if (oldParentAlias.has_value() && duplicateEntityAliasMap.contains(oldParentAlias->get()))
+ {
+ // Get the dom into a QString for search/replace purposes
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer writer(buffer);
+ linkPatchesCopy.Accept(writer);
+
+ QString linkPatchesString(buffer.GetString());
+
+ ReplaceOldAliases(linkPatchesString, oldParentAlias->get(), duplicateEntityAliasMap[oldParentAlias->get()]);
+
+ linkPatchesCopy.Parse(linkPatchesString.toUtf8().constData());
+ }
+ }
+
+ PrefabUndoHelpers::CreateLink(
+ oldInstance->GetTemplateId(), commonOwningInstance->get().GetTemplateId(),
+ AZStd::move(linkPatchesCopy), newInstanceAlias, undoBatch.GetUndoBatch());
}
// Select the duplicated entities/instances
@@ -1507,14 +1535,13 @@ namespace AzToolsFramework
void PrefabPublicHandler::DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance,
const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder,
- EntityIdList& duplicatedEntityIds)
+ EntityIdList& duplicatedEntityIds, AZStd::unordered_map& oldAliasToNewAliasMap)
{
if (entities.empty())
{
return;
}
- AZStd::unordered_map oldAliasToNewAliasMap;
AZStd::unordered_map aliasToEntityDomMap;
for (AZ::Entity* entity : entities)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
index 65e1391722..fc5906c80e 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
@@ -87,7 +87,7 @@ namespace AzToolsFramework
*/
void DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance,
const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder,
- EntityIdList& duplicatedEntityIds);
+ EntityIdList& duplicatedEntityIds, AZStd::unordered_map& oldAliasToNewAliasMap);
/**
* Duplicate a list of instances owned by a common owning instance by directly
* copying/modifying their entries in the instance DOM
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp
index f72de82f36..4cd18cbc91 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
@@ -57,6 +58,13 @@ namespace AzToolsFramework
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly);
}
}
+
+ if (auto behaviorContext = azrtti_cast(context))
+ {
+ behaviorContext->ConstantProperty("EditorNonUniformScaleComponentTypeId", BehaviorConstant(EditorNonUniformScaleComponent::RTTI_Type()))
+ ->Attribute(AZ::Script::Attributes::Module, "editor")
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
+ }
}
void EditorNonUniformScaleComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
index 85250f2a32..b4d0342c44 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
@@ -210,6 +210,19 @@ namespace AzToolsFramework
//! Type to inherit to implement ViewportInteractionRequests.
using ViewportInteractionRequestBus = AZ::EBus;
+ //! An interface to notify when changes to viewport settings have happened.
+ class ViewportSettingNotifications
+ {
+ public:
+ virtual void OnGridSnappingChanged([[maybe_unused]] bool enabled) {}
+ virtual void OnDrawHelpersChanged([[maybe_unused]] bool enabled) {}
+
+ protected:
+ ViewportSettingNotifications() = default;
+ };
+
+ using ViewportSettingsNotificationBus = AZ::EBus;
+
//! Requests to freeze the Viewport Input
//! Added to prevent a bug with the legacy CryEngine Viewport code that would
//! keep doing raycast tests even when no level is loaded, causing a crash.
diff --git a/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
index e0ba106875..ce29b81a5c 100644
--- a/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
+++ b/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
@@ -56,7 +56,8 @@ namespace AzAssetBrowserRequestHandlerPrivate
using namespace AzToolsFramework;
using namespace AzToolsFramework::AssetBrowser;
// return true ONLY if we can handle the drop request in the viewport.
- bool CanSpawnEntityForProduct(const ProductAssetBrowserEntry* product)
+ bool CanSpawnEntityForProduct(const ProductAssetBrowserEntry* product,
+ AZStd::optional> optionalProductAssetTypes = AZStd::nullopt)
{
if (!product)
{
@@ -70,7 +71,6 @@ namespace AzAssetBrowserRequestHandlerPrivate
bool canCreateComponent = false;
AZ::AssetTypeInfoBus::EventResult(canCreateComponent, product->GetAssetType(), &AZ::AssetTypeInfo::CanCreateComponent, product->GetAssetId());
-
if (!canCreateComponent)
{
return false;
@@ -78,16 +78,25 @@ namespace AzAssetBrowserRequestHandlerPrivate
AZ::Uuid componentTypeId = AZ::Uuid::CreateNull();
AZ::AssetTypeInfoBus::EventResult(componentTypeId, product->GetAssetType(), &AZ::AssetTypeInfo::GetComponentTypeId);
-
- if (!componentTypeId.IsNull())
+ if (componentTypeId.IsNull())
{
// we have a component type that handles this asset.
- return true;
+ return false;
+ }
+
+ if (optionalProductAssetTypes.has_value())
+ {
+ bool hasConflictingProducts = false;
+ AZ::AssetTypeInfoBus::EventResult(hasConflictingProducts, product->GetAssetType(), &AZ::AssetTypeInfo::HasConflictingProducts, optionalProductAssetTypes.value());
+ if (hasConflictingProducts)
+ {
+ return false;
+ }
}
// additional operations can be added here.
- return false;
+ return true;
}
void SpawnEntityAtPoint(const ProductAssetBrowserEntry* product, AzQtComponents::ViewportDragContext* viewportDragContext, EntityIdList& spawnList, AzFramework::SliceInstantiationTicket& spawnTicket)
@@ -511,9 +520,16 @@ void AzAssetBrowserRequestHandler::Drop(QDropEvent* event, AzQtComponents::DragA
}
// Handle products
+ AZStd::vector productAssetTypes;
+ productAssetTypes.reserve(products.size());
+ for (const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* entry : products)
+ {
+ productAssetTypes.emplace_back(entry->GetAssetType());
+ }
+
for (const ProductAssetBrowserEntry* product : products)
{
- if (CanSpawnEntityForProduct(product))
+ if (CanSpawnEntityForProduct(product, productAssetTypes))
{
SpawnEntityAtPoint(product, viewportDragContext, spawnedEntities, spawnTicket);
}
diff --git a/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt
index 51620c6e37..6a5fb7c6c8 100644
--- a/Code/Sandbox/Editor/CMakeLists.txt
+++ b/Code/Sandbox/Editor/CMakeLists.txt
@@ -128,6 +128,7 @@ ly_add_target(
Legacy::EditorCore
RUNTIME_DEPENDENCIES
Gem::AtomViewportDisplayInfo
+ Legacy::EditorCommon
)
ly_add_source_properties(
SOURCES CryEdit.cpp
diff --git a/Code/Sandbox/Editor/Style/Editor.qss b/Code/Sandbox/Editor/Style/Editor.qss
index 2e96c73f35..726902bbd9 100644
--- a/Code/Sandbox/Editor/Style/Editor.qss
+++ b/Code/Sandbox/Editor/Style/Editor.qss
@@ -208,22 +208,9 @@ WelcomeScreenDialog QLabel
margin: 0;
}
-WelcomeScreenDialog QLabel#titleLabel
+WelcomeScreenDialog QLabel#currentProjectLabel
{
- font-size: 22px;
- line-height: 32px;
-}
-
-WelcomeScreenDialog QLabel#bodyLabel
-{
- font-size: 14px;
- line-height: 20px;
-}
-
-WelcomeScreenDialog QLabel[fontStyle="sectionTitle"], QLabel#titleLabel[fontStyle="sectionTitle"], QLabel#documentationLink
-{
- font-size: 16px;
- line-height: 24px;
+ margin-top: 10px;
}
WelcomeScreenDialog QPushButton
@@ -232,36 +219,20 @@ WelcomeScreenDialog QPushButton
line-height: 16px;
}
-WelcomeScreenDialog QFrame#viewContainer
-{
- background-color: transparent;
-}
-
-WelcomeScreenDialog QFrame#viewContainer[articleStyle="pinned"]
-{
- background: rgba(180,139,255,5%);
- border: 1px solid #B48BFF;
- box-shadow: 0 0 4px 0 rgba(0,0,0,50%);
-}
-
WelcomeScreenDialog QWidget#articleViewContainerRoot
{
- background: #111111;
+ background: #444444;
}
-WelcomeScreenDialog QScrollArea#previewArea
+WelcomeScreenDialog QWidget#levelViewFTUEContainer
{
- background-color: transparent;
+ background: #282828;
}
-WelcomeScreenDialog QWidget#articleViewContents
-{
- background-color: transparent;
-}
-
-WelcomeScreenDialog QFrame#imageFrame
-{
- background-color: transparent;
+QTableWidget#recentLevelTable::item {
+ background-color: rgb(64,64,64);
+ margin-bottom: 4px;
+ margin-top: 4px;
}
/* Particle Editor */
diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp
index dc4815eb6a..5b13b1d308 100644
--- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp
+++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp
@@ -45,6 +45,7 @@
#include
#include
+#include
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include "ui_ViewportTitleDlg.h"
@@ -57,13 +58,16 @@ inline namespace Helpers
{
void ToggleHelpers()
{
- GetIEditor()->GetDisplaySettings()->DisplayHelpers(!GetIEditor()->GetDisplaySettings()->IsDisplayHelpers());
+ const bool newValue = !GetIEditor()->GetDisplaySettings()->IsDisplayHelpers();
+ GetIEditor()->GetDisplaySettings()->DisplayHelpers(newValue);
GetIEditor()->Notify(eNotify_OnDisplayRenderUpdate);
- if (GetIEditor()->GetDisplaySettings()->IsDisplayHelpers() == false)
+ if (newValue == false)
{
GetIEditor()->GetObjectManager()->SendEvent(EVENT_HIDE_HELPER);
}
+ AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Broadcast(
+ &AzToolsFramework::ViewportInteraction::ViewportSettingNotifications::OnDrawHelpersChanged, newValue);
}
bool IsHelpersShown()
@@ -126,6 +130,7 @@ CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent)
SetupCameraDropdownMenu();
SetupResolutionDropdownMenu();
SetupViewportInformationMenu();
+ SetupHelpersButton();
SetupOverflowMenu();
Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequest, gSettings.bMuteAudio ? m_oMuteAudioRequest : m_oUnmuteAudioRequest);
@@ -207,15 +212,16 @@ void CViewportTitleDlg::SetupViewportInformationMenu()
}
+void CViewportTitleDlg::SetupHelpersButton()
+{
+ connect(m_ui->m_helpers, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers);
+ m_ui->m_helpers->setChecked(Helpers::IsHelpersShown());
+}
+
void CViewportTitleDlg::SetupOverflowMenu()
{
// Setup the overflow menu
QMenu* overFlowMenu = new QMenu(this);
- m_debugHelpersAction = new QAction("Debug Helpers", overFlowMenu);
- m_debugHelpersAction->setCheckable(true);
- m_debugHelpersAction->setChecked(Helpers::IsHelpersShown());
- connect(m_debugHelpersAction, &QAction::triggered, this, &CViewportTitleDlg::OnToggleHelpers);
- overFlowMenu->addAction(m_debugHelpersAction);
m_audioMuteAction = new QAction("Mute Audio", overFlowMenu);
connect(m_audioMuteAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedMuteAudio);
@@ -329,7 +335,7 @@ void CViewportTitleDlg::OnMaximize()
void CViewportTitleDlg::OnToggleHelpers()
{
Helpers::ToggleHelpers();
- m_debugHelpersAction->setChecked(Helpers::IsHelpersShown());
+ m_ui->m_helpers->setChecked(Helpers::IsHelpersShown());
}
void CViewportTitleDlg::SetNoViewportInfo()
@@ -755,7 +761,7 @@ void CViewportTitleDlg::OnEditorNotifyEvent(EEditorNotifyEvent event)
switch (event)
{
case eNotify_OnDisplayRenderUpdate:
- m_debugHelpersAction->setChecked(Helpers::IsHelpersShown());
+ m_ui->m_helpers->setChecked(Helpers::IsHelpersShown());
break;
case eNotify_OnBeginGameMode:
case eNotify_OnEndGameMode:
diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.h b/Code/Sandbox/Editor/ViewportTitleDlg.h
index 255354dcbb..e4670e7873 100644
--- a/Code/Sandbox/Editor/ViewportTitleDlg.h
+++ b/Code/Sandbox/Editor/ViewportTitleDlg.h
@@ -102,6 +102,7 @@ protected:
void SetupResolutionDropdownMenu();
void SetupViewportInformationMenu();
void SetupOverflowMenu();
+ void SetupHelpersButton();
QString m_title;
@@ -172,7 +173,6 @@ protected:
QAction* m_normalInformationAction = nullptr;
QAction* m_fullInformationAction = nullptr;
QAction* m_compactInformationAction = nullptr;
- QAction* m_debugHelpersAction = nullptr;
QAction* m_audioMuteAction = nullptr;
QAction* m_enableVRAction = nullptr;
QAction* m_enableGridSnappingAction = nullptr;
diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.ui b/Code/Sandbox/Editor/ViewportTitleDlg.ui
index 2d547bfa99..7d8e9d50d4 100644
--- a/Code/Sandbox/Editor/ViewportTitleDlg.ui
+++ b/Code/Sandbox/Editor/ViewportTitleDlg.ui
@@ -81,6 +81,18 @@
+ -
+
+
+
+ :/Menu/helpers.svg:/Menu/helpers.svg
+
+
+
+ true
+
+
+
-
@@ -94,7 +106,7 @@
- :/stylesheet/img/UI20/menu-centered.svg:/stylesheet/img/UI20/menu-centered.svg
+ :/Menu/menu.svg:/Menu/menu.svg
diff --git a/Code/Sandbox/Editor/WelcomeScreen/DefaultActiveProject.png b/Code/Sandbox/Editor/WelcomeScreen/DefaultActiveProject.png
new file mode 100644
index 0000000000..89c3a7cd47
--- /dev/null
+++ b/Code/Sandbox/Editor/WelcomeScreen/DefaultActiveProject.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:263e95489560dac6e5944ef3caba13e598f83ddead324b943ad7735ba015e1a9
+size 70727
diff --git a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp
index 6faf29dc8e..fa0b2d8135 100644
--- a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp
+++ b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp
@@ -15,7 +15,8 @@
#include "WelcomeScreenDialog.h"
// Qt
-#include
+#include
+#include
#include
#include
#include
@@ -24,6 +25,7 @@
#include
#include
#include
+#include
#include
@@ -74,65 +76,39 @@ static int GetSmallestScreenHeight()
WelcomeScreenDialog::WelcomeScreenDialog(QWidget* pParent)
: QDialog(new WindowDecorationWrapper(WindowDecorationWrapper::OptionAutoAttach | WindowDecorationWrapper::OptionAutoTitleBarButtons, pParent), Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::WindowTitleHint)
, ui(new Ui::WelcomeScreenDialog)
- , m_pRecentListModel(new QStringListModel(this))
, m_pRecentList(nullptr)
{
ui->setupUi(this);
- // Make our welcome screen checkboxes appear as toggle switches
- AzQtComponents::CheckBox::applyToggleSwitchStyle(ui->autoLoadLevel);
- AzQtComponents::CheckBox::applyToggleSwitchStyle(ui->showOnStartup);
+ ui->recentLevelTable->setColumnCount(3);
+ ui->recentLevelTable->setMouseTracking(true);
+ ui->recentLevelTable->setContextMenuPolicy(Qt::CustomContextMenu);
+ ui->recentLevelTable->horizontalHeader()->hide();
+ ui->recentLevelTable->verticalHeader()->hide();
+ ui->recentLevelTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ ui->recentLevelTable->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->recentLevelTable->setIconSize(QSize(20, 20));
+ installEventFilter(this);
- ui->autoLoadLevel->setChecked(gSettings.bAutoloadLastLevelAtStartup);
- ui->showOnStartup->setChecked(!gSettings.bShowDashboardAtStartup);
-
- ui->recentLevelList->setModel(m_pRecentListModel);
- ui->recentLevelList->setMouseTracking(true);
- ui->recentLevelList->setContextMenuPolicy(Qt::CustomContextMenu);
-
- auto currentProjectButtonMenu = new QMenu();
-
- ui->currentProjectButton->setMenu(currentProjectButtonMenu);
auto projectName = AZ::Utils::GetProjectName();
- ui->currentProjectButton->setText(projectName.c_str());
- ui->currentProjectButton->adjustSize();
- ui->currentProjectButton->setMinimumWidth(ui->currentProjectButton->width() + 40);
+ ui->currentProjectName->setText(projectName.c_str());
- ui->documentationLink->setCursor(Qt::PointingHandCursor);
- ui->documentationLink->installEventFilter(this);
+ ui->newLevelButton->setDefault(true);
- connect(ui->recentLevelList, &QWidget::customContextMenuRequested, this, &WelcomeScreenDialog::OnShowContextMenu);
+ // Hide these buttons until the new functionality is added
+ ui->gridButton->hide();
+ ui->objectListButton->hide();
+ ui->switchProjectButton->hide();
- connect(ui->recentLevelList, &QListView::entered, this, &WelcomeScreenDialog::OnShowToolTip);
- connect(ui->recentLevelList, &QListView::clicked, this, &WelcomeScreenDialog::OnRecentLevelListItemClicked);
+ connect(ui->recentLevelTable, &QWidget::customContextMenuRequested, this, &WelcomeScreenDialog::OnShowContextMenu);
+
+ connect(ui->recentLevelTable, &QTableWidget::entered, this, &WelcomeScreenDialog::OnShowToolTip);
+ connect(ui->recentLevelTable, &QTableWidget::clicked, this, &WelcomeScreenDialog::OnRecentLevelTableItemClicked);
connect(ui->newLevelButton, &QPushButton::clicked, this, &WelcomeScreenDialog::OnNewLevelBtnClicked);
+ connect(ui->levelFileLabel, &QLabel::linkActivated, this, &WelcomeScreenDialog::OnNewLevelLabelClicked);
connect(ui->openLevelButton, &QPushButton::clicked, this, &WelcomeScreenDialog::OnOpenLevelBtnClicked);
- connect(ui->newSliceButton, &QPushButton::clicked, this, &WelcomeScreenDialog::OnNewSliceBtnClicked);
- connect(ui->openSliceButton, &QPushButton::clicked, this, &WelcomeScreenDialog::OnOpenSliceBtnClicked);
-
- connect(ui->documentationButton, &QPushButton::clicked, this, &WelcomeScreenDialog::OnDocumentationBtnClicked);
- connect(ui->showOnStartup, &QCheckBox::clicked, this, &WelcomeScreenDialog::OnShowOnStartupBtnClicked);
- connect(ui->autoLoadLevel, &QCheckBox::clicked, this, &WelcomeScreenDialog::OnAutoLoadLevelBtnClicked);
-
- m_manifest = new News::ResourceManifest(
- std::bind(&WelcomeScreenDialog::SyncSuccess, this),
- std::bind(&WelcomeScreenDialog::SyncFail, this, std::placeholders::_1),
- std::bind(&WelcomeScreenDialog::SyncUpdate, this, std::placeholders::_1, std::placeholders::_2));
-
- m_articleViewContainer = new News::ArticleViewContainer(this, *m_manifest);
- connect(m_articleViewContainer, &News::ArticleViewContainer::scrolled,
- this, &WelcomeScreenDialog::previewAreaScrolled);
- ui->articleViewContainerRoot->layout()->addWidget(m_articleViewContainer);
-
- m_manifest->Sync();
-
-#ifndef ENABLE_SLICE_EDITOR
- ui->newSliceButton->hide();
- ui->openSliceButton->hide();
-#endif
-
// Adjust the height, if need be
// Do it in the constructor so that the WindowDecoratorWrapper handles it correctly
int smallestHeight = GetSmallestScreenHeight();
@@ -153,16 +129,10 @@ WelcomeScreenDialog::WelcomeScreenDialog(QWidget* pParent)
WelcomeScreenDialog::~WelcomeScreenDialog()
{
delete ui;
- delete m_manifest;
}
void WelcomeScreenDialog::done(int result)
{
- if (m_waitingOnAsync)
- {
- m_manifest->Abort();
- }
-
QDialog::done(result);
}
@@ -173,13 +143,11 @@ const QString& WelcomeScreenDialog::GetLevelPath()
bool WelcomeScreenDialog::eventFilter(QObject *watched, QEvent *event)
{
- if (watched == ui->documentationLink)
+ if (event->type() == QEvent::Show)
{
- if (event->type() == QEvent::MouseButtonRelease)
- {
- OnDocumentationBtnClicked(false);
- return true;
- }
+ ui->recentLevelTable->horizontalHeader()->resizeSection(0, ui->nameLabel->width());
+ ui->recentLevelTable->horizontalHeader()->resizeSection(1, ui->modifiedLabel->width());
+ ui->recentLevelTable->horizontalHeader()->resizeSection(2, ui->typeLabel->width());
}
return QDialog::eventFilter(watched, event);
@@ -207,7 +175,9 @@ void WelcomeScreenDialog::SetRecentFileList(RecentFileList* pList)
int nCurDir = sCurDir.length();
int recentListSize = pList->GetSize();
- for (int i = 0; i < recentListSize; ++i)
+ int currentRow = 0;
+ ui->recentLevelTable->setRowCount(recentListSize);
+ for (int i = 0; i < recentListSize; ++i)
{
const QString& recentFile = pList->m_arrNames[i];
if (recentFile.endsWith(m_levelExtension))
@@ -218,7 +188,7 @@ void WelcomeScreenDialog::SetRecentFileList(RecentFileList* pList)
if (sCurEntryDir.compare(sCurDir, Qt::CaseInsensitive) == 0)
{
QString fullPath = recentFile;
- QString name = Path::GetFileName(fullPath);
+ const QString name = Path::GetFile(fullPath);
Path::ConvertSlashToBackSlash(fullPath);
fullPath = Path::ToUnixPath(fullPath.toLower());
@@ -226,18 +196,34 @@ void WelcomeScreenDialog::SetRecentFileList(RecentFileList* pList)
if (fullPath.contains(gamePath))
{
- m_pRecentListModel->setStringList(m_pRecentListModel->stringList() << QString(name));
+ if (gSettings.prefabSystem)
+ {
+ QIcon icon;
+ icon.addFile(QString::fromUtf8(":/Level/level.svg"), QSize(), QIcon::Normal, QIcon::Off);
+ ui->recentLevelTable->setItem(currentRow, 0, new QTableWidgetItem(icon, name));
+ }
+ else
+ {
+ ui->recentLevelTable->setItem(currentRow, 0, new QTableWidgetItem(name));
+ }
+ QFileInfo file(recentFile);
+ QDateTime dateTime = file.lastModified();
+ QString date = QLocale::system().toString(dateTime.date(), QLocale::ShortFormat) + " " +
+ QLocale::system().toString(dateTime.time(), QLocale::LongFormat);
+ ui->recentLevelTable->setItem(currentRow, 1, new QTableWidgetItem(date));
+ ui->recentLevelTable->setItem(currentRow++, 2, new QTableWidgetItem(tr("Level")));
m_levels.push_back(std::make_pair(name, recentFile));
}
}
}
}
}
+ ui->recentLevelTable->setRowCount(currentRow);
+ ui->recentLevelTable->setMinimumHeight(currentRow * ui->recentLevelTable->verticalHeader()->defaultSectionSize());
+ ui->recentLevelTable->setMaximumHeight(currentRow * ui->recentLevelTable->verticalHeader()->defaultSectionSize());
+ ui->levelFileLabel->setVisible(currentRow ? false : true);
- ui->recentLevelList->setCurrentIndex(QModelIndex());
- int rowSize = ui->recentLevelList->sizeHintForRow(0) + ui->recentLevelList->spacing() * 2;
- ui->recentLevelList->setMinimumHeight(m_pRecentListModel->rowCount() * rowSize);
- ui->recentLevelList->setMaximumHeight(m_pRecentListModel->rowCount() * rowSize);
+ ui->recentLevelTable->setCurrentIndex(QModelIndex());
}
@@ -245,7 +231,7 @@ void WelcomeScreenDialog::RemoveLevelEntry(int index)
{
TNamePathPair levelPath = m_levels[index];
- m_pRecentListModel->removeRow(index);
+ ui->recentLevelTable->removeRow(index);
m_levels.erase(m_levels.begin() + index);
@@ -284,21 +270,18 @@ void WelcomeScreenDialog::OnShowToolTip(const QModelIndex& index)
{
const QString& fullPath = m_levels[index.row()].second;
- //TEMPORARY:Begin This can be put back once the main window is in Qt
- //QRect itemRect = ui->recentLevelList->visualRect(index);
- QToolTip::showText(QCursor::pos(), QString("Open level: %1").arg(fullPath) /*, ui->recentLevelList, itemRect*/);
- //TEMPORARY:END
+ QToolTip::showText(QCursor::pos(), QString("Open level: %1").arg(fullPath));
}
void WelcomeScreenDialog::OnShowContextMenu(const QPoint& pos)
{
- QModelIndex index = ui->recentLevelList->indexAt(pos);
+ QModelIndex index = ui->recentLevelTable->indexAt(pos);
if (index.isValid())
{
- QString level = m_pRecentListModel->data(index, 0).toString();
+ QString level = ui->recentLevelTable->itemAt(pos)->text();
- QPoint globalPos = ui->recentLevelList->viewport()->mapToGlobal(pos);
+ QPoint globalPos = ui->recentLevelTable->viewport()->mapToGlobal(pos);
QMenu contextMenu;
contextMenu.addAction(QString("Remove " + level + " from recent list"));
@@ -310,13 +293,16 @@ void WelcomeScreenDialog::OnShowContextMenu(const QPoint& pos)
}
}
-
void WelcomeScreenDialog::OnNewLevelBtnClicked([[maybe_unused]] bool checked)
{
m_levelPath = "new";
accept();
}
+void WelcomeScreenDialog::OnNewLevelLabelClicked([[maybe_unused]] const QString& path)
+{
+ OnNewLevelBtnClicked(true);
+}
void WelcomeScreenDialog::OnOpenLevelBtnClicked([[maybe_unused]] bool checked)
{
@@ -329,27 +315,7 @@ void WelcomeScreenDialog::OnOpenLevelBtnClicked([[maybe_unused]] bool checked)
}
}
-void WelcomeScreenDialog::OnNewSliceBtnClicked([[maybe_unused]] bool checked)
-{
- m_levelPath = "new slice";
- accept();
-}
-
-void WelcomeScreenDialog::OnOpenSliceBtnClicked(bool)
-{
- QString fileName = QFileDialog::getOpenFileName(MainWindow::instance(),
- tr("Open Slice"),
- Path::GetEditingGameDataFolder().c_str(),
- tr("Slice (*.slice)"));
-
- if (!fileName.isEmpty())
- {
- m_levelPath = fileName;
- accept();
- }
-}
-
-void WelcomeScreenDialog::OnRecentLevelListItemClicked(const QModelIndex& modelIndex)
+void WelcomeScreenDialog::OnRecentLevelTableItemClicked(const QModelIndex& modelIndex)
{
int index = modelIndex.row();
@@ -365,45 +331,6 @@ void WelcomeScreenDialog::OnCloseBtnClicked([[maybe_unused]] bool checked)
accept();
}
-void WelcomeScreenDialog::OnAutoLoadLevelBtnClicked(bool checked)
-{
- gSettings.bAutoloadLastLevelAtStartup = checked;
- gSettings.Save();
-}
-
-
-void WelcomeScreenDialog::OnShowOnStartupBtnClicked(bool checked)
-{
- gSettings.bShowDashboardAtStartup = !checked;
- gSettings.Save();
-
- if (gSettings.bShowDashboardAtStartup == false)
- {
- QMessageBox msgBox(AzToolsFramework::GetActiveWindow());
- msgBox.setWindowTitle(QObject::tr("Skip the Welcome dialog on startup"));
- msgBox.setText(QObject::tr("You may re-enable the Welcome dialog at any time by going to Edit > Editor Settings > Global Preferences in the menu bar."));
- msgBox.exec();
- }
-}
-
-void WelcomeScreenDialog::OnDocumentationBtnClicked([[maybe_unused]] bool checked)
-{
- QString webLink = tr("https://aws.amazon.com/lumberyard/support/");
- QDesktopServices::openUrl(QUrl(webLink));
-}
-
-void WelcomeScreenDialog::SyncFail([[maybe_unused]] News::ErrorCode error)
-{
- m_articleViewContainer->AddErrorMessage();
- m_waitingOnAsync = false;
-}
-
-void WelcomeScreenDialog::SyncSuccess()
-{
- m_articleViewContainer->PopulateArticles();
- m_waitingOnAsync = false;
-}
-
void WelcomeScreenDialog::previewAreaScrolled()
{
//this should only be reported once per session
diff --git a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.h b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.h
index 73e9d75ea3..a3460630ac 100644
--- a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.h
+++ b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.h
@@ -52,13 +52,9 @@ private:
Ui::WelcomeScreenDialog* ui;
QString m_levelPath;
- QStringListModel* m_pRecentListModel;
TNameFullPathArray m_levels;
RecentFileList* m_pRecentList;
- News::ResourceManifest* m_manifest = nullptr;
- News::ArticleViewContainer* m_articleViewContainer = nullptr;
const char* m_levelExtension = nullptr;
- bool m_waitingOnAsync = true;
bool m_messageScrollReported = false;
void RemoveLevelEntry(int index);
@@ -66,19 +62,11 @@ private:
void OnShowToolTip(const QModelIndex& index);
void OnShowContextMenu(const QPoint& point);
void OnNewLevelBtnClicked(bool checked);
+ void OnNewLevelLabelClicked(const QString& checked);
void OnOpenLevelBtnClicked(bool checked);
- void OnNewSliceBtnClicked(bool checked);
- void OnOpenSliceBtnClicked(bool checked);
- void OnRecentLevelListItemClicked(const QModelIndex& index);
- void OnGettingStartedBtnClicked(bool checked);
- void OnTutorialsBtnClicked(bool checked);
- void OnDocumentationBtnClicked(bool checked);
- void OnForumsBtnClicked(bool checked);
- void OnAutoLoadLevelBtnClicked(bool checked);
- void OnShowOnStartupBtnClicked(bool checked);
+ void OnRecentLevelTableItemClicked(const QModelIndex& index);
void OnCloseBtnClicked(bool checked);
- void SyncUpdate(const QString& /* message */, News::LogType /* logType */) {}
void SyncFail(News::ErrorCode error);
void SyncSuccess();
diff --git a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.qrc b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.qrc
index b6fa8150c5..9e8ff62f48 100644
--- a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.qrc
+++ b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.qrc
@@ -1,5 +1,5 @@
- WelcomeScreenDialogHeader.png
+ DefaultActiveProject.png
diff --git a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.ui b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.ui
index be0d175a09..680b411121 100644
--- a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.ui
+++ b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.ui
@@ -2,12 +2,15 @@
WelcomeScreenDialog
+
+ true
+
0
0
- 800
- 600
+ 945
+ 639
@@ -18,21 +21,21 @@
- 800
- 600
+ 945
+ 639
- 800
- 16777215
+ 945
+ 639
Qt::TabFocus
- Welcome to Open 3D Engine
+ Welcome to O3DE
@@ -53,100 +56,6 @@
0
-
-
-
-
-
- 0
- 36
-
-
-
-
- 16777215
- 36
-
-
-
-
- 10
-
-
- 16
-
-
- 0
-
-
- 12
-
-
- 0
-
-
-
-
-
-
- 0
- 0
-
-
-
- Current project:
-
-
-
- -
-
-
- Current Project Name
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 1
-
-
-
- color: "black"
-
-
- QFrame::Plain
-
-
- 0
-
-
- Qt::Horizontal
-
-
-
-
@@ -165,20 +74,26 @@
0
-
-
+
+
+
+ 0
+ 0
+
+
- 0
+ 183
0
- 320
+ 183
16777215
-
+
0
@@ -191,6 +106,143 @@
0
+
+ 10
+
+
-
+
+
+ 15
+
+
-
+
+
+ 10
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Active project
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 126
+ 167
+
+
+
+
+ 126
+ 167
+
+
+
+
+
+
+ :/WelcomeScreenDialog/DefaultActiveProject.png
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ MyGame
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ 15
+
+
+ 15
+
+
-
+
+
+ Switch project...
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 762
+ 0
+
+
+
+
+ 762
+ 16777215
+
+
+
+
+ 0
+
+
+ 20
+
+
+ 0
+
+
+ 20
+
0
@@ -227,7 +279,7 @@
- Open or create a level
+ Recent Files
-1
@@ -255,16 +307,6 @@
0
- -
-
-
- Qt::ScrollBarAlwaysOff
-
-
- 4
-
-
-
@@ -310,8 +352,26 @@
-
+
+
+ 0
+ 0
+
+
+
+
+ 156
+ 0
+
+
+
+
+ 156
+ 16777215
+
+
- New level...
+ Create new...
@@ -333,8 +393,67 @@
-
+
+
+ 156
+ 0
+
+
+
+
+ 156
+ 16777215
+
+
+
+ Open...
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/stylesheet/img/UI20/toolbar/Object_list.svg:/stylesheet/img/UI20/toolbar/Object_list.svg
+
+
+
+ 24
+ 24
+
+
+
+
+ -
+
- Open level...
+ ...
+
+
+
+ :/stylesheet/img/UI20/toolbar/Grid.svg:/stylesheet/img/UI20/toolbar/Grid.svg
+
+
+
+ 24
+ 24
+
@@ -358,65 +477,130 @@
-
-
-
-
- 0
- 0
-
+
+
+ 6
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- New slice...
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 24
- 0
-
-
-
-
- -
-
-
- Open slice...
-
-
-
-
-
+ -
+
+
+ Name
+
+
+
+ -
+
+
+ Last modified
+
+
+
+ -
+
+
+ Type
+
+
+
+
+ -
+
+
+ 16
+
+
+ 16
+
+
+ 16
+
+
-
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ No level file created yet for this project. <a href="#">Create one</a> now.
+
+
+ Qt::RichText
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ 3
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ 1
+
+
+ 48
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
-
@@ -439,205 +623,16 @@
- -
-
-
-
- 0
- 48
-
-
-
-
- 16777215
- 48
-
-
-
-
- 10
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 24
- 24
-
-
-
- info
-
-
-
- :/stylesheet/img/UI20/Info.svg:/stylesheet/img/UI20/Info.svg
-
-
-
- -
-
-
- Documentation and tutorials
-
-
- link
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 1
- 16777215
-
-
-
- color: "black"
-
-
- QFrame::Plain
-
-
- 0
-
-
- Qt::Vertical
-
-
-
- -
-
-
-
- 480
- 0
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
-
- 16777215
- 1
-
-
-
- color: "black"
-
-
- QFrame::Plain
-
-
- 0
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 36
-
-
-
-
- 16777215
- 36
-
-
-
-
- 30
-
-
- 16
-
-
- 0
-
-
- 16
-
-
- 0
-
-
-
-
-
-
- 0
- 0
-
-
-
- Auto-load last opened level on startup
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Skip this dialog on startup
-
-
-
-
-
-
+
diff --git a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialogHeader.png b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialogHeader.png
deleted file mode 100644
index e2656e3dfd..0000000000
--- a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialogHeader.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:53b846352880d940621b14b1ea9514e0a4c95aa6ead4d00234a98684c061c04f
-size 29505
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
index 25b58ab544..b81d013b87 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
@@ -255,7 +255,6 @@ namespace AZ
{
return AZStd::make_pair(animation, anim);
}
-
Events::ProcessingResult AssImpAnimationImporter::ImportAnimation(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Animation");
@@ -447,7 +446,22 @@ namespace AZ
return combinedAnimationResult.GetResult();
}
- decltype(boneAnimations) parentFillerAnimations;
+
+ AZStd::unordered_set boneList;
+
+ for (int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex)
+ {
+ aiMesh* mesh = scene->mMeshes[meshIndex];
+
+ for (int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
+ {
+ aiBone* bone = mesh->mBones[boneIndex];
+
+ boneList.insert(bone->mName.C_Str());
+ }
+ }
+
+ decltype(boneAnimations) fillerAnimations;
// Go through all the animations and make sure we create animations for bones who's parents don't have an animation
for (auto&& anim : boneAnimations)
@@ -459,8 +473,8 @@ namespace AZ
{
if (!IsPivotNode(parent->mName))
{
- if (boneAnimations.find(parent->mName.C_Str()) == boneAnimations.end() &&
- parentFillerAnimations.find(parent->mName.C_Str()) == parentFillerAnimations.end())
+ if (!boneAnimations.contains(parent->mName.C_Str()) &&
+ !fillerAnimations.contains(parent->mName.C_Str()))
{
// Create 1 key for each type that just copies the current transform
ConsolidatedNodeAnim emptyAnimation;
@@ -472,7 +486,7 @@ namespace AZ
globalTransform.Decompose(scale, rotation, position);
emptyAnimation.mNumRotationKeys = emptyAnimation.mNumPositionKeys = emptyAnimation.mNumScalingKeys = 1;
-
+
emptyAnimation.m_ownedPositionKeys.emplace_back(0, position);
emptyAnimation.mPositionKeys = emptyAnimation.m_ownedPositionKeys.data();
@@ -481,9 +495,9 @@ namespace AZ
emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale);
emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data();
-
- parentFillerAnimations.insert(
- AZStd::make_pair(parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation))));
+
+ fillerAnimations.insert(AZStd::make_pair(
+ parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation))));
}
}
@@ -491,7 +505,7 @@ namespace AZ
}
}
- boneAnimations.insert(AZStd::make_move_iterator(parentFillerAnimations.begin()), AZStd::make_move_iterator(parentFillerAnimations.end()));
+ boneAnimations.insert(AZStd::make_move_iterator(fillerAnimations.begin()), AZStd::make_move_iterator(fillerAnimations.end()));
auto animItr = boneAnimations.equal_range(currentNode->mName.C_Str());
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp
index 5b43941715..e726547c98 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp
@@ -98,6 +98,20 @@ namespace AZ
}
}
+ aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode)
+ {
+ aiMatrix4x4 transform = {};
+ const aiNode* iteratingNode = currentNode;
+
+ while (iteratingNode)
+ {
+ transform = iteratingNode->mTransformation * transform;
+ iteratingNode = iteratingNode->mParent;
+ }
+
+ return transform;
+ }
+
Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Bone");
@@ -111,12 +125,7 @@ namespace AZ
}
bool isBone = false;
-
- if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid()))
- {
- isBone = true;
- }
- else
+
{
AZStd::unordered_map mainBoneList;
AZStd::unordered_map boneLookup;
@@ -170,15 +179,8 @@ namespace AZ
{
createdBoneData = AZStd::make_shared();
}
-
- aiMatrix4x4 transform = currentNode->mTransformation;
- const aiNode* parent = currentNode->mParent;
- while (parent)
- {
- transform = parent->mTransformation * transform;
- parent = parent->mParent;
- }
+ aiMatrix4x4 transform = CalculateWorldTransform(currentNode);
SceneAPI::DataTypes::MatrixType globalTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform);
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h
index bc4bdd474e..86069cdd9e 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h
@@ -31,7 +31,7 @@ namespace AZ
~AssImpBoneImporter() override = default;
static void Reflect(ReflectContext* context);
-
+
Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp
index bcc007e3a7..f7a85a161b 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp
@@ -46,8 +46,9 @@ namespace AZ
serializeContext->Class()->Version(1);
}
}
-
- void GetAllBones(const aiScene* scene, AZStd::unordered_map& boneLookup)
+
+ void GetAllBones(
+ const aiScene* scene, AZStd::unordered_multimap& boneLookup)
{
for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex)
{
@@ -57,7 +58,7 @@ namespace AZ
{
const aiBone* bone = mesh->mBones[boneIndex];
- boneLookup[bone->mName.C_Str()] = bone;
+ boneLookup.emplace(bone->mName.C_Str(), bone);
}
}
}
@@ -73,41 +74,53 @@ namespace AZ
return Events::ProcessingResult::Ignored;
}
- AZStd::unordered_map boneLookup;
+ AZStd::unordered_multimap boneLookup;
GetAllBones(scene, boneLookup);
auto boneIterator = boneLookup.find(currentNode->mName.C_Str());
const bool isBone = boneIterator != boneLookup.end();
-
- aiMatrix4x4 combinedTransform;
+
+ DataTypes::MatrixType localTransform;
if (isBone)
{
- auto parentNode = currentNode->mParent;
-
- aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix;
- aiMatrix4x4 parentOffset {};
+ AZStd::vector offsets, inverseOffsets;
+ auto iteratingNode = currentNode;
- auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str());
-
- if (parentNode && parentBoneIterator != boneLookup.end())
+ while (iteratingNode && boneLookup.count(iteratingNode->mName.C_Str()))
{
- const auto& parentBone = parentBoneIterator->second;
+ AZStd::string name = iteratingNode->mName.C_Str();
- parentOffset = parentBone->mOffsetMatrix;
- }
+ auto range = boneLookup.equal_range(name);
- auto inverseOffset = offsetMatrix;
- inverseOffset.Inverse();
+ if (range.first != range.second)
+ {
+ // There can be multiple offsetMatrices for a given bone, we're only interested in grabbing the first one
+ auto boneFirstOffsetMatrix = range.first->second->mOffsetMatrix;
+ auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(boneFirstOffsetMatrix);
+ offsets.push_back(azMat);
+ inverseOffsets.push_back(azMat.GetInverseFull());
+ }
- combinedTransform = parentOffset * inverseOffset;
+ iteratingNode = iteratingNode->mParent;
+ }
+
+ localTransform =
+ offsets.at(AZ::GetMin(offsets.size()-1, static_cast(1))) // parent bone offset, or if there is no parent, then current node offset
+ * inverseOffsets.at(inverseOffsets.size() - 1) // Inverse of root bone offset
+ * offsets.at(offsets.size() - 1) // Root bone offset
+ * inverseOffsets.at(0); // Inverse of current node offset
}
else
{
- combinedTransform = GetConcatenatedLocalTransform(currentNode);
+ localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode));
}
- DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
+ // Don't bother adding a node with the identity matrix
+ if (localTransform == DataTypes::MatrixType::Identity())
+ {
+ return Events::ProcessingResult::Ignored;
+ }
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp b/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp
index a08e6f4d7f..aa668921d7 100644
--- a/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp
+++ b/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp
@@ -1765,16 +1765,8 @@ namespace LUAEditor
return false;
}
- //name has the full path in it, we need to convert it to an asset name
- AZStd::string projectRoot, databaseRoot, databasePath, databaseFile, fileExtension;
- if (!AzFramework::StringFunc::AssetDatabasePath::Split(name.toUtf8().data(), &projectRoot, &databaseRoot, &databasePath, &databaseFile, &fileExtension))
- {
- AZ_Warning("LUAEditorMainWindow", false, AZStd::string::format("Path is invalid: '%s'", name.toUtf8().data()).c_str());
- return false;
- }
-
AzFramework::StringFunc::Path::Split(name.toUtf8().data(), nullptr, &m_lastOpenFilePath);
- AzFramework::StringFunc::AssetDatabasePath::Join(databasePath.c_str(), databaseFile.c_str(), newAssetName);
+ newAssetName = name.toUtf8().data();
return true;
}
diff --git a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h
index c892f86b66..ab03223323 100644
--- a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h
+++ b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h
@@ -46,6 +46,7 @@ namespace AWSCore
void InitializeAWSDocActions();
void InitializeAWSGlobalDocsSubMenu();
void InitializeAWSFeatureGemActions();
+ void AddSpaceForIcon(QMenu* menu);
// AWSCoreEditorRequestBus interface implementation
void SetAWSClientAuthEnabled() override;
diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp
index c319788547..a592c7417a 100644
--- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp
+++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp
@@ -35,6 +35,8 @@
namespace AWSCore
{
+ static constexpr int IconSize = 16;
+
AWSCoreEditorMenu::AWSCoreEditorMenu(const QString& text)
: QMenu(text)
, m_resourceMappingToolWatcher(nullptr)
@@ -43,6 +45,7 @@ namespace AWSCore
InitializeResourceMappingToolAction();
this->addSeparator();
InitializeAWSFeatureGemActions();
+ AddSpaceForIcon(this);
AWSCoreEditorRequestBus::Handler::BusConnect();
}
@@ -136,6 +139,8 @@ namespace AWSCore
globalDocsMenu->addAction(AddExternalLinkAction(AWSAndScriptCanvasActionText, AWSAndScriptCanvasUrl, ":/Notifications/link.svg"));
globalDocsMenu->addAction(AddExternalLinkAction(AWSAndComponentsActionText, AWSAndComponentsUrl, ":/Notifications/link.svg"));
globalDocsMenu->addAction(AddExternalLinkAction(CallAWSResourcesActionText, CallAWSResourcesUrl, ":/Notifications/link.svg"));
+
+ AddSpaceForIcon(globalDocsMenu);
}
void AWSCoreEditorMenu::InitializeAWSFeatureGemActions()
@@ -170,6 +175,8 @@ namespace AWSCore
AWSClientAuthPlatformSpecificActionText, AWSClientAuthPlatformSpecificUrl, ":/Notifications/link.svg"));
subMenu->addAction(AddExternalLinkAction(
AWSClientAuthAPIReferenceActionText, AWSClientAuthAPIReferenceUrl, ":/Notifications/link.svg"));
+
+ AddSpaceForIcon(subMenu);
}
void AWSCoreEditorMenu::SetAWSMetricsEnabled()
@@ -198,6 +205,7 @@ namespace AWSCore
QDesktopServices::openUrl(QUrl::fromLocalFile(configFilePath.c_str()));
});
subMenu->addAction(settingsAction);
+ AddSpaceForIcon(subMenu);
}
QMenu* AWSCoreEditorMenu::SetAWSFeatureSubMenu(const AZStd::string& menuText)
@@ -209,6 +217,7 @@ namespace AWSCore
{
QMenu* subMenu = new QMenu(QObject::tr(menuText.c_str()));
subMenu->setIcon(QIcon(QString(":/Notifications/checkmark.svg")));
+ subMenu->setProperty("noHover", true);
this->insertMenu(*itr, subMenu);
this->removeAction(*itr);
return subMenu;
@@ -216,4 +225,11 @@ namespace AWSCore
}
return nullptr;
}
+
+ void AWSCoreEditorMenu::AddSpaceForIcon(QMenu* menu)
+ {
+ QSize size = menu->sizeHint();
+ size.setWidth(size.width() + IconSize);
+ menu->setFixedSize(size);
+ }
} // namespace AWSCore
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
index ff0c4c59da..c635f94d56 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
@@ -1015,7 +1015,7 @@
{
"id": "pdo",
"displayName": "Pixel Depth Offset",
- "description": "Whether to enable the pixel depth offset feature.",
+ "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.",
"type": "Bool",
"defaultValue": false,
"connection": {
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
index c07eac3d47..d9a21e7662 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
@@ -417,7 +417,7 @@
{
"id": "pdo",
"displayName": "Pixel Depth Offset",
- "description": "Whether to enable the pixel depth offset feature.",
+ "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.",
"type": "Bool",
"defaultValue": false,
"connection": {
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
index 2d94f66edf..fd2c74dae0 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
@@ -956,7 +956,7 @@
{
"id": "pdo",
"displayName": "Pixel Depth Offset",
- "description": "Whether to enable the pixel depth offset feature.",
+ "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.",
"type": "Bool",
"defaultValue": false,
"connection": {
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionCopyFrameBuffer.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionCopyFrameBuffer.pass
index ac7ea3754c..ee83e60621 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionCopyFrameBuffer.pass
+++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionCopyFrameBuffer.pass
@@ -21,7 +21,7 @@
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
- "LoadAction": "Load"
+ "LoadAction": "DontCare"
}
}
],
diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp
index a895c04b95..551b561200 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp
@@ -173,7 +173,7 @@ namespace AZ
{
if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type"))
{
- // Requiring explicit type info to differentiate be=tween colors versus vectors and numeric types
+ // Requiring explicit type info to differentiate between colors versus vectors and numeric types
const AZ::Uuid baseTypeId = azrtti_typeid();
AZ::Uuid typeId = AZ::Uuid::CreateNull();
result.Combine(LoadTypeId(typeId, inputPropertyValue, context, &baseTypeId));
@@ -198,7 +198,7 @@ namespace AZ
{
outputPropertyValue.SetObject();
- // Storing explicit type info to differentiate be=tween colors versus vectors and numeric types
+ // Storing explicit type info to differentiate between colors versus vectors and numeric types
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context));
outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator());
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp
index c433a6f9cf..29dc91e2fa 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp
@@ -35,7 +35,6 @@ namespace AZ
{
m_device = device;
m_srgLayout = srgLayout;
- m_srgPool = srgPool;
m_constantBufferSize = srgLayout->GetConstantDataSize();
if (m_constantBufferSize)
@@ -93,9 +92,6 @@ namespace AZ
//Attach the constant buffer
AttachConstantBuffer();
-
- m_samplerCache = [[NSCache alloc]init];
- [m_samplerCache setName:@"SamplerCache"];
}
}
}
@@ -211,8 +207,8 @@ namespace AZ
}
else
{
- RHI::Ptr nullMtlBufferMemPtr = m_device->GetNullDescriptorManager().GetNullImage(shaderInputImage.m_type).GetMemory();
- mtlTextures[imageArrayLen] = nullMtlBufferMemPtr->GetGpuAddress>();
+ RHI::Ptr nullMtlImagePtr = m_device->GetNullDescriptorManager().GetNullImage(shaderInputImage.m_type).GetMemory();
+ mtlTextures[imageArrayLen] = nullMtlImagePtr->GetGpuAddress>();
}
imageArrayLen++;
}
@@ -345,15 +341,20 @@ namespace AZ
m_device->GetArgumentBufferAllocator().DeAllocate(m_argumentBuffer);
}
#endif
- m_argumentBuffer = {};
- m_constantBuffer = {};
- [m_samplerCache removeAllObjects];
- [m_samplerCache release];
- m_samplerCache = nil;
+ if(m_argumentBuffer.IsValid())
+ {
+ m_device->QueueForRelease(m_argumentBuffer);
+ }
+ if(m_constantBuffer.IsValid())
+ {
+ m_device->QueueForRelease(m_constantBuffer);
+ }
+
[m_argumentEncoder release];
m_argumentEncoder = nil;
+
Base::Shutdown();
}
@@ -374,23 +375,22 @@ namespace AZ
id ArgumentBuffer::GetMtlSampler(MTLSamplerDescriptor* samplerDesc)
{
- id mtlSamplerState = [m_samplerCache objectForKey:samplerDesc];
+ const NSCache* samplerCache = m_device->GetSamplerCache();
+ id mtlSamplerState = [samplerCache objectForKey:samplerDesc];
if(mtlSamplerState == nil)
{
mtlSamplerState = [m_device->GetMtlDevice() newSamplerStateWithDescriptor:samplerDesc];
- [m_samplerCache setObject:mtlSamplerState forKey:samplerDesc];
+ [samplerCache setObject:mtlSamplerState forKey:samplerDesc];
}
return mtlSamplerState;
}
- void ArgumentBuffer::AddUntrackedResourcesToEncoder(id commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
+ void ArgumentBuffer::CollectUntrackedResources(id commandEncoder,
+ const ShaderResourceGroupVisibility& srgResourcesVisInfo,
+ ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute,
+ GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const
{
- //Map to cache all the resources based on the usage as we can batch all the resources for a given usage
- ComputeResourcesToMakeResidentMap resourcesToMakeResidentCompute;
- //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage
- GraphicsResourcesToMakeResidentMap resourcesToMakeResidentGraphics;
-
//Cache the constant buffer associated with a srg
if (m_constantBufferSize)
{
@@ -434,25 +434,6 @@ namespace AZ
}
}
}
-
- //Call UseResource on all resources for Compute stage
- for (const auto& key : resourcesToMakeResidentCompute)
- {
- AZStd::vector> resourcesToProcessVec(key.second.begin(), key.second.end());
- [static_cast>(commandEncoder) useResources: &resourcesToProcessVec[0]
- count: resourcesToProcessVec.size()
- usage: key.first];
- }
-
- //Call UseResource on all resources for Vertex and Fragment stages
- for (const auto& key : resourcesToMakeResidentGraphics)
- {
- AZStd::vector> resourcesToProcessVec(key.second.begin(), key.second.end());
- [static_cast>(commandEncoder) useResources: &resourcesToProcessVec[0]
- count: resourcesToProcessVec.size()
- usage: key.first.first
- stages: key.first.second];
- }
}
void ArgumentBuffer::CollectResourcesForCompute(id encoder,
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h
index 29d7d5e239..d4d9222249 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h
@@ -97,7 +97,15 @@ namespace AZ
id GetArgEncoderBuffer() const;
size_t GetOffset() const;
- void AddUntrackedResourcesToEncoder(id commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const;
+ //Map to cache all the resources based on the usage as we can batch all the resources for a given usage.
+ using ComputeResourcesToMakeResidentMap = AZStd::unordered_map>>;
+ //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage.
+ using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, AZStd::unordered_set>>;
+
+ void CollectUntrackedResources(id commandEncoder,
+ const ShaderResourceGroupVisibility& srgResourcesVisInfo,
+ ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute,
+ GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const;
void ClearResourceTracking();
@@ -120,11 +128,7 @@ namespace AZ
ResourceBindingsMap m_resourceBindings;
static const int MaxEntriesInArgTable = 31;
- //Map to cache all the resources based on the usage as we can batch all the resources for a given usage.
- using ComputeResourcesToMakeResidentMap = AZStd::unordered_map>>;
- //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage.
- using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, AZStd::unordered_set>>;
-
+
void CollectResourcesForCompute(id encoder,
const ResourceBindingsSet& resourceBindingData,
ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const;
@@ -153,9 +157,6 @@ namespace AZ
MemoryView m_argumentBuffer;
MemoryView m_constantBuffer;
#endif
-
- ShaderResourceGroupPool* m_srgPool = nullptr;
- NSCache* m_samplerCache;
};
}
}
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/BufferPoolResolver.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/BufferPoolResolver.cpp
index b986b8ea75..da6665d9c3 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/BufferPoolResolver.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/BufferPoolResolver.cpp
@@ -40,7 +40,7 @@ namespace AZ
buffer->m_pendingResolves++;
uploadRequest.m_attachmentBuffer = buffer;
- uploadRequest.m_byteOffset = buffer->GetMemoryView().GetOffset() + request.m_byteOffset;
+ uploadRequest.m_byteOffset = request.m_byteOffset;
uploadRequest.m_stagingBuffer = stagingBuffer;
return stagingBuffer->GetMemoryView().GetCpuAddress();
@@ -51,6 +51,12 @@ namespace AZ
void BufferPoolResolver::Compile()
{
+ for (BufferUploadPacket& packet : m_uploadPackets)
+ {
+ Buffer* stagingBuffer = packet.m_stagingBuffer.get();
+ //Inform the GPU that the CPU has modified the staging buffer.
+ Platform::SynchronizeBufferOnCPU(stagingBuffer->GetMemoryView().GetGpuAddress>(), stagingBuffer->GetMemoryView().GetOffset(), stagingBuffer->GetMemoryView().GetSize());
+ }
}
void BufferPoolResolver::Resolve(CommandList& commandList) const
@@ -62,15 +68,12 @@ namespace AZ
Buffer* destBuffer = packet.m_attachmentBuffer;
AZ_Assert(stagingBuffer, "Staging Buffer is null.");
AZ_Assert(destBuffer, "Attachment Buffer is null.");
-
- //Inform the GPU that the CPU has modified the staging buffer.
- Platform::SynchronizeBufferOnCPU(stagingBuffer->GetMemoryView().GetGpuAddress>(), stagingBuffer->GetMemoryView().GetOffset(), stagingBuffer->GetMemoryView().GetSize());
RHI::CopyBufferDescriptor copyDescriptor;
copyDescriptor.m_sourceBuffer = stagingBuffer;
copyDescriptor.m_sourceOffset = stagingBuffer->GetMemoryView().GetOffset();
copyDescriptor.m_destinationBuffer = destBuffer;
- copyDescriptor.m_destinationOffset = static_cast(packet.m_byteOffset);
+ copyDescriptor.m_destinationOffset = destBuffer->GetMemoryView().GetOffset() + static_cast(packet.m_byteOffset);
copyDescriptor.m_size = stagingBuffer->GetMemoryView().GetSize();
commandList.Submit(RHI::CopyItem(copyDescriptor));
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp
index 7f65c9ea47..3c554c6128 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp
@@ -85,6 +85,7 @@ namespace AZ
destinationOffset:descriptor.m_destinationOffset
size:descriptor.m_size];
+ Platform::SynchronizeBufferOnGPU(blitEncoder, destinationBuffer->GetMemoryView().GetGpuAddress>());
break;
}
case RHI::CopyItemType::Image:
@@ -114,6 +115,8 @@ namespace AZ
destinationSlice: descriptor.m_destinationSubresource.m_arraySlice
destinationLevel: descriptor.m_destinationSubresource.m_mipSlice
destinationOrigin: destinationOrigin];
+
+ Platform::SynchronizeTextureOnGPU(blitEncoder, destinationImage->GetMemoryView().GetGpuAddress>());
break;
}
case RHI::CopyItemType::BufferToImage:
@@ -266,6 +269,11 @@ namespace AZ
mtlVertexArgBufferOffsets.fill(0);
mtlFragmentOrComputeArgBufferOffsets.fill(0);
+ //Map to cache all the resources based on the usage as we can batch all the resources for a given usage
+ ArgumentBuffer::ComputeResourcesToMakeResidentMap resourcesToMakeResidentCompute;
+ //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage
+ ArgumentBuffer::GraphicsResourcesToMakeResidentMap resourcesToMakeResidentGraphics;
+
for (uint32_t slot = 0; slot < RHI::Limits::Pipeline::ShaderResourceGroupCountMax; ++slot)
{
const ShaderResourceGroup* shaderResourceGroup = bindings.m_srgsBySlot[slot];
@@ -291,7 +299,6 @@ namespace AZ
//For graphics and compute shader stages, cache all the argument buffers, offsets and track the min/max indices
if(m_commandEncoderType == CommandEncoderType::Render)
{
- id renderEncoder = GetEncoder>();
uint8_t numBitsSet = RHI::CountBitsSet(static_cast(srgVisInfo));
if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Vertex)
{
@@ -334,11 +341,11 @@ namespace AZ
//format compatible with the appropriate metal function.
if(m_commandEncoderType == CommandEncoderType::Render)
{
- shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo);
+ shaderResourceGroup->CollectUntrackedResources(m_encoder, srgResourcesVisInfo, resourcesToMakeResidentCompute, resourcesToMakeResidentGraphics);
}
else if(m_commandEncoderType == CommandEncoderType::Compute)
{
- shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo);
+ shaderResourceGroup->CollectUntrackedResources(m_encoder, srgResourcesVisInfo, resourcesToMakeResidentCompute, resourcesToMakeResidentGraphics);
}
}
}
@@ -368,6 +375,32 @@ namespace AZ
mtlFragmentOrComputeArgBufferOffsets);
}
+ id renderEncoder = GetEncoder>();
+ id computeEncoder = GetEncoder>();
+
+ //Call UseResource on all resources for Compute stage
+ for (const auto& key : resourcesToMakeResidentCompute)
+ {
+ AZStd::vector> resourcesToProcessVec(key.second.begin(), key.second.end());
+
+ [computeEncoder useResources: &resourcesToProcessVec[0]
+ count: resourcesToProcessVec.size()
+ usage: key.first];
+
+ }
+
+ //Call UseResource on all resources for Vertex and Fragment stages
+ for (const auto& key : resourcesToMakeResidentGraphics)
+ {
+
+ AZStd::vector> resourcesToProcessVec(key.second.begin(), key.second.end());
+
+ [renderEncoder useResources: &resourcesToProcessVec[0]
+ count: resourcesToProcessVec.size()
+ usage: key.first.first
+ stages: key.first.second];
+ }
+
return true;
}
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp
index c27be3344f..bdf9dcfd27 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp
@@ -83,7 +83,7 @@ namespace AZ
for (id residentHeap : *m_residentHeaps)
{
[renderEncoder useHeap : residentHeap
- stages : MTLRenderStageFragment];
+ stages : MTLRenderStageVertex | MTLRenderStageFragment];
}
break;
}
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp
index 6b40c8acd1..8eb9463afa 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp
@@ -80,6 +80,9 @@ namespace AZ
m_nullDescriptorManager.Init(*this);
+ m_samplerCache = [[NSCache alloc]init];
+ [m_samplerCache setName:@"SamplerCache"];
+
return RHI::ResultCode::Success;
}
@@ -101,6 +104,10 @@ namespace AZ
m_releaseQueue.Shutdown();
m_pipelineLayoutCache.Shutdown();
+ [m_samplerCache removeAllObjects];
+ [m_samplerCache release];
+ m_samplerCache = nil;
+
for (AZ::u32 i = 0; i < CommandEncoderTypeCount; ++i)
{
m_commandListPools[i].Shutdown();
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h
index c7df33b12f..6d108a0c3c 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h
@@ -144,6 +144,11 @@ namespace AZ
return m_asyncUploadQueue;
}
+ const NSCache* GetSamplerCache() const
+ {
+ return m_samplerCache;
+ }
+
BufferMemoryAllocator& GetArgBufferConstantBufferAllocator() { return m_argumentBufferConstantsAllocator;}
BufferMemoryAllocator& GetArgumentBufferAllocator() { return m_argumentBufferAllocator;}
@@ -194,6 +199,7 @@ namespace AZ
RHI::HeapMemoryUsage m_argumentBufferAllocatorMemoryUsage;
NullDescriptorManager m_nullDescriptorManager;
+ NSCache* m_samplerCache;
};
}
}
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp
index 68c676d3c2..f36757054e 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp
@@ -11,6 +11,7 @@
*/
#include "Atom_RHI_Metal_precompiled.h"
+#include
#include
#include
@@ -33,10 +34,12 @@ namespace AZ
return *m_compiledArgBuffers[m_compiledDataIndex];
}
- void ShaderResourceGroup::AddUntrackedResourcesToEncoder(id commandEncoder,
- const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
+ void ShaderResourceGroup::CollectUntrackedResources(id commandEncoder,
+ const ShaderResourceGroupVisibility& srgResourcesVisInfo,
+ ArgumentBuffer::ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute,
+ ArgumentBuffer::GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const
{
- GetCompiledArgumentBuffer().AddUntrackedResourcesToEncoder(commandEncoder, srgResourcesVisInfo);
+ GetCompiledArgumentBuffer().CollectUntrackedResources(commandEncoder, srgResourcesVisInfo, resourcesToMakeResidentCompute, resourcesToMakeResidentGraphics);
}
}
}
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h
index c20dc35a20..bb8f2d58d4 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h
@@ -47,7 +47,10 @@ namespace AZ
const ImageView* GetImageView(const int index) const;
void UpdateCompiledDataIndex();
const ArgumentBuffer& GetCompiledArgumentBuffer() const;
- void AddUntrackedResourcesToEncoder(id commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const;
+ void CollectUntrackedResources(id commandEncoder,
+ const ShaderResourceGroupVisibility& srgResourcesVisInfo,
+ ArgumentBuffer::ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute,
+ ArgumentBuffer::GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const;
private:
ShaderResourceGroup() = default;
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h
index eb4c4ed0aa..f22b5cf87f 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h
@@ -30,6 +30,7 @@ namespace AZ
//! It does this by recursively creating Compute Passes to write to each mip using the Compute Shader.
class DownsampleMipChainPass
: public ParentPass
+ , private ShaderReloadNotificationBus::Handler
{
AZ_RPI_PASS(DownsampleMipChainPass);
@@ -39,6 +40,7 @@ namespace AZ
//! Creates a new pass without a PassTemplate
static Ptr Create(const PassDescriptor& descriptor);
+ virtual ~DownsampleMipChainPass();
protected:
explicit DownsampleMipChainPass(const PassDescriptor& descriptor);
@@ -49,6 +51,11 @@ namespace AZ
void BuildInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
+ // ShaderReloadNotificationBus::Handler overrides...
+ void OnShaderReinitialized(const Shader& shader) override;
+ void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override;
+ void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override;
+
private:
// Gets target height, width and mip levels from the input/output image attachment
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h
index f3da349195..31aa28412f 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h
@@ -103,10 +103,14 @@ namespace AZ
AZStd::size_t CalculateTriangleCount() const;
};
- class ModelAssetHandler : public AssetHandler
+ class ModelAssetHandler
+ : public AssetHandler
{
public:
AZ_RTTI(ModelAssetHandler, "{993B8CE3-1BBF-4712-84A0-285DB9AE808F}", AssetHandler);
+
+ // AZ::AssetTypeInfoBus::Handler overrides
+ bool HasConflictingProducts(const AZStd::vector& productAssetTypes) const override;
};
} //namespace RPI
} // namespace AZ
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp
index 329247d4eb..d206a0db08 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp
@@ -54,8 +54,14 @@ namespace AZ
}
m_passData = *passData;
+ ShaderReloadNotificationBus::Handler::BusConnect(passData->m_shaderReference.m_assetId);
}
+ DownsampleMipChainPass::~DownsampleMipChainPass()
+ {
+ ShaderReloadNotificationBus::Handler::BusDisconnect();
+ }
+
void DownsampleMipChainPass::ResetInternal()
{
RemoveChildren();
@@ -206,5 +212,19 @@ namespace AZ
ParentPass::FrameBeginInternal(params);
}
+ void DownsampleMipChainPass::OnShaderReinitialized([[maybe_unused]] const Shader& shader)
+ {
+ m_needToUpdateChildren = true;
+ }
+
+ void DownsampleMipChainPass::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset)
+ {
+ m_needToUpdateChildren = true;
+ }
+
+ void DownsampleMipChainPass::OnShaderVariantReinitialized([[maybe_unused]] const ShaderVariant& shaderVariant)
+ {
+ m_needToUpdateChildren = true;
+ }
} // namespace RPI
} // namespace AZ
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp
index 52fda0f56b..9e194078c1 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp
@@ -315,5 +315,26 @@ namespace AZ
return modelTriangleCount;
}
- } //namespace RPI
+
+ bool ModelAssetHandler::HasConflictingProducts(const AZStd::vector& productAssetTypes) const
+ {
+ size_t modelAssetCount = 0;
+ size_t actorAssetCount = 0;
+ for (const AZ::Data::AssetType& assetType : productAssetTypes)
+ {
+ if (assetType == azrtti_typeid())
+ {
+ modelAssetCount++;
+ }
+ else if (assetType == AZ::Data::AssetType("{F67CC648-EA51-464C-9F5D-4A9CE41A7F86}")) // ActorAsset
+ {
+ actorAssetCount++;
+ }
+ }
+
+ // When dropping a well-defined character, consisting of a mesh and a skeleton/actor,
+ // do not create an entity with a mesh component.
+ return modelAssetCount == 1 && actorAssetCount == 1;
+ }
+ } // namespace RPI
} // namespace AZ
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp
index 420e2732d0..f2dc1fc3e4 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp
@@ -10,6 +10,9 @@
*
*/
+#include
+#include
+
#include
#include
#include
@@ -223,7 +226,12 @@ namespace MaterialEditor
}
else if (inputChannelId == InputDeviceKeyboard::Key::AlphanumericZ && (m_keys & Ctrl) == None)
{
- Reset();
+ // only reset camera if no other widget besides viewport is in focus
+ const auto focus = QApplication::focusWidget();
+ if (!focus || focus->objectName() == "Viewport")
+ {
+ Reset();
+ }
}
break;
case InputChannel::State::Updated:
diff --git a/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.cpp
index c9ab5a135e..b21c008353 100644
--- a/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.cpp
+++ b/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.cpp
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
@@ -540,11 +541,10 @@ namespace AudioControls
}
//-------------------------------------------------------------------------------------------//
- AZStd::string CAudioSystemEditor_wwise::GetDataPath() const
+ AZ::IO::FixedMaxPath CAudioSystemEditor_wwise::GetDataPath() const
{
- AZStd::string path(Path::GetEditingGameDataFolder());
- AZ::StringFunc::Path::Join(path.c_str(), "sounds/wwise_project/", path);
- return path;
+ auto projectPath = AZ::IO::FixedMaxPath{ AZ::Utils::GetProjectPath() };
+ return (projectPath / "sounds" / "wwise_project");
}
} // namespace AudioControls
diff --git a/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.h b/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.h
index ee7b54217d..e2a9fdf5d7 100644
--- a/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.h
+++ b/Gems/AudioEngineWwise/Code/Source/Editor/AudioSystemEditor_wwise.h
@@ -86,7 +86,7 @@ namespace AudioControls
const AZStd::string_view GetTypeIcon(TImplControlType type) const override;
const AZStd::string_view GetTypeIconSelected(TImplControlType type) const override;
AZStd::string GetName() const override;
- AZStd::string GetDataPath() const;
+ AZ::IO::FixedMaxPath GetDataPath() const override;
void DataSaved() override {}
void ConnectionRemoved(IAudioSystemControl* control) override;
//////////////////////////////////////////////////////////
diff --git a/Gems/AudioEngineWwise/Code/Source/Editor/AudioWwiseLoader.cpp b/Gems/AudioEngineWwise/Code/Source/Editor/AudioWwiseLoader.cpp
index 074e25d39a..3f2aac2b98 100644
--- a/Gems/AudioEngineWwise/Code/Source/Editor/AudioWwiseLoader.cpp
+++ b/Gems/AudioEngineWwise/Code/Source/Editor/AudioWwiseLoader.cpp
@@ -54,12 +54,12 @@ namespace AudioControls
void CAudioWwiseLoader::Load(CAudioSystemEditor_wwise* audioSystemImpl)
{
m_audioSystemImpl = audioSystemImpl;
- const AZStd::string wwiseProjectFullPath(m_audioSystemImpl->GetDataPath());
- LoadControlsInFolder(wwiseProjectFullPath + WwiseStrings::GameParametersFolder);
- LoadControlsInFolder(wwiseProjectFullPath + WwiseStrings::GameStatesFolder);
- LoadControlsInFolder(wwiseProjectFullPath + WwiseStrings::SwitchesFolder);
- LoadControlsInFolder(wwiseProjectFullPath + WwiseStrings::EventsFolder);
- LoadControlsInFolder(wwiseProjectFullPath + WwiseStrings::EnvironmentsFolder);
+ const AZ::IO::FixedMaxPath wwiseProjectFullPath{ m_audioSystemImpl->GetDataPath() };
+ LoadControlsInFolder(AZ::IO::FixedMaxPath{ wwiseProjectFullPath / WwiseStrings::GameParametersFolder }.Native());
+ LoadControlsInFolder(AZ::IO::FixedMaxPath{ wwiseProjectFullPath / WwiseStrings::GameStatesFolder }.Native());
+ LoadControlsInFolder(AZ::IO::FixedMaxPath{ wwiseProjectFullPath / WwiseStrings::SwitchesFolder }.Native());
+ LoadControlsInFolder(AZ::IO::FixedMaxPath{ wwiseProjectFullPath / WwiseStrings::EventsFolder }.Native());
+ LoadControlsInFolder(AZ::IO::FixedMaxPath{ wwiseProjectFullPath / WwiseStrings::EnvironmentsFolder }.Native());
LoadSoundBanks(Audio::Wwise::GetBanksRootPath(), "", false);
}
diff --git a/Gems/AudioSystem/Code/Include/Editor/IAudioSystemEditor.h b/Gems/AudioSystem/Code/Include/Editor/IAudioSystemEditor.h
index ac2bc8c0b8..0ccd1390af 100644
--- a/Gems/AudioSystem/Code/Include/Editor/IAudioSystemEditor.h
+++ b/Gems/AudioSystem/Code/Include/Editor/IAudioSystemEditor.h
@@ -14,6 +14,7 @@
#pragma once
#include
+#include
#include
#include
@@ -151,7 +152,7 @@ namespace AudioControls
//! Gets the folder where the implementation specific controls data are stored.
//! This is used by the ACE to update if controls are changed while the editor is open.
//! @return String with the path to the folder where the implementation specific controls are stored.
- virtual AZStd::string GetDataPath() const = 0;
+ virtual AZ::IO::FixedMaxPath GetDataPath() const = 0;
//! Informs the plugin that the ACE has saved the data in case it needs to do any clean up.
virtual void DataSaved() = 0;
diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorWindow.cpp b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorWindow.cpp
index 7e3528362e..68d5a30af9 100644
--- a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorWindow.cpp
+++ b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorWindow.cpp
@@ -218,7 +218,7 @@ namespace AudioControls
IAudioSystemEditor* pAudioSystemImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
if (pAudioSystemImpl)
{
- StartWatchingFolder(pAudioSystemImpl->GetDataPath());
+ StartWatchingFolder(pAudioSystemImpl->GetDataPath().LexicallyNormal().Native());
m_pMiddlewareDockWidget->setWindowTitle(QString(pAudioSystemImpl->GetName().c_str()) + " Controls");
}
}
diff --git a/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h b/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h
index d08acd0b17..1937341cd2 100644
--- a/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h
+++ b/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h
@@ -14,6 +14,7 @@
// AZ
#include
+#include
#include
// Graph Model
diff --git a/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h b/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h
index 50c1287080..f3dd85575f 100644
--- a/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h
+++ b/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h
@@ -14,10 +14,10 @@
// AZ
#include
#include
-#include
#include
// Graph Model
+#include
#include
#include
@@ -136,9 +136,9 @@ namespace GraphModel
//! Set/gets a bundle of generic metadata that is provided by the node graph UI
//! system. This may include node positions, comment blocks, node groupings, and
//! bookmarks, for example.
- void SetUiMetadata(const AZStd::any& uiMetadata);
- const AZStd::any& GetUiMetadata() const;
- AZStd::any& GetUiMetadata();
+ void SetUiMetadata(const GraphModelIntegration::GraphCanvasMetadata& uiMetadata);
+ const GraphModelIntegration::GraphCanvasMetadata& GetUiMetadata() const;
+ GraphModelIntegration::GraphCanvasMetadata& GetUiMetadata();
AZStd::shared_ptr FindSlot(const Endpoint& endpoint);
@@ -157,7 +157,7 @@ namespace GraphModel
ConnectionList m_connections;
//! Used to store and serialize metadata from the graph UI, like node positions, comments, group boxes, etc.
- AZStd::any m_uiMetadata;
+ GraphModelIntegration::GraphCanvasMetadata m_uiMetadata;
//! Used to store all of our node <-> wrapper node mappings
NodeWrappingMap m_nodeWrappings;
diff --git a/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h b/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h
index 0ce02ffa9d..0b012fd2cd 100644
--- a/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h
+++ b/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h
@@ -12,6 +12,7 @@
#pragma once
// AZ
+#include
#include
#include
#include
@@ -165,6 +166,32 @@ namespace GraphModel
ExtendableSlotConfiguration m_extendableSlotConfiguration;
};
+ //! Custom JSON serializer for Slot because we use an AZStd::any for m_value
+ class JsonSlotSerializer
+ : public AZ::BaseJsonSerializer
+ {
+ public:
+ AZ_RTTI(JsonSlotSerializer, "{8AC96D70-7BCD-4D68-8813-269938982D51}", AZ::BaseJsonSerializer);
+ AZ_CLASS_ALLOCATOR(JsonSlotSerializer, AZ::SystemAllocator, 0);
+
+ AZ::JsonSerializationResult::Result Load(
+ void* outputValue, const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+ AZ::JsonDeserializerContext& context) override;
+
+ AZ::JsonSerializationResult::Result Store(
+ rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const AZ::Uuid& valueTypeId,
+ AZ::JsonSerializerContext& context) override;
+
+ private:
+ template
+ bool LoadAny(
+ AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
+ AZ::JsonSerializationResult::ResultCode& result);
+ template
+ bool StoreAny(
+ const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
+ AZ::JsonSerializationResult::ResultCode& result);
+ };
//!!! Start in Graph.h for high level GraphModel documentation !!!
@@ -180,6 +207,7 @@ namespace GraphModel
class Slot : public GraphElement, public AZStd::enable_shared_from_this
{
friend class Graph; // So the Graph can update the Slot's cache of Connection pointers
+ friend class JsonSlotSerializer; // So we can set the m_value and m_subId directly from the serializer
public:
AZ_CLASS_ALLOCATOR(Slot, AZ::SystemAllocator, 0);
diff --git a/Gems/GraphModel/Code/Source/Integration/GraphController.cpp b/Gems/GraphModel/Code/Source/Integration/GraphController.cpp
index f6ce6282f4..bb5291637e 100644
--- a/Gems/GraphModel/Code/Source/Integration/GraphController.cpp
+++ b/Gems/GraphModel/Code/Source/Integration/GraphController.cpp
@@ -1338,11 +1338,7 @@ namespace GraphModelIntegration
GraphCanvasMetadata* GraphController::GetGraphMetadata()
{
- if (!m_graph->GetUiMetadata().is())
- {
- m_graph->SetUiMetadata(AZStd::any(GraphCanvasMetadata()));
- }
- GraphCanvasMetadata* graphCanvasMetadata = AZStd::any_cast(&m_graph->GetUiMetadata());
+ GraphCanvasMetadata* graphCanvasMetadata = &m_graph->GetUiMetadata();
AZ_Assert(graphCanvasMetadata, "GraphCanvasMetadata not initialized");
return graphCanvasMetadata;
}
diff --git a/Gems/GraphModel/Code/Source/Model/Graph.cpp b/Gems/GraphModel/Code/Source/Model/Graph.cpp
index 809679e9f6..e82b5d8e15 100644
--- a/Gems/GraphModel/Code/Source/Model/Graph.cpp
+++ b/Gems/GraphModel/Code/Source/Model/Graph.cpp
@@ -37,7 +37,7 @@ namespace GraphModel
if (serializeContext)
{
serializeContext->Class()
- ->Version(1)
+ ->Version(2)
->Field("m_nodes", &Graph::m_nodes)
->Field("m_connections", &Graph::m_connections)
->Field("m_uiMetadata", &Graph::m_uiMetadata)
@@ -312,19 +312,19 @@ namespace GraphModel
}
- void Graph::SetUiMetadata(const AZStd::any& uiMetadata)
+ void Graph::SetUiMetadata(const GraphModelIntegration::GraphCanvasMetadata& uiMetadata)
{
m_uiMetadata = uiMetadata;
}
- const AZStd::any& Graph::GetUiMetadata() const
+ const GraphModelIntegration::GraphCanvasMetadata& Graph::GetUiMetadata() const
{
return m_uiMetadata;
}
- AZStd::any& Graph::GetUiMetadata()
+ GraphModelIntegration::GraphCanvasMetadata& Graph::GetUiMetadata()
{
return m_uiMetadata;
}
diff --git a/Gems/GraphModel/Code/Source/Model/Slot.cpp b/Gems/GraphModel/Code/Source/Model/Slot.cpp
index e5fb9f8cb8..6433129af8 100644
--- a/Gems/GraphModel/Code/Source/Model/Slot.cpp
+++ b/Gems/GraphModel/Code/Source/Model/Slot.cpp
@@ -11,9 +11,14 @@
*/
// AZ
+#include
+#include
+#include
+#include
#include
#include
#include
+#include
#include
// Graph Model
@@ -294,13 +299,164 @@ namespace GraphModel
/////////////////////////////////////////////////////////
// Slot
+ AZ::JsonSerializationResult::Result JsonSlotSerializer::Load(
+ void* outputValue, const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+ AZ::JsonDeserializerContext& context)
+ {
+ namespace JSR = AZ::JsonSerializationResult;
+
+ AZ_Assert(
+ azrtti_typeid() == outputValueTypeId,
+ "Unable to deserialize Slot from json because the provided type is %s.",
+ outputValueTypeId.ToString().c_str());
+
+ Slot* slot = reinterpret_cast(outputValue);
+ AZ_Assert(slot, "Output value for JsonSlotSerializer can't be null.");
+
+ JSR::ResultCode result(JSR::Tasks::ReadField);
+
+ auto serializedSlotValue = inputValue.FindMember("m_value");
+ if (serializedSlotValue != inputValue.MemberEnd())
+ {
+ AZStd::any slotValue;
+ if (LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result) ||
+ LoadAny(slotValue, serializedSlotValue->value, context, result))
+ {
+ slot->m_value = slotValue;
+ }
+ }
+
+ // Load m_subId normally because it's just an int
+ {
+ SlotSubId slotSubId = 0;
+ result.Combine(ContinueLoadingFromJsonObjectField(
+ &slotSubId, azrtti_typeid(), inputValue,
+ "m_subId", context));
+ slot->m_subId = slotSubId;
+ }
+
+ return context.Report(
+ result,
+ result.GetProcessing() != JSR::Processing::Halted ? "Succesfully loaded Slot information."
+ : "Failed to load Slot information.");
+ }
+
+ AZ::JsonSerializationResult::Result JsonSlotSerializer::Store(
+ rapidjson::Value& outputValue, const void* inputValue, [[maybe_unused]] const void* defaultValue, const AZ::Uuid& valueTypeId,
+ AZ::JsonSerializerContext& context)
+ {
+ namespace JSR = AZ::JsonSerializationResult;
+
+ AZ_Assert(
+ azrtti_typeid() == valueTypeId,
+ "Unable to Serialize Slot because the provided type is %s.", valueTypeId.ToString().c_str());
+
+ const Slot* slot = reinterpret_cast(inputValue);
+ AZ_Assert(slot, "Input value for JsonSlotSerializer can't be null.");
+
+ outputValue.SetObject();
+
+ JSR::ResultCode result(JSR::Tasks::WriteValue);
+
+ {
+ AZ::ScopedContextPath subPathPropertyOverrides(context, "m_value");
+
+ if (!slot->m_value.empty())
+ {
+ rapidjson::Value outputPropertyValue;
+ if (StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result) ||
+ StoreAny(slot->m_value, outputPropertyValue, context, result))
+ {
+ outputValue.AddMember("m_value", outputPropertyValue, context.GetJsonAllocator());
+ }
+ }
+ }
+
+ {
+ AZ::ScopedContextPath subSlotId(context, "m_subId");
+ SlotSubId defaultSubId = 0;
+
+ result.Combine(ContinueStoringToJsonObjectField(
+ outputValue, "m_subId", &slot->m_subId, &defaultSubId,
+ azrtti_typeid(), context));
+ }
+
+ return context.Report(
+ result,
+ result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored MaterialAssignment information."
+ : "Failed to store MaterialAssignment information.");
+ }
+
+ template
+ bool JsonSlotSerializer::LoadAny(
+ AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
+ AZ::JsonSerializationResult::ResultCode& result)
+ {
+ auto valueItr = inputPropertyValue.FindMember("Value");
+ auto typeItr = inputPropertyValue.FindMember("$type");
+ if ((valueItr != inputPropertyValue.MemberEnd()) && (typeItr != inputPropertyValue.MemberEnd()))
+ {
+ // Requiring explicit type info to differentiate between colors versus vectors and numeric types
+ const AZ::Uuid baseTypeId = azrtti_typeid();
+ AZ::Uuid typeId = AZ::Uuid::CreateNull();
+ result.Combine(LoadTypeId(typeId, inputPropertyValue, context, &baseTypeId));
+
+ if (typeId == azrtti_typeid())
+ {
+ T value;
+ result.Combine(ContinueLoadingFromJsonObjectField(&value, azrtti_typeid(), inputPropertyValue, "Value", context));
+ propertyValue = value;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template
+ bool JsonSlotSerializer::StoreAny(
+ const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
+ AZ::JsonSerializationResult::ResultCode& result)
+ {
+ if (propertyValue.is())
+ {
+ outputPropertyValue.SetObject();
+
+ // Storing explicit type info to differentiate between colors versus vectors and numeric types
+ rapidjson::Value typeValue;
+ result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context));
+ outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator());
+
+ T value = AZStd::any_cast(propertyValue);
+ result.Combine(
+ ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid(), context));
+ return true;
+ }
+ return false;
+ }
+
void Slot::Reflect(AZ::ReflectContext* context)
{
- AZ::SerializeContext* serializeContext = azrtti_cast(context);
- if (serializeContext)
+ if (auto jsonContext = azrtti_cast(context))
+ {
+ jsonContext->Serializer()->HandlesType();
+ }
+
+ if (auto serializeContext = azrtti_cast(context))
{
serializeContext->Class()
- ->Version(0)
+ ->Version(1)
->Field("m_value", &Slot::m_value)
->Field("m_subId", &Slot::m_subId)
// m_slotDescription is not reflected because that data is populated procedurally by each node
diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp
index 3879cd2597..2f3a7d7ab4 100644
--- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp
+++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp
@@ -460,10 +460,10 @@ namespace LandscapeCanvasEditor
GraphCanvas::StyleManagerRequestBus::Event(editorId, &GraphCanvas::StyleManagerRequests::RegisterDataPaletteStyle, LandscapeCanvas::AreaTypeId, "VegetationAreaDataColorPalette");
LandscapeCanvas::LandscapeCanvasRequestBus::Handler::BusConnect();
- AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
AzToolsFramework::EntityCompositionNotificationBus::Handler::BusConnect();
AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect();
+ AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect();
CrySystemEventBus::Handler::BusConnect();
AZ::EntitySystemBus::Handler::BusConnect();
@@ -480,6 +480,7 @@ namespace LandscapeCanvasEditor
{
AZ::EntitySystemBus::Handler::BusDisconnect();
CrySystemEventBus::Handler::BusDisconnect();
+ AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect();
AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
@@ -883,6 +884,10 @@ namespace LandscapeCanvasEditor
if (landscapeCanvasComponent)
{
landscapeCanvasComponent->m_graph = *m_serializeContext->CloneObject(graph.get());
+
+ // Mark the Landscape Canvas entity as dirty so the changes to the graph will be picked up on the next save
+ AzToolsFramework::ScopedUndoBatch undo("Update Landscape Canvas Graph");
+ AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, rootEntityId);
}
}
}
@@ -1572,7 +1577,7 @@ namespace LandscapeCanvasEditor
void MainWindow::HandleEditorEntityCreated(const AZ::EntityId& entityId, GraphCanvas::GraphId graphId)
{
- if (m_ignoreGraphUpdates)
+ if (m_ignoreGraphUpdates || m_prefabPropagationInProgress)
{
return;
}
@@ -1622,6 +1627,11 @@ namespace LandscapeCanvasEditor
void MainWindow::OnEditorEntityDeleted(const AZ::EntityId& entityId)
{
+ if (m_prefabPropagationInProgress)
+ {
+ return;
+ }
+
m_queuedEntityDeletes.push_back(entityId);
QTimer::singleShot(0, [this, entityId]() {
@@ -2456,6 +2466,11 @@ namespace LandscapeCanvasEditor
void MainWindow::EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId)
{
+ if (m_prefabPropagationInProgress)
+ {
+ return;
+ }
+
GraphCanvas::GraphId oldGraphId = FindGraphContainingEntity(oldParentId);
GraphCanvas::GraphId newGraphId = FindGraphContainingEntity(newParentId);
@@ -2482,6 +2497,20 @@ namespace LandscapeCanvasEditor
}
}
+ void MainWindow::OnPrefabInstancePropagationBegin()
+ {
+ // Ignore graph updates during prefab propagation because the entities will be
+ // deleted and re-created, which would inadvertantly trigger our logic to close
+ // the graph when the corresponding entity is deleted.
+ m_prefabPropagationInProgress = true;
+ }
+
+ void MainWindow::OnPrefabInstancePropagationEnd()
+ {
+ // See comment above in OnPrefabInstancePropagationBegin
+ m_prefabPropagationInProgress = false;
+ }
+
void MainWindow::OnCryEditorEndCreate()
{
UpdateGraphEnabled();
@@ -2490,6 +2519,15 @@ namespace LandscapeCanvasEditor
void MainWindow::OnCryEditorEndLoad()
{
UpdateGraphEnabled();
+
+ AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
+ }
+
+ void MainWindow::OnCryEditorCloseScene()
+ {
+ UpdateGraphEnabled();
+
+ AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
}
void MainWindow::OnCryEditorSceneClosed()
diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h
index eddf998d8d..e6887eecfd 100644
--- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h
+++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -84,6 +85,7 @@ namespace LandscapeCanvasEditor
, private AzToolsFramework::EntityCompositionNotificationBus::Handler
, private AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler
, private AzToolsFramework::ToolsApplicationNotificationBus::Handler
+ , private AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler
, private CrySystemEventBus::Handler
{
Q_OBJECT
@@ -183,10 +185,15 @@ namespace LandscapeCanvasEditor
void EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId) override;
////////////////////////////////////////////////////////////////////////
+ //! PrefabPublicNotificationBus overrides
+ void OnPrefabInstancePropagationBegin() override;
+ void OnPrefabInstancePropagationEnd() override;
+
////////////////////////////////////////////////////////////////////////
// CrySystemEventBus overrides
void OnCryEditorEndCreate() override;
void OnCryEditorEndLoad() override;
+ void OnCryEditorCloseScene() override;
void OnCryEditorSceneClosed() override;
////////////////////////////////////////////////////////////////////////
@@ -246,6 +253,7 @@ namespace LandscapeCanvasEditor
AZ::SerializeContext* m_serializeContext = nullptr;
bool m_ignoreGraphUpdates = false;
+ bool m_prefabPropagationInProgress = false;
bool m_inObjectPickMode = false;
using DeletedNodePositionsMap = AZStd::unordered_map;
diff --git a/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake b/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake
index 715762b58c..4d5680a30d 100644
--- a/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake
+++ b/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake
@@ -8,12 +8,3 @@
# 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.
#
-
-add_custom_command(TARGET LmbrCentral.Editor POST_BUILD
- COMMAND "${CMAKE_COMMAND}" -P "${LY_ROOT_FOLDER}/cmake/Platform/Mac/RPathChange.cmake"
- "$/lrelease"
- @loader_path/../lib
- "${QT_PATH}/lib"
- COMMENT "Patching lrelease..."
- VERBATIM
-)
diff --git a/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake b/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake
index 73e1fb82c1..4d5680a30d 100644
--- a/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake
+++ b/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake
@@ -8,19 +8,3 @@
# 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.
#
-
-add_custom_command(TARGET LmbrCentral.Editor POST_BUILD
- COMMAND "${CMAKE_COMMAND}"
- -DLY_TIMESTAMP_REFERENCE=$/lrelease.exe
- -DLY_LOCK_FILE=$/qtdeploy.lock
- -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
- EXEC_COMMAND "${CMAKE_COMMAND}" -E
- env PATH="${QT_PATH}/bin"
- ${WINDEPLOYQT_EXECUTABLE}
- $<$:--pdb>
- --verbose 0
- --no-compiler-runtime
- $/lrelease.exe
- COMMENT "Patching lrelease..."
- VERBATIM
-)
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h
index 19689171c5..9f2f9f4804 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h
@@ -63,10 +63,10 @@ namespace Multiplayer
//! @}
NetEntityId GetNetEntityId() const;
- bool IsAuthority() const;
- bool IsAutonomous() const;
- bool IsServer() const;
- bool IsClient() const;
+ bool IsNetEntityRoleAuthority() const;
+ bool IsNetEntityRoleAutonomous() const;
+ bool IsNetEntityRoleServer() const;
+ bool IsNetEntityRoleClient() const;
ConstNetworkEntityHandle GetEntityHandle() const;
NetworkEntityHandle GetEntityHandle();
void MarkDirty();
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h
index 7d9b7d4086..dd4b9588e4 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h
@@ -64,10 +64,23 @@ namespace Multiplayer
//! @}
NetEntityRole GetNetEntityRole() const;
- bool IsAuthority() const;
- bool IsAutonomous() const;
- bool IsServer() const;
- bool IsClient() const;
+
+ //! IsNetEntityRoleAuthority
+ //! @return true if this network entity is an authoritative proxy on a server (full authority); otherwise false.
+ bool IsNetEntityRoleAuthority() const;
+
+ //! IsNetEntityRoleAutonomous
+ //! @return true if this network entity is an autonomous proxy on a client (can execute local prediction) or if this network entity is an authoritative proxy on a server but has autonomous privileges (ie: a host who is also a player); otherwise false.
+ bool IsNetEntityRoleAutonomous() const;
+
+ //! IsNetEntityRoleServer
+ //! @return true if this network entity is a simulated proxy on a server (ie: a different server may have authority for this entity, but the entity has been replicated on this server; otherwise false.
+ bool IsNetEntityRoleServer() const;
+
+ //! IsNetEntityRoleClient
+ //! @return true if this network entity is a simulated proxy on a client; otherwise false.
+ bool IsNetEntityRoleClient() const;
+
bool HasController() const;
NetEntityId GetNetEntityId() const;
const PrefabEntityId& GetPrefabEntityId() const;
diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp
index 8542288b23..2ad883c7e7 100644
--- a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp
+++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp
@@ -46,24 +46,24 @@ namespace Multiplayer
return m_netBindComponent ? m_netBindComponent->GetNetEntityId() : InvalidNetEntityId;
}
- bool MultiplayerComponent::IsAuthority() const
+ bool MultiplayerComponent::IsNetEntityRoleAuthority() const
{
- return m_netBindComponent ? m_netBindComponent->IsAuthority() : false;
+ return m_netBindComponent ? m_netBindComponent->IsNetEntityRoleAuthority() : false;
}
- bool MultiplayerComponent::IsAutonomous() const
+ bool MultiplayerComponent::IsNetEntityRoleAutonomous() const
{
- return m_netBindComponent ? m_netBindComponent->IsAutonomous() : false;
+ return m_netBindComponent ? m_netBindComponent->IsNetEntityRoleAutonomous() : false;
}
- bool MultiplayerComponent::IsServer() const
+ bool MultiplayerComponent::IsNetEntityRoleServer() const
{
- return m_netBindComponent ? m_netBindComponent->IsServer() : false;
+ return m_netBindComponent ? m_netBindComponent->IsNetEntityRoleServer() : false;
}
- bool MultiplayerComponent::IsClient() const
+ bool MultiplayerComponent::IsNetEntityRoleClient() const
{
- return m_netBindComponent ? m_netBindComponent->IsClient() : false;
+ return m_netBindComponent ? m_netBindComponent->IsNetEntityRoleClient() : false;
}
ConstNetworkEntityHandle MultiplayerComponent::GetEntityHandle() const
diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp
index b0bafccf79..071dfd4ee2 100644
--- a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp
+++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp
@@ -29,12 +29,12 @@ namespace Multiplayer
bool MultiplayerController::IsAuthority() const
{
- return GetNetBindComponent() ? GetNetBindComponent()->IsAuthority() : false;
+ return GetNetBindComponent() ? GetNetBindComponent()->IsNetEntityRoleAuthority() : false;
}
bool MultiplayerController::IsAutonomous() const
{
- return GetNetBindComponent() ? GetNetBindComponent()->IsAutonomous() : false;
+ return GetNetBindComponent() ? GetNetBindComponent()->IsNetEntityRoleAutonomous() : false;
}
AZ::Entity* MultiplayerController::GetEntity() const
diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp
index 0847d42dd6..352bc92d1c 100644
--- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp
+++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp
@@ -54,69 +54,72 @@ namespace Multiplayer
->Attribute(AZ::Script::Attributes::Module, "multiplayer")
->Attribute(AZ::Script::Attributes::Category, "Multiplayer")
- ->Method("IsAuthority", [](AZ::EntityId id) -> bool {
+ ->Method("IsNetEntityRoleAuthority", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id);
if (!entity)
{
- AZ_Warning( "NetBindComponent", false, "NetBindComponent IsAuthority failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
+ AZ_Warning( "NetBindComponent", false, "NetBindComponent IsNetEntityRoleAuthority failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
NetBindComponent* netBindComponent = entity-> FindComponent();
if (!netBindComponent)
{
- AZ_Warning( "NetBindComponent", false, "NetBindComponent IsAuthority failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
+ AZ_Warning( "NetBindComponent", false, "NetBindComponent IsNetEntityRoleAuthority failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
- return netBindComponent->IsAuthority();
+ return netBindComponent->IsNetEntityRoleAuthority();
})
- ->Method("IsAutonomous", [](AZ::EntityId id) -> bool {
+
+ ->Method("IsNetEntityRoleAutonomous", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id);
if (!entity)
{
- AZ_Warning( "NetBindComponent", false, "NetBindComponent IsAutonomous failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
+ AZ_Warning( "NetBindComponent", false, "NetBindComponent IsNetEntityRoleAutonomous failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
NetBindComponent* netBindComponent = entity->FindComponent();
if (!netBindComponent)
{
- AZ_Warning("NetBindComponent", false, "NetBindComponent IsAutonomous failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
+ AZ_Warning("NetBindComponent", false, "NetBindComponent IsNetEntityRoleAutonomous failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
- return netBindComponent->IsAutonomous();
+ return netBindComponent->IsNetEntityRoleAutonomous();
})
- ->Method("IsClient", [](AZ::EntityId id) -> bool {
+
+ ->Method("IsNetEntityRoleClient", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id);
if (!entity)
{
- AZ_Warning( "NetBindComponent", false, "NetBindComponent IsClient failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
+ AZ_Warning( "NetBindComponent", false, "NetBindComponent IsNetEntityRoleClient failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
NetBindComponent* netBindComponent = entity->FindComponent();
if (!netBindComponent)
{
- AZ_Warning("NetBindComponent", false, "NetBindComponent IsClient failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
+ AZ_Warning("NetBindComponent", false, "NetBindComponent IsNetEntityRoleClient failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
- return netBindComponent->IsClient();
+ return netBindComponent->IsNetEntityRoleClient();
})
- ->Method("IsServer", [](AZ::EntityId id) -> bool {
+
+ ->Method("IsNetEntityRoleServer", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id);
if (!entity)
{
- AZ_Warning( "NetBindComponent", false, "NetBindComponent IsServer failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
+ AZ_Warning( "NetBindComponent", false, "NetBindComponent IsNetEntityRoleServer failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
NetBindComponent* netBindComponent = entity->FindComponent();
if (!netBindComponent)
{
- AZ_Warning("NetBindComponent", false, "NetBindComponent IsServer failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
+ AZ_Warning("NetBindComponent", false, "NetBindComponent IsNetEntityRoleServer failed. Entity '%s' (id: %s) is missing a NetBindComponent, make sure this entity contains a component which derives from NetBindComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
- return netBindComponent->IsServer();
+ return netBindComponent->IsNetEntityRoleServer();
})
;
}
@@ -179,23 +182,23 @@ namespace Multiplayer
return m_netEntityRole;
}
- bool NetBindComponent::IsAuthority() const
+ bool NetBindComponent::IsNetEntityRoleAuthority() const
{
return (m_netEntityRole == NetEntityRole::Authority);
}
- bool NetBindComponent::IsAutonomous() const
+ bool NetBindComponent::IsNetEntityRoleAutonomous() const
{
return (m_netEntityRole == NetEntityRole::Autonomous)
|| (m_netEntityRole == NetEntityRole::Authority) && m_allowAutonomy;
}
- bool NetBindComponent::IsServer() const
+ bool NetBindComponent::IsNetEntityRoleServer() const
{
return (m_netEntityRole == NetEntityRole::Server);
}
- bool NetBindComponent::IsClient() const
+ bool NetBindComponent::IsNetEntityRoleClient() const
{
return (m_netEntityRole == NetEntityRole::Client);
}
diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp
index b0f1b221e8..3405abdc57 100644
--- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp
+++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp
@@ -96,7 +96,7 @@ namespace Multiplayer
{
AZ_Assert(entityHandle.GetNetBindComponent(), "No NetBindComponent found on networked entity");
[[maybe_unused]] const bool isClientOnlyEntity = false;// (ServerIdFromEntityId(it->first) == InvalidHostId);
- AZ_Assert(entityHandle.GetNetBindComponent()->IsAuthority() || isClientOnlyEntity, "Trying to delete a proxy entity, this will lead to issues deserializing entity updates");
+ AZ_Assert(entityHandle.GetNetBindComponent()->IsNetEntityRoleAuthority() || isClientOnlyEntity, "Trying to delete a proxy entity, this will lead to issues deserializing entity updates");
}
m_removeList.push_back(entityHandle.GetNetEntityId());
m_removeEntitiesEvent.Enqueue(AZ::TimeMs{ 0 });
diff --git a/Gems/PhysX/Code/Editor/DebugDraw.cpp b/Gems/PhysX/Code/Editor/DebugDraw.cpp
index 829b776e28..1f1c24b9ad 100644
--- a/Gems/PhysX/Code/Editor/DebugDraw.cpp
+++ b/Gems/PhysX/Code/Editor/DebugDraw.cpp
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -56,6 +57,15 @@ namespace PhysX
return false;
}
+ bool IsDrawColliderReadOnly()
+ {
+ bool helpersVisible = false;
+ AzToolsFramework::EditorRequestBus::BroadcastResult(helpersVisible,
+ &AzToolsFramework::EditorRequests::DisplayHelpersVisible);
+ // if helpers are visible, draw colliders is NOT read only and can be changed.
+ return !helpersVisible;
+ }
+
static void BuildAABBVerts(const AZ::Aabb& aabb,
AZStd::vector& verts,
AZStd::vector& points,
@@ -145,28 +155,42 @@ namespace PhysX
"PhysX Collider Debug Draw", "Manages global and per-collider debug draw settings and logic")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Collider::m_locallyEnabled, "Draw collider",
"Shows the geometry for the collider in the viewport")
- ->Attribute(AZ::Edit::Attributes::CheckboxTooltip,
- "If set, the geometry of this collider is visible in the viewport")
- ->Attribute(AZ::Edit::Attributes::Visibility,
- VisibilityFunc{ []() { return IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } })
+ ->Attribute(AZ::Edit::Attributes::CheckboxTooltip,
+ "If set, the geometry of this collider is visible in the viewport. 'Draw Helpers' needs to be enabled to use.")
+ ->Attribute(AZ::Edit::Attributes::Visibility,
+ VisibilityFunc{ []() { return IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } })
+ ->Attribute(AZ::Edit::Attributes::ReadOnly, &IsDrawColliderReadOnly)
->DataElement(AZ::Edit::UIHandlers::Button, &Collider::m_globalButtonState, "Draw collider",
"Shows the geometry for the collider in the viewport")
- ->Attribute(AZ::Edit::Attributes::ButtonText, "Global override")
- ->Attribute(AZ::Edit::Attributes::ButtonTooltip,
- "A global setting is overriding this property (to disable the override, "
- "set the Global Collision Debug setting to \"Set manually\" in the PhysX Configuration)")
- ->Attribute(AZ::Edit::Attributes::Visibility,
- VisibilityFunc{ []() { return !IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } })
- ->Attribute(AZ::Edit::Attributes::ChangeNotify, &OpenPhysXSettingsWindow)
+ ->Attribute(AZ::Edit::Attributes::ButtonText, "Global override")
+ ->Attribute(AZ::Edit::Attributes::ButtonTooltip,
+ "A global setting is overriding this property (to disable the override, "
+ "set the Global Collision Debug setting to \"Set manually\" in the PhysX Configuration)."
+ "'Draw Helpers' needs to be enabled to use.")
+ ->Attribute(AZ::Edit::Attributes::Visibility,
+ VisibilityFunc{ []() { return !IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } })
+ ->Attribute(AZ::Edit::Attributes::ChangeNotify, &OpenPhysXSettingsWindow)
+ ->Attribute(AZ::Edit::Attributes::ReadOnly, &IsDrawColliderReadOnly)
;
}
}
}
+ Collider::Collider()
+ : m_debugDisplayDataChangedEvent(
+ [this]([[maybe_unused]] const PhysX::Debug::DebugDisplayData& data)
+ {
+ this->RefreshTreeHelper();
+ })
+ {
+
+ }
+
void Collider::Connect(AZ::EntityId entityId)
{
m_entityId = entityId;
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityId);
+ AzToolsFramework::EntitySelectionEvents::Bus::Handler::BusConnect(m_entityId);
}
void Collider::SetDisplayCallback(const DisplayCallback* callback)
@@ -176,6 +200,11 @@ namespace PhysX
void Collider::Disconnect()
{
+ if (AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusIsConnected())
+ {
+ AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusDisconnect();
+ }
+ AzToolsFramework::EntitySelectionEvents::Bus::Handler::BusDisconnect();
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
m_displayCallback = nullptr;
m_entityId = AZ::EntityId();
@@ -731,6 +760,33 @@ namespace PhysX
}
}
+ void Collider::OnDrawHelpersChanged([[maybe_unused]] bool enabled)
+ {
+ RefreshTreeHelper();
+ }
+
+ void Collider::OnSelected()
+ {
+ AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusConnect(
+ AzFramework::g_defaultSceneEntityDebugDisplayId);
+ if (auto* physXDebug = AZ::Interface::Get())
+ {
+ physXDebug->RegisterDebugDisplayDataChangedEvent(m_debugDisplayDataChangedEvent);
+ }
+ }
+
+ void Collider::OnDeselected()
+ {
+ AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusDisconnect();
+ m_debugDisplayDataChangedEvent.Disconnect();
+ }
+
+ void Collider::RefreshTreeHelper()
+ {
+ AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
+ &AzToolsFramework::ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
+ }
+
AZStd::string Collider::GetEntityName() const
{
AZStd::string entityName;
diff --git a/Gems/PhysX/Code/Editor/DebugDraw.h b/Gems/PhysX/Code/Editor/DebugDraw.h
index c43634717a..34b3b57667 100644
--- a/Gems/PhysX/Code/Editor/DebugDraw.h
+++ b/Gems/PhysX/Code/Editor/DebugDraw.h
@@ -15,8 +15,11 @@
#include
#include
#include
+#include
+#include
#include
#include
+#include
namespace PhysX
{
@@ -40,13 +43,15 @@ namespace PhysX
class Collider
: protected AzFramework::EntityDebugDisplayEventBus::Handler
+ , protected AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Handler
+ , protected AzToolsFramework::EntitySelectionEvents::Bus::Handler
{
public:
AZ_CLASS_ALLOCATOR(Collider, AZ::SystemAllocator, 0);
AZ_RTTI(Collider, "{7DE9CA01-DF1E-4D72-BBF4-76C9136BE6A2}");
static void Reflect(AZ::ReflectContext* context);
- Collider() = default;
+ Collider();
void Connect(AZ::EntityId entityId);
void SetDisplayCallback(const DisplayCallback* callback);
@@ -109,11 +114,20 @@ namespace PhysX
const AZStd::vector& GetIndices(AZ::u32 geomIndex) const;
protected:
- // AzFramework::EntityDebugDisplayEventBus
+ // AzFramework::EntityDebugDisplayEventBus overrides ...
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
+ // AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Handler overrides ...
+ void OnDrawHelpersChanged(bool enabled) override;
+
+ // AzToolsFramework::EntitySelectionEvents::Bus::Handler overrides ...
+ void OnSelected() override;
+ void OnDeselected() override;
+
+ void RefreshTreeHelper();
+
// Internal mesh drawing subroutines
void DrawTriangleMesh(
AzFramework::DebugDisplayRequests& debugDisplay, const Physics::ColliderConfiguration& colliderConfig, AZ::u32 geomIndex,
@@ -143,6 +157,8 @@ namespace PhysX
};
mutable AZStd::vector m_geometry;
+
+ PhysX::Debug::DebugDisplayDataChangedEvent::Handler m_debugDisplayDataChangedEvent;
};
} // namespace DebugDraw
} // namespace PhysX
diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake
index a0b2185190..a48714849b 100644
--- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake
+++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake
@@ -23,7 +23,7 @@ ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux
# platform-specific:
ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-android TARGETS freetype PACKAGE_HASH 74dd75382688323c3a2a5090f473840b5d7e9d2aed1a4fcdff05ed2a09a664f2)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.14-android TARGETS tiff PACKAGE_HASH a9b30a1980946390c2fad0ed94562476a1d7ba8c1f36934ae140a89c54a8efd0)
-ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev3-android TARGETS AWSNativeSDK PACKAGE_HASH e2192157534cc8c4e22769545d88dff03ec6c1031599716ef63de3ebbb8c9a44)
+ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-android TARGETS AWSNativeSDK PACKAGE_HASH 9d163696591a836881fc22dac3c94e57b0278771b6c6cec807ff6a5e96f2669d)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-android TARGETS Lua PACKAGE_HASH 1f638e94a17a87fe9e588ea456d5893876094b4db191234380e4c4eb9e06c300)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS PhysX PACKAGE_HASH b8cb6aa46b2a21671f6cb1f6a78713a3ba88824d0447560ff5ce6c01014b9f43)
ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705)
diff --git a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
index 6ad428c08d..25418bf6cf 100644
--- a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
+++ b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
@@ -105,12 +105,10 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS")
endif()
endif()
if(anything_new)
+ unset(fixup_bundle_ignore)
# LYN-4505: Patch dxc, is configured in the wrong folder in 3p
if(EXISTS ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7)
- # we copy to not invalidate the copy check from above
- file(COPY ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/lib/libdxcompiler.3.7.dylib
- DESTINATION ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin
- )
+ list(APPEND fixup_bundle_ignore dxc-3.7)
endif()
# Python.framework being copied by fixup_bundle
#if(EXISTS ${bundle_path}/Contents/Frameworks/Python.framework)
@@ -139,8 +137,17 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS")
#endif()
list(REMOVE_DUPLICATES plugin_libs)
list(REMOVE_DUPLICATES plugin_dirs)
- fixup_bundle("${bundle_path}" "${plugin_libs}" "${plugin_dirs}")
+ fixup_bundle("${bundle_path}" "${plugin_libs}" "${plugin_dirs}" IGNORE_ITEM ${fixup_bundle_ignore})
file(TOUCH "${bundle_path}")
file(TOUCH "${fixup_timestamp_file}")
+
+ # fixup bundle ends up removing the rpath of dxc (despite we exclude it)
+ if(EXISTS ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7)
+ find_program(LY_INSTALL_NAME_TOOL install_name_tool)
+ if (NOT LY_INSTALL_NAME_TOOL)
+ message(FATAL_ERROR "Unable to locate 'install_name_tool'")
+ endif()
+ execute_process(COMMAND ${LY_INSTALL_NAME_TOOL} -add_rpath @executable_path/../lib ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7)
+ endif()
endif()
endif()
diff --git a/scripts/migration/non_uniform_scale.py b/scripts/migration/non_uniform_scale.py
new file mode 100644
index 0000000000..038cb1144b
--- /dev/null
+++ b/scripts/migration/non_uniform_scale.py
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+
+import sys
+import azlmbr
+from pathlib import Path
+
+def fixup_current_level(threshold):
+ nonUniformScaleComponentId = azlmbr.editor.EditorNonUniformScaleComponentTypeId
+
+ # iterate over all entities in the level
+ entityIdList = azlmbr.entity.SearchBus(azlmbr.bus.Broadcast, 'SearchEntities', azlmbr.entity.SearchFilter())
+ for entityId in entityIdList:
+ name = azlmbr.editor.EditorEntityInfoRequestBus(azlmbr.bus.Event, 'GetName', entityId)
+ local = azlmbr.components.TransformBus(azlmbr.bus.Event, 'GetLocalScale', entityId)
+
+ # only process entities where the non-uniformity is greater than the threshold
+ local_max = max(local.x, local.y, local.z)
+ local_min = min(local.x, local.y, local.z)
+ if local_max / local_min > 1 + threshold:
+
+ # check if there is already a Non-uniform Scale component
+ getComponentOutcome = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'GetComponentOfType', entityId, nonUniformScaleComponentId)
+ if getComponentOutcome.IsSuccess():
+ print(f"skipping {name} as it already has a Non-uniform Scale component")
+
+ else:
+ # add Non-uniform Scale component and set it to the non-uniform part of the local scale
+ azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast,'AddComponentsOfType', entityId, [nonUniformScaleComponentId])
+ vec = azlmbr.math.Vector3(local.x / local_max, local.y / local_max, local.z / local_max)
+ azlmbr.entity.NonUniformScaleRequestBus(azlmbr.bus.Event, 'SetScale', entityId, vec)
+ print(f"added non-uniform scale component for {name}: {local.x}, {local.y}, {local.z}")
+
+if __name__ == '__main__':
+ # handle the arguments manually since argparse causes problems when run through EditorPythonBindings
+ process_all_levels = "--all" in sys.argv
+
+ # ignore entities where the relative difference between the min and max scale values is less than this threshold
+ threshold = 0.001
+ for i in range(len(sys.argv) - 1):
+ if sys.argv[i] == "--threshold":
+ try:
+ threshold = float(sys.argv[i + 1])
+ except ValueError:
+ print(f"invalid threshold value {sys.argv[i + 1]}, using default value {threshold}")
+ pass
+
+ if process_all_levels:
+ game_folder = Path(azlmbr.legacy.general.get_game_folder())
+ level_folder = game_folder / 'Levels'
+ levels = [str(level) for level in level_folder.rglob('*.ly')] + [str(level) for level in level_folder.rglob('*.cry')]
+ for level in levels:
+ if "_savebackup" not in level:
+ print(f'loading level {level}')
+ azlmbr.legacy.general.open_level_no_prompt(level)
+ azlmbr.legacy.general.idle_wait(2.0)
+ fixup_current_level(threshold)
+ azlmbr.legacy.general.save_level()
+ else:
+ fixup_current_level(threshold)