diff --git a/.clang-format b/.clang-format
index 04e0284f97..ef3ce64192 100644
--- a/.clang-format
+++ b/.clang-format
@@ -13,6 +13,7 @@ AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: None
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: true
+BinPackParameters: false
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
index 3507f532b5..91ac495e0e 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
@@ -2471,7 +2471,17 @@ namespace AzToolsFramework
break;
}
});
-
+
+ AddAction(
+ m_actions, { QKeySequence(Qt::Key_U) },
+ /*ID_VIEWPORTUI_VISIBLE=*/50040, "Toggle ViewportUI", "Hide/Unhide Viewport UI",
+ [this]()
+ {
+ SetViewportUiClusterVisible(m_transformModeClusterId, !m_viewportUiVisible);
+ SetViewportUiClusterVisible(m_spaceCluster.m_spaceClusterId, !m_viewportUiVisible);
+ m_viewportUiVisible = !m_viewportUiVisible;
+ });
+
EditorMenuRequestBus::Broadcast(&EditorMenuRequests::RestoreEditMenuToDefault);
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h
index 2bc4d7cbf6..2ec7fa2489 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h
@@ -306,6 +306,7 @@ namespace AzToolsFramework
AzFramework::ClickDetector m_clickDetector; //!< Detect different types of mouse click.
AzFramework::CursorState m_cursorState; //!< Track the mouse position and delta movement each frame.
SpaceCluster m_spaceCluster; //!< Related viewport ui state for controlling the current reference space.
+ bool m_viewportUiVisible = true; //!< Used to hide/show the viewport ui elements.
};
//! The ETCS (EntityTransformComponentSelection) namespace contains functions and data used exclusively by
diff --git a/Code/Sandbox/Editor/AboutDialog.ui b/Code/Sandbox/Editor/AboutDialog.ui
index 67767c0de1..0b86f15542 100644
--- a/Code/Sandbox/Editor/AboutDialog.ui
+++ b/Code/Sandbox/Editor/AboutDialog.ui
@@ -75,14 +75,14 @@
- 161
- 49
+ 175
+ 66
- 161
- 49
+ 175
+ 66
diff --git a/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt
index 7be9947e99..01b58e3f77 100644
--- a/Code/Sandbox/Editor/CMakeLists.txt
+++ b/Code/Sandbox/Editor/CMakeLists.txt
@@ -177,6 +177,11 @@ ly_add_target(
Legacy::EditorLib
ProjectManager
)
+set_property(SOURCE
+ CryEdit.cpp
+ APPEND PROPERTY
+ COMPILE_DEFINITIONS LY_CMAKE_TARGET="Editor"
+)
ly_add_translations(
TARGETS Editor
PREFIX Translations
@@ -186,15 +191,8 @@ ly_add_translations(
)
ly_add_dependencies(Editor AssetProcessor)
-if(TARGET Editor)
- set_property(SOURCE
- CryEdit.cpp
- APPEND PROPERTY
- COMPILE_DEFINITIONS LY_CMAKE_TARGET="Editor"
- )
-else()
- message(FATAL_ERROR "Cannot set LY_CMAKE_TARGET define to Editor as the target doesn't exist anymore."
- " Perhaps it has been renamed")
+if(LY_FIRST_PROJECT_PATH)
+ set_property(TARGET Editor APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_FIRST_PROJECT_PATH}\"")
endif()
################################################################################
diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp
index c60f32560b..c723e6049a 100644
--- a/Code/Sandbox/Editor/CryEdit.cpp
+++ b/Code/Sandbox/Editor/CryEdit.cpp
@@ -281,6 +281,8 @@ BOOL CCryDocManager::DoPromptFileName(QString& fileName, [[maybe_unused]] UINT n
[[maybe_unused]] DWORD lFlags, BOOL bOpenFileDialog, [[maybe_unused]] CDocTemplate* pTemplate)
{
CLevelFileDialog levelFileDialog(bOpenFileDialog);
+ levelFileDialog.show();
+ levelFileDialog.adjustSize();
if (levelFileDialog.exec() == QDialog::Accepted)
{
@@ -2079,6 +2081,8 @@ void CCryEditApp::OnDocumentationAWSSupport()
void CCryEditApp::OnDocumentationFeedback()
{
FeedbackDialog dialog;
+ dialog.show();
+ dialog.adjustSize();
dialog.exec();
}
@@ -3347,6 +3351,8 @@ void CCryEditApp::OnCreateSlice()
void CCryEditApp::OnOpenLevel()
{
CLevelFileDialog levelFileDialog(true);
+ levelFileDialog.show();
+ levelFileDialog.adjustSize();
if (levelFileDialog.exec() == QDialog::Accepted)
{
diff --git a/Code/Sandbox/Editor/Resource.h b/Code/Sandbox/Editor/Resource.h
index 9c50045367..98a6e56d14 100644
--- a/Code/Sandbox/Editor/Resource.h
+++ b/Code/Sandbox/Editor/Resource.h
@@ -369,3 +369,4 @@
#define ID_TOOLBAR_WIDGET_SPACER_RIGHT 50013
#define ID_TOOLBAR_WIDGET_PLAYCONSOLE_LABEL 50014
#define ID_TOOLBAR_WIDGET_LAST 50020
+#define ID_VIEWPORTUI_VISIBLE 50040
diff --git a/Code/Sandbox/Editor/StartupLogoDialog.ui b/Code/Sandbox/Editor/StartupLogoDialog.ui
index 6e01808a84..0815fa8b18 100644
--- a/Code/Sandbox/Editor/StartupLogoDialog.ui
+++ b/Code/Sandbox/Editor/StartupLogoDialog.ui
@@ -42,14 +42,14 @@
- 161
- 49
+ 175
+ 66
- 161
- 50
+ 175
+ 66
diff --git a/Code/Sandbox/Editor/o3de_logo.svg b/Code/Sandbox/Editor/o3de_logo.svg
index ba44566ce8..35a880c5c8 100644
--- a/Code/Sandbox/Editor/o3de_logo.svg
+++ b/Code/Sandbox/Editor/o3de_logo.svg
@@ -1,22 +1,35 @@
-
\ No newline at end of file
diff --git a/Code/Tools/AssetProcessor/CMakeLists.txt b/Code/Tools/AssetProcessor/CMakeLists.txt
index 5d4980eed4..6c12ab6024 100644
--- a/Code/Tools/AssetProcessor/CMakeLists.txt
+++ b/Code/Tools/AssetProcessor/CMakeLists.txt
@@ -125,6 +125,10 @@ ly_add_target(
AZ::AssetProcessorBatch.Static
)
+if(LY_FIRST_PROJECT_PATH)
+ set_property(TARGET AssetProcessor AssetProcessorBatch APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_FIRST_PROJECT_PATH}\"")
+endif()
+
# Adds the AssetProcessorBatch target as a C preprocessor define so that it can be used as a Settings Registry
# specialization in order to look up the generated .setreg which contains the dependencies
# specified for the target.
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
index 57200e3b36..0fc0d89fcb 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
@@ -131,6 +131,22 @@ namespace O3DE::ProjectManager
return false;
}
+ if (event->type() == QEvent::MouseButtonPress)
+ {
+ QMouseEvent* mouseEvent = static_cast(event);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(option, fullRect, itemRect, contentRect);
+ const QRect buttonRect = CalcButtonRect(contentRect);
+
+ if (buttonRect.contains(mouseEvent->pos()))
+ {
+ const bool isAdded = GemModel::IsAdded(modelIndex);
+ GemModel::SetIsAdded(*model, modelIndex, !isAdded);
+ return true;
+ }
+ }
+
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
}
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
index df11c4c7a6..6c09c95572 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
@@ -38,6 +38,7 @@ namespace O3DE::ProjectManager
item->setData(aznumeric_cast(gemInfo.m_platforms), RolePlatforms);
item->setData(aznumeric_cast(gemInfo.m_types), RoleTypes);
item->setData(gemInfo.m_summary, RoleSummary);
+ item->setData(false, RoleWasPreviouslyAdded);
item->setData(gemInfo.m_isAdded, RoleIsAdded);
item->setData(gemInfo.m_directoryLink, RoleDirectoryLink);
item->setData(gemInfo.m_documentationLink, RoleDocLink);
@@ -47,6 +48,7 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated);
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
item->setData(gemInfo.m_features, RoleFeatures);
+ item->setData(gemInfo.m_path, RolePath);
appendRow(item);
@@ -89,11 +91,6 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleSummary).toString();
}
- bool GemModel::IsAdded(const QModelIndex& modelIndex)
- {
- return modelIndex.data(RoleIsAdded).toBool();
- }
-
QString GemModel::GetDirectoryLink(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleDirectoryLink).toString();
@@ -180,4 +177,62 @@ namespace O3DE::ProjectManager
{
return modelIndex.data(RoleFeatures).toStringList();
}
+
+ QString GemModel::GetPath(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RolePath).toString();
+ }
+
+ bool GemModel::IsAdded(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleIsAdded).toBool();
+ }
+
+ void GemModel::SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded)
+ {
+ model.setData(modelIndex, isAdded, RoleIsAdded);
+ }
+
+ void GemModel::SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded)
+ {
+ model.setData(modelIndex, wasAdded, RoleWasPreviouslyAdded);
+ }
+
+ bool GemModel::NeedsToBeAdded(const QModelIndex& modelIndex)
+ {
+ return (!modelIndex.data(RoleWasPreviouslyAdded).toBool() && modelIndex.data(RoleIsAdded).toBool());
+ }
+
+ bool GemModel::NeedsToBeRemoved(const QModelIndex& modelIndex)
+ {
+ return (modelIndex.data(RoleWasPreviouslyAdded).toBool() && !modelIndex.data(RoleIsAdded).toBool());
+ }
+
+ QVector GemModel::GatherGemsToBeAdded() const
+ {
+ QVector result;
+ for (int row = 0; row < rowCount(); ++row)
+ {
+ const QModelIndex modelIndex = index(row, 0);
+ if (NeedsToBeAdded(modelIndex))
+ {
+ result.push_back(modelIndex);
+ }
+ }
+ return result;
+ }
+
+ QVector GemModel::GatherGemsToBeRemoved() const
+ {
+ QVector result;
+ for (int row = 0; row < rowCount(); ++row)
+ {
+ const QModelIndex modelIndex = index(row, 0);
+ if (NeedsToBeRemoved(modelIndex))
+ {
+ result.push_back(modelIndex);
+ }
+ }
+ return result;
+ }
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
index 0caa399b58..77f973a91c 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
@@ -46,13 +46,22 @@ namespace O3DE::ProjectManager
static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex);
static GemInfo::Types GetTypes(const QModelIndex& modelIndex);
static QString GetSummary(const QModelIndex& modelIndex);
- static bool IsAdded(const QModelIndex& modelIndex);
static QString GetDirectoryLink(const QModelIndex& modelIndex);
static QString GetDocLink(const QModelIndex& modelIndex);
static QString GetVersion(const QModelIndex& modelIndex);
static QString GetLastUpdated(const QModelIndex& modelIndex);
static int GetBinarySizeInKB(const QModelIndex& modelIndex);
static QStringList GetFeatures(const QModelIndex& modelIndex);
+ static QString GetPath(const QModelIndex& modelIndex);
+
+ static bool IsAdded(const QModelIndex& modelIndex);
+ static void SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded);
+ static void SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded);
+ static bool NeedsToBeAdded(const QModelIndex& modelIndex);
+ static bool NeedsToBeRemoved(const QModelIndex& modelIndex);
+
+ QVector GatherGemsToBeAdded() const;
+ QVector GatherGemsToBeRemoved() const;
private:
enum UserRole
@@ -62,6 +71,7 @@ namespace O3DE::ProjectManager
RoleGemOrigin,
RolePlatforms,
RoleSummary,
+ RoleWasPreviouslyAdded,
RoleIsAdded,
RoleDirectoryLink,
RoleDocLink,
@@ -71,7 +81,8 @@ namespace O3DE::ProjectManager
RoleLastUpdated,
RoleBinarySize,
RoleFeatures,
- RoleTypes
+ RoleTypes,
+ RolePath
};
QHash m_nameToIndexMap;
diff --git a/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/license.txt b/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/license.txt
new file mode 100644
index 0000000000..158138973a
--- /dev/null
+++ b/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/license.txt
@@ -0,0 +1,209 @@
+vulkan.h was generated using a code generator from https://github.com/Dav1dde/glad
+
+/*
+** Copyright (c) 2014-2020 The Khronos Group Inc.
+**
+** SPDX-License-Identifier: Apache-2.0
+*/
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelKdTree.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelKdTree.h
index 9cd33eda6c..832681d7f1 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelKdTree.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelKdTree.h
@@ -35,7 +35,15 @@ namespace AZ
ModelKdTree() = default;
bool Build(const ModelAsset* model);
- bool RayIntersection(const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distance, AZ::Vector3& normal) const;
+ //! Return if a ray intersected the model.
+ //! @param raySrc The starting point of the ray.
+ //! @param rayDir The direction and length of the ray (magnitude is encoded in the direction).
+ //! @param[out] The normalized distance of the intersection (in the range 0.0-1.0) - to calculate the actual
+ //! distance, multiply distanceNormalized by the magnitude of rayDir.
+ //! @param[out] The surface normal of the intersection with the model.
+ //! @return Return true if there was an intersection with the model, false otherwise.
+ bool RayIntersection(
+ const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const;
void GetPenetratedBoxes(const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, AZStd::vector& outBoxes);
enum ESplitAxis
@@ -53,8 +61,14 @@ namespace AZ
private:
void BuildRecursively(ModelKdTreeNode* pNode, const AZ::Aabb& boundbox, AZStd::vector& indices);
- bool RayIntersectionRecursively(ModelKdTreeNode* pNode, const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distance, AZ::Vector3& normal) const;
- void GetPenetratedBoxesRecursively(ModelKdTreeNode* pNode, const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, AZStd::vector& outBoxes);
+ bool RayIntersectionRecursively(
+ ModelKdTreeNode* pNode,
+ const AZ::Vector3& raySrc,
+ const AZ::Vector3& rayDir,
+ float& distanceNormalized,
+ AZ::Vector3& normal) const;
+ void GetPenetratedBoxesRecursively(
+ ModelKdTreeNode* pNode, const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, AZStd::vector& outBoxes);
void ConstructMeshList(const ModelAsset* model, const AZ::Transform& matParent);
static const int s_MinimumVertexSizeInLeafNode = 3 * 10;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp
index 15c8aaf528..86477bf785 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp
@@ -140,8 +140,9 @@ namespace AZ
bool Model::LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
- float firstHit;
- const int result = Intersect::IntersectRayAABB2(rayStart, dir.GetReciprocal(), m_aabb, firstHit, distance);
+ float start;
+ float end;
+ const int result = Intersect::IntersectRayAABB2(rayStart, dir.GetReciprocal(), m_aabb, start, end);
if (Intersect::ISECT_RAY_AABB_NONE != result)
{
if (ModelAsset* modelAssetPtr = m_modelAsset.Get())
@@ -164,7 +165,9 @@ namespace AZ
return false;
}
- bool Model::RayIntersection(const AZ::Transform& modelTransform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const
+ bool Model::RayIntersection(
+ const AZ::Transform& modelTransform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayStart, const AZ::Vector3& dir,
+ float& distanceFactor, AZ::Vector3& normal) const
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
const AZ::Vector3 clampedScale = nonUniformScale.GetMax(AZ::Vector3(AZ::MinTransformScale));
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelKdTree.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelKdTree.cpp
index 6a1897815f..bee489c2fd 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelKdTree.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelKdTree.cpp
@@ -11,6 +11,7 @@
*/
#include
+#include
#include
#include
@@ -191,10 +192,10 @@ namespace AZ
if (ModelLodAsset* lodAssetPtr = model->GetLodAssets()[0].Get())
{
- AZ_Warning("ModelKdTree", lodAssetPtr->GetMeshes().size() <= std::numeric_limits::max() + 1,
+ AZ_Warning("ModelKdTree", lodAssetPtr->GetMeshes().size() <= AZStd::numeric_limits::max() + 1,
"KdTree generation doesn't support models with greater than 256 meshes. RayIntersection results will be incorrect "
"unless the meshes are merged or broken up into multiple models");
- const size_t size = AZStd::min(lodAssetPtr->GetMeshes().size(), std::numeric_limits::max() + 1);
+ const size_t size = AZStd::min(lodAssetPtr->GetMeshes().size(), AZStd::numeric_limits::max() + 1);
m_meshes.reserve(size);
AZStd::transform(
lodAssetPtr->GetMeshes().begin(), AZStd::next(lodAssetPtr->GetMeshes().begin(), size),
@@ -204,20 +205,42 @@ namespace AZ
}
}
- bool ModelKdTree::RayIntersection(const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distance, AZ::Vector3& normal) const
+ bool ModelKdTree::RayIntersection(
+ const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
{
- return RayIntersectionRecursively(m_pRootNode.get(), raySrc, rayDir, distance, normal);
+ float closestDistanceNormalized = AZStd::numeric_limits::max();
+ if (RayIntersectionRecursively(m_pRootNode.get(), raySrc, rayDir, closestDistanceNormalized, normal))
+ {
+ distanceNormalized = closestDistanceNormalized;
+ return true;
+ }
+
+ return false;
}
- bool ModelKdTree::RayIntersectionRecursively(ModelKdTreeNode* pNode, const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distance, AZ::Vector3& normal) const
+ bool ModelKdTree::RayIntersectionRecursively(
+ ModelKdTreeNode* pNode,
+ const AZ::Vector3& raySrc,
+ const AZ::Vector3& rayDir,
+ float& distanceNormalized,
+ AZ::Vector3& normal) const
{
+ using Intersect::IntersectRayAABB2;
+ using Intersect::IntersectSegmentTriangleCCW;
+ using Intersect::ISECT_RAY_AABB_NONE;
+
if (!pNode)
{
return false;
}
float start, end;
- if (AZ::Intersect::IntersectRayAABB2(raySrc, rayDir.GetReciprocal(), pNode->GetBoundBox(), start, end) == Intersect::ISECT_RAY_AABB_NONE)
+ if (IntersectRayAABB2(raySrc, rayDir.GetReciprocal(), pNode->GetBoundBox(), start, end) == ISECT_RAY_AABB_NONE)
+ {
+ return false;
+ }
+
+ if (start > distanceNormalized)
{
return false;
}
@@ -235,17 +258,13 @@ namespace AZ
return false;
}
- AZ::Vector3 intersectionNormal;
- float hitDistanceNormalized;
- const float maxDist(FLT_MAX);
- float nearestDist = maxDist;
-
+ float nearestDistanceNormalized = distanceNormalized;
for (AZ::u32 i = 0; i < nVBuffSize; ++i)
{
const auto& [first, second, third] = pNode->GetVertexIndex(i);
const AZ::u32 nObjIndex = pNode->GetObjIndex(i);
- AZStd::array_view positionBuffer = m_meshes[nObjIndex].m_vertexData;
+ const AZStd::array_view positionBuffer = m_meshes[nObjIndex].m_vertexData;
if (positionBuffer.empty())
{
@@ -258,25 +277,23 @@ namespace AZ
AZ::Vector3{positionBuffer[third * 3 + 0], positionBuffer[third * 3 + 1], positionBuffer[third * 3 + 2]},
};
- const AZ::Vector3 rayEnd = raySrc + rayDir * distance;
-
- if (AZ::Intersect::IntersectSegmentTriangleCCW(raySrc, rayEnd, trianglePoints[0], trianglePoints[1], trianglePoints[2],
- intersectionNormal, hitDistanceNormalized) != Intersect::ISECT_RAY_AABB_NONE)
+ float hitDistanceNormalized;
+ AZ::Vector3 intersectionNormal;
+ const AZ::Vector3 rayEnd = raySrc + rayDir;
+ if (IntersectSegmentTriangleCCW(raySrc, rayEnd, trianglePoints[0], trianglePoints[1], trianglePoints[2],
+ intersectionNormal, hitDistanceNormalized) != ISECT_RAY_AABB_NONE)
{
- float hitDistance = hitDistanceNormalized * distance;
-
- if (nearestDist > hitDistance)
+ if (nearestDistanceNormalized > hitDistanceNormalized)
{
normal = intersectionNormal;
+ nearestDistanceNormalized = hitDistanceNormalized;
}
-
- nearestDist = AZStd::GetMin(nearestDist, hitDistance);
}
}
- if (nearestDist < maxDist)
+ if (nearestDistanceNormalized < distanceNormalized)
{
- distance = AZStd::GetMin(distance, nearestDist);
+ distanceNormalized = nearestDistanceNormalized;
return true;
}
@@ -284,8 +301,8 @@ namespace AZ
}
// running both sides to find the closest intersection
- const bool bFoundChild0 = RayIntersectionRecursively(pNode->GetChild(0), raySrc, rayDir, distance, normal);
- const bool bFoundChild1 = RayIntersectionRecursively(pNode->GetChild(1), raySrc, rayDir, distance, normal);
+ const bool bFoundChild0 = RayIntersectionRecursively(pNode->GetChild(0), raySrc, rayDir, distanceNormalized, normal);
+ const bool bFoundChild1 = RayIntersectionRecursively(pNode->GetChild(1), raySrc, rayDir, distanceNormalized, normal);
return bFoundChild0 || bFoundChild1;
}
@@ -311,5 +328,5 @@ namespace AZ
GetPenetratedBoxesRecursively(pNode->GetChild(0), raySrc, rayDir, outBoxes);
GetPenetratedBoxesRecursively(pNode->GetChild(1), raySrc, rayDir, outBoxes);
}
- }
-}
+ } // namespace RPI
+} // namespace AZ
diff --git a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp
index 1ec14c6169..3ce17bee8b 100644
--- a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp
+++ b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp
@@ -1074,13 +1074,13 @@ namespace UnitTest
}
};
- class KdTreeIntersectsFixture
+ class KdTreeIntersectsParameterizedFixture
: public ModelTests
, public ::testing::WithParamInterface
{
};
- TEST_P(KdTreeIntersectsFixture, KdTreeIntersects)
+ TEST_P(KdTreeIntersectsParameterizedFixture, KdTreeIntersects)
{
TwoSeparatedPlanesMesh mesh;
@@ -1090,7 +1090,10 @@ namespace UnitTest
float distance = AZStd::numeric_limits::max();
AZ::Vector3 normal;
- EXPECT_THAT(kdTree.RayIntersection(AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos), AZ::Vector3::CreateAxisZ(-1.0f), distance, normal), testing::Eq(GetParam().expectedShouldIntersect));
+ EXPECT_THAT(
+ kdTree.RayIntersection(
+ AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos), AZ::Vector3::CreateAxisZ(-1.0f), distance, normal),
+ testing::Eq(GetParam().expectedShouldIntersect));
EXPECT_THAT(distance, testing::FloatEq(GetParam().expectedDistance));
}
@@ -1119,5 +1122,63 @@ namespace UnitTest
KdTreeIntersectParams{0.778f, 0.111f, 1.0f, 0.5f, true},
KdTreeIntersectParams{0.778f, 0.778f, 1.0f, 0.5f, true},
};
- INSTANTIATE_TEST_CASE_P(KdTreeIntersectsPlane, KdTreeIntersectsFixture, ::testing::ValuesIn(intersectTestData));
+
+ INSTANTIATE_TEST_CASE_P(KdTreeIntersectsPlane, KdTreeIntersectsParameterizedFixture, ::testing::ValuesIn(intersectTestData));
+
+ class KdTreeIntersectsFixture
+ : public ModelTests
+ {
+ public:
+ void SetUp() override
+ {
+ ModelTests::SetUp();
+
+ m_mesh = AZStd::make_unique();
+ m_kdTree = AZStd::make_unique();
+ ASSERT_TRUE(m_kdTree->Build(m_mesh->GetModel().Get()));
+ }
+
+ void TearDown() override
+ {
+ m_kdTree.reset();
+ m_mesh.reset();
+
+ ModelTests::TearDown();
+ }
+
+ AZStd::unique_ptr m_mesh;
+ AZStd::unique_ptr m_kdTree;
+ };
+
+ TEST_F(KdTreeIntersectsFixture, KdTreeIntersectionReturnsNormalizedDistance)
+ {
+ float t = AZStd::numeric_limits::max();
+ AZ::Vector3 normal;
+
+ constexpr float rayLength = 100.0f;
+ EXPECT_THAT(
+ m_kdTree->RayIntersection(
+ AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::Eq(true));
+ EXPECT_THAT(t, testing::FloatEq(0.005f));
+ }
+
+ TEST_F(KdTreeIntersectsFixture, KdTreeIntersectionHandlesInvalidStartingNormalizedDistance)
+ {
+ float t = -0.5f; // invalid starting distance
+ AZ::Vector3 normal;
+
+ constexpr float rayLength = 10.0f;
+ EXPECT_THAT(
+ m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(0.75f), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::Eq(true));
+ EXPECT_THAT(t, testing::FloatEq(0.025f));
+ }
+
+ TEST_F(KdTreeIntersectsFixture, KdTreeIntersectionDoesNotScaleRayByStartingDistance)
+ {
+ float t = 10.0f; // starting distance (used to check it is not read from initially by RayIntersection)
+ AZ::Vector3 normal;
+
+ EXPECT_THAT(
+ m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(), t, normal), testing::Eq(false));
+ }
} // namespace UnitTest
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp
index f2ad9a13e6..e1c9026c74 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp
@@ -140,9 +140,16 @@ namespace AZ
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
+ float t;
AZ::Vector3 ignoreNormal;
+ constexpr float rayLength = 1000.0f;
+ if (m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir * rayLength, t, ignoreNormal))
+ {
+ distance = rayLength * t;
+ return true;
+ }
- return m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir, distance, ignoreNormal);
+ return false;
}
bool EditorMeshComponent::SupportsEditorRayIntersect()
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp
index c089dd01f9..e7eecd3c7f 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp
@@ -485,16 +485,12 @@ namespace AZ
m_transformInterface->GetWorldTM(), m_cachedNonUniformScale, ray.m_startWorldPosition,
ray.m_endWorldPosition - ray.m_startWorldPosition, t, normal))
{
- // note: this is a temporary workaround to handle cases where model->RayIntersection
- // returns negative distances, follow-up ATOM-15673
- const auto absT = AZStd::abs(t);
-
// fill in ray result structure after successful intersection
const auto intersectionLine = (ray.m_endWorldPosition - ray.m_startWorldPosition);
result.m_uv = AZ::Vector2::CreateZero();
- result.m_worldPosition = ray.m_startWorldPosition + intersectionLine * absT;
+ result.m_worldPosition = ray.m_startWorldPosition + intersectionLine * t;
result.m_worldNormal = normal;
- result.m_distance = intersectionLine.GetLength() * absT;
+ result.m_distance = intersectionLine.GetLength() * t;
result.m_entityAndComponent = m_entityComponentIdPair;
}
}
diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp
index 294f4c7c99..46760af8f0 100644
--- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp
+++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp
@@ -218,6 +218,10 @@ namespace EMStudio
}
const bool saveResult = manifest.SaveToFile(manifestFilename.c_str());
+ if (saveResult)
+ {
+ actor->SetDirtyFlag(false);
+ }
// Source Control: Add file in case it did not exist before (when saving it the first time).
if (saveResult && !fileExisted)
diff --git a/cmake/3rdParty/FindClang.cmake b/cmake/3rdParty/FindClang.cmake
deleted file mode 100644
index 8062e6ebb2..0000000000
--- a/cmake/3rdParty/FindClang.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-# its licensors.
-#
-# For complete copyright and license terms please see the LICENSE at the root of this
-# distribution (the "License"). All use of this software is governed by the License,
-# or, if provided, by the license below or the license accompanying this file. Do not
-# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#
-
-ly_add_external_target(
- NAME Clang
- VERSION 6.0.1-az
-)
diff --git a/cmake/3rdParty/cmake_files.cmake b/cmake/3rdParty/cmake_files.cmake
index ebbad6e156..f7a315686f 100644
--- a/cmake/3rdParty/cmake_files.cmake
+++ b/cmake/3rdParty/cmake_files.cmake
@@ -11,7 +11,6 @@
set(FILES
BuiltInPackages.cmake
- FindClang.cmake
FindOpenGLInterface.cmake
FindRadTelemetry.cmake
FindVkValidation.cmake
diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake
index 297dad4ddf..adaf7ee15f 100644
--- a/cmake/Projects.cmake
+++ b/cmake/Projects.cmake
@@ -167,6 +167,9 @@ endfunction()
# Add the projects here so the above function is found
foreach(project ${LY_PROJECTS})
file(REAL_PATH ${project} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR})
+ if(NOT LY_FIRST_PROJECT)
+ ly_set(LY_FIRST_PROJECT_PATH ${full_directory_path})
+ endif()
string(SHA256 full_directory_hash ${full_directory_path})
# Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit
diff --git a/scripts/build/Platform/Mac/pipeline.json b/scripts/build/Platform/Mac/pipeline.json
index 58f62b421d..81c57002b6 100644
--- a/scripts/build/Platform/Mac/pipeline.json
+++ b/scripts/build/Platform/Mac/pipeline.json
@@ -1,6 +1,6 @@
{
"ENV": {
- "NODE_LABEL": "mac",
+ "NODE_LABEL": "mac-catalina-7ad2e45b",
"LY_3RDPARTY_PATH": "/Users/lybuilder/3rdParty",
"TIMEOUT": 30,
"WORKSPACE": "/Users/lybuilder/workspace",
diff --git a/scripts/build/Platform/iOS/pipeline.json b/scripts/build/Platform/iOS/pipeline.json
index 58f62b421d..81c57002b6 100644
--- a/scripts/build/Platform/iOS/pipeline.json
+++ b/scripts/build/Platform/iOS/pipeline.json
@@ -1,6 +1,6 @@
{
"ENV": {
- "NODE_LABEL": "mac",
+ "NODE_LABEL": "mac-catalina-7ad2e45b",
"LY_3RDPARTY_PATH": "/Users/lybuilder/3rdParty",
"TIMEOUT": 30,
"WORKSPACE": "/Users/lybuilder/workspace",