From d841f0c0db73e4c2449360824425f55f1e3a43aa Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 4 Jun 2021 16:18:53 -0500 Subject: [PATCH 01/35] Got transform result close for 3 bone chain, longer chains are still not correct (cherry picked from commit 5ac65de6148dcc03b9f2953e97dd943493f23ed9) # Conflicts: # Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp --- .../Importers/AssImpTransformImporter.cpp | 64 +++++++++++++++++-- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index bcc007e3a7..153dfce69d 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -61,7 +61,7 @@ namespace AZ } } } - +#pragma optimize("", off) Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context) { AZ_TraceContext("Importer", "transform"); @@ -79,6 +79,11 @@ namespace AZ auto boneIterator = boneLookup.find(currentNode->mName.C_Str()); const bool isBone = boneIterator != boneLookup.end(); + if (currentNode->mName.C_Str() == AZStd::string("FrontCloth_02")) + { + __debugbreak(); + } + aiMatrix4x4 combinedTransform; if (isBone) @@ -87,20 +92,67 @@ namespace AZ aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix; aiMatrix4x4 parentOffset {}; + aiMatrix4x4 parentTransform{}; - auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); + if (parentNode) + { + parentTransform = parentNode->mTransformation; + } + + auto azOffset = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(offsetMatrix); + decltype(azOffset) azParentOffset{}; + AZStd::vector transforms, offsets, inverseTransforms, inverseOffsets; + + auto addTransform = [&](AZStd::string, aiMatrix4x4 mat) + { + auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); + transforms.push_back(azMat); + inverseTransforms.push_back(azMat.GetInverseFull()); + }; + auto addOffset = [&]([[maybe_unused]] auto name, aiMatrix4x4 mat) + { + auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); + offsets.push_back(azMat); + inverseOffsets.push_back(azMat.GetInverseFull()); + }; - if (parentNode && parentBoneIterator != boneLookup.end()) + auto curNode = currentNode; + + while (curNode && boneLookup.count(curNode->mName.C_Str())) { - const auto& parentBone = parentBoneIterator->second; + AZStd::string name = curNode->mName.C_Str(); + addOffset(name, boneLookup.at(name)->mOffsetMatrix); + addTransform(name, curNode->mTransformation); + + curNode = curNode->mParent; + } - parentOffset = parentBone->mOffsetMatrix; + // Go up the tree to find the root bone. It's parent will be the scene mRootNode + while (parentNode && parentNode->mParent && parentNode->mParent != scene->mRootNode) + { + parentNode = parentNode->mParent; + } + + auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); + aiMatrix4x4 rootOffsetMatrix{}; + + if (parentBoneIterator != boneLookup.end()) + { + rootOffsetMatrix = parentBoneIterator->second->mOffsetMatrix; } auto inverseOffset = offsetMatrix; inverseOffset.Inverse(); - combinedTransform = parentOffset * inverseOffset; + auto parentTransformInverse = parentTransform; + parentTransformInverse.Inverse(); + + //auto azInverse = azOffset.GetInverseFull(); + //auto azCombined = azParentOffset * azInverse; + //combinedTransform = parentOffset * inverseOffset; + + //parentTransform ^-1 * parentParent * azOffsetInverse + combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; } else { From 66a030b800c0def8a0b15847b3661b990f925837 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 9 Jun 2021 22:35:03 -0500 Subject: [PATCH 02/35] Fix transform data Use first offsetMatrix for a bone (there may be multiple) and calculate using offsetOfParent * inverseRootOffset * rootOffset * inverseOffset (cherry picked from commit a8eae976dda39ad28f9aa235e1e6ba34715ac48a) # Conflicts: # Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp --- .../Importers/AssImpTransformImporter.cpp | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index 153dfce69d..dc59f59147 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,18 +74,19 @@ 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(); - if (currentNode->mName.C_Str() == AZStd::string("FrontCloth_02")) + if (currentNode->mName.C_Str() == AZStd::string("spine_C0_0_jnt")) { - __debugbreak(); + //__debugbreak(); } aiMatrix4x4 combinedTransform; + DataTypes::MatrixType finalMat; if (isBone) { @@ -121,7 +123,16 @@ namespace AZ while (curNode && boneLookup.count(curNode->mName.C_Str())) { AZStd::string name = curNode->mName.C_Str(); - addOffset(name, boneLookup.at(name)->mOffsetMatrix); + + auto range = boneLookup.equal_range(name); + + for (auto it = range.first; it != range.second; ++it) + { + addOffset(name, it->second->mOffsetMatrix); + break; + } + + //addOffset(name, boneLookup.at(name)->mOffsetMatrix); addTransform(name, curNode->mTransformation); curNode = curNode->mParent; @@ -152,14 +163,24 @@ namespace AZ //combinedTransform = parentOffset * inverseOffset; //parentTransform ^-1 * parentParent * azOffsetInverse - combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; + //combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; + + //azNodeLocal = offsets[1] * inverseOffsets[3] * (offsets[3] * inverseOffsets[0]) + finalMat = + offsets.at(AZ::GetMin(offsets.size()-1, (decltype(offsets.size()))1)) * inverseOffsets.at(inverseOffsets.size() - 1) * offsets.at(offsets.size() - 1) * inverseOffsets.at(0); } else { combinedTransform = GetConcatenatedLocalTransform(currentNode); } - DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); + //DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); + DataTypes::MatrixType localTransform = finalMat; + + if (localTransform == DataTypes::MatrixType::Identity()) + { + return Events::ProcessingResult::Ignored; + } context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform); context.m_sourceSceneSystem.ConvertUnit(localTransform); From 10999b699979aed380138557457440f55e3f0938 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Sat, 12 Jun 2021 13:26:25 -0500 Subject: [PATCH 03/35] All bones have animations (cherry picked from commit d17a8070010cdc5bc4e08d17b1549736d031414a) --- .../Importers/AssImpAnimationImporter.cpp | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index d72cdde8e7..f066540c50 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,24 +446,41 @@ namespace AZ return combinedAnimationResult.GetResult(); } + + AZStd::unordered_set boneList; + + for (int i = 0; i < scene->mNumMeshes; ++i) + { + auto mesh = scene->mMeshes[i]; + + for (auto boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + { + auto bone = mesh->mBones[boneIndex]; + + boneList.insert(bone->mName.C_Str()); + } + } + decltype(boneAnimations) parentFillerAnimations; // 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) { - const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); - const aiNode* parent = node->mParent; + //const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); + //const aiNode* parent = node->mParent; - while (parent && parent != scene->mRootNode) + //while (parent && parent != scene->mRootNode) + for (auto boneName : boneList) { - if (!IsPivotNode(parent->mName)) + if (!IsPivotNode(aiString(boneName.c_str()))) { - if (boneAnimations.find(parent->mName.C_Str()) == boneAnimations.end() && - parentFillerAnimations.find(parent->mName.C_Str()) == parentFillerAnimations.end()) + if (boneAnimations.find(boneName) == boneAnimations.end() && + parentFillerAnimations.find(boneName) == parentFillerAnimations.end()) { // Create 1 key for each type that just copies the current transform ConsolidatedNodeAnim emptyAnimation; - aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(parent); + auto node = scene->mRootNode->FindNode(boneName.c_str()); + aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(node); aiVector3D position, scale; aiQuaternion rotation; @@ -483,11 +499,11 @@ namespace AZ emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); parentFillerAnimations.insert( - AZStd::make_pair(parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); + AZStd::make_pair(boneName, AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } - parent = parent->mParent; + //parent = parent->mParent; } } From 9b039c1f9da20e7c8b881bdf81d6df88af0342d4 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Sat, 12 Jun 2021 13:27:32 -0500 Subject: [PATCH 04/35] Fix creating bone data for non-bones (cherry picked from commit 8d1bdd1456e70e4efc47aa36dce660bc91e7dfcf) --- .../Importers/AssImpBoneImporter.cpp | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 5b43941715..694e3566f6 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -97,7 +97,7 @@ namespace AZ EnumChildren(scene, child, mainBoneList, boneLookup); } } - +#pragma optimize("", off) Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context) { AZ_TraceContext("Importer", "Bone"); @@ -112,11 +112,11 @@ namespace AZ bool isBone = false; - if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid())) - { - isBone = true; - } - else + //if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid())) + //{ + // isBone = true; + //} + //else { AZStd::unordered_map mainBoneList; AZStd::unordered_map boneLookup; @@ -171,11 +171,22 @@ namespace AZ createdBoneData = AZStd::make_shared(); } + // L_Lower_Eyelid_Jnt_01 + if (context.m_sourceNode.GetName() == AZStd::string("L_Lower_Eyelid_Jnt_01")) + { + //__debugbreak(); + } + + AZStd::vector transforms; aiMatrix4x4 transform = currentNode->mTransformation; const aiNode* parent = currentNode->mParent; - + + auto addTrans = [&](auto mat) { transforms.push_back(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat)); }; + addTrans(transform); + while (parent) { + addTrans(parent->mTransformation); transform = parent->mTransformation * transform; parent = parent->mParent; } From 7dc4d8438b008ce914734638eb2bd46621107b9d Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Sat, 12 Jun 2021 20:33:50 -0500 Subject: [PATCH 05/35] Fix non-bone transforms setting the wrong matrix variable (cherry picked from commit 838a8b47da73e50fca4ea9ee5abc7c33250bf25d) --- .../FbxSceneBuilder/Importers/AssImpTransformImporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index dc59f59147..3e22bfc671 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -85,7 +85,7 @@ namespace AZ //__debugbreak(); } - aiMatrix4x4 combinedTransform; + //aiMatrix4x4 combinedTransform; DataTypes::MatrixType finalMat; if (isBone) @@ -171,7 +171,7 @@ namespace AZ } else { - combinedTransform = GetConcatenatedLocalTransform(currentNode); + finalMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); } //DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); From 57b19feca5d113ba6fc727cbc8e92e15bff5a9a9 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 16 Jun 2021 12:03:47 -0500 Subject: [PATCH 06/35] Cleanup code --- .../Importers/AssImpAnimationImporter.cpp | 8 +- .../Importers/AssImpBoneImporter.cpp | 34 ++---- .../Importers/AssImpTransformImporter.cpp | 104 ++++-------------- 3 files changed, 32 insertions(+), 114 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index f066540c50..7ab9deb141 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -463,13 +463,9 @@ namespace AZ decltype(boneAnimations) parentFillerAnimations; - // Go through all the animations and make sure we create animations for bones who's parents don't have an animation + // Go through all the animations and make sure we create placeholder animations for any bones missing them for (auto&& anim : boneAnimations) { - //const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); - //const aiNode* parent = node->mParent; - - //while (parent && parent != scene->mRootNode) for (auto boneName : boneList) { if (!IsPivotNode(aiString(boneName.c_str()))) @@ -502,8 +498,6 @@ namespace AZ AZStd::make_pair(boneName, AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } - - //parent = parent->mParent; } } diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 694e3566f6..648007ca47 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -97,7 +97,7 @@ namespace AZ EnumChildren(scene, child, mainBoneList, boneLookup); } } -#pragma optimize("", off) + Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context) { AZ_TraceContext("Importer", "Bone"); @@ -111,12 +111,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,25 +165,14 @@ namespace AZ { createdBoneData = AZStd::make_shared(); } - - // L_Lower_Eyelid_Jnt_01 - if (context.m_sourceNode.GetName() == AZStd::string("L_Lower_Eyelid_Jnt_01")) - { - //__debugbreak(); - } - - AZStd::vector transforms; - aiMatrix4x4 transform = currentNode->mTransformation; - const aiNode* parent = currentNode->mParent; - - auto addTrans = [&](auto mat) { transforms.push_back(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat)); }; - addTrans(transform); - - while (parent) + + aiMatrix4x4 transform{}; + const aiNode* iteratingNode = currentNode; + + while (iteratingNode) { - addTrans(parent->mTransformation); - transform = parent->mTransformation * transform; - parent = parent->mParent; + transform = iteratingNode->mTransformation * transform; + iteratingNode = iteratingNode->mParent; } SceneAPI::DataTypes::MatrixType globalTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform); diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index 3e22bfc671..f7a85a161b 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -62,7 +62,7 @@ namespace AZ } } } -#pragma optimize("", off) + Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context) { AZ_TraceContext("Importer", "transform"); @@ -79,104 +79,44 @@ namespace AZ auto boneIterator = boneLookup.find(currentNode->mName.C_Str()); const bool isBone = boneIterator != boneLookup.end(); - - if (currentNode->mName.C_Str() == AZStd::string("spine_C0_0_jnt")) - { - //__debugbreak(); - } - - //aiMatrix4x4 combinedTransform; - DataTypes::MatrixType finalMat; + + DataTypes::MatrixType localTransform; if (isBone) { - auto parentNode = currentNode->mParent; - - aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix; - aiMatrix4x4 parentOffset {}; - aiMatrix4x4 parentTransform{}; - - if (parentNode) - { - parentTransform = parentNode->mTransformation; - } - - auto azOffset = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(offsetMatrix); - decltype(azOffset) azParentOffset{}; - AZStd::vector transforms, offsets, inverseTransforms, inverseOffsets; - - auto addTransform = [&](AZStd::string, aiMatrix4x4 mat) - { - auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); - transforms.push_back(azMat); - inverseTransforms.push_back(azMat.GetInverseFull()); - }; - auto addOffset = [&]([[maybe_unused]] auto name, aiMatrix4x4 mat) - { - auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); - offsets.push_back(azMat); - inverseOffsets.push_back(azMat.GetInverseFull()); - }; - - auto curNode = currentNode; + AZStd::vector offsets, inverseOffsets; + auto iteratingNode = currentNode; - while (curNode && boneLookup.count(curNode->mName.C_Str())) + while (iteratingNode && boneLookup.count(iteratingNode->mName.C_Str())) { - AZStd::string name = curNode->mName.C_Str(); + AZStd::string name = iteratingNode->mName.C_Str(); auto range = boneLookup.equal_range(name); - for (auto it = range.first; it != range.second; ++it) + if (range.first != range.second) { - addOffset(name, it->second->mOffsetMatrix); - break; + // 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()); } - //addOffset(name, boneLookup.at(name)->mOffsetMatrix); - addTransform(name, curNode->mTransformation); - - curNode = curNode->mParent; - } - - // Go up the tree to find the root bone. It's parent will be the scene mRootNode - while (parentNode && parentNode->mParent && parentNode->mParent != scene->mRootNode) - { - parentNode = parentNode->mParent; - } - - auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); - aiMatrix4x4 rootOffsetMatrix{}; - - if (parentBoneIterator != boneLookup.end()) - { - rootOffsetMatrix = parentBoneIterator->second->mOffsetMatrix; + iteratingNode = iteratingNode->mParent; } - - auto inverseOffset = offsetMatrix; - inverseOffset.Inverse(); - - auto parentTransformInverse = parentTransform; - parentTransformInverse.Inverse(); - - //auto azInverse = azOffset.GetInverseFull(); - //auto azCombined = azParentOffset * azInverse; - //combinedTransform = parentOffset * inverseOffset; - - //parentTransform ^-1 * parentParent * azOffsetInverse - //combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; - - //azNodeLocal = offsets[1] * inverseOffsets[3] * (offsets[3] * inverseOffsets[0]) - finalMat = - offsets.at(AZ::GetMin(offsets.size()-1, (decltype(offsets.size()))1)) * inverseOffsets.at(inverseOffsets.size() - 1) * offsets.at(offsets.size() - 1) * inverseOffsets.at(0); + + 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 { - finalMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); + localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); } - //DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); - DataTypes::MatrixType localTransform = finalMat; - + // Don't bother adding a node with the identity matrix if (localTransform == DataTypes::MatrixType::Identity()) { return Events::ProcessingResult::Ignored; From ff81b0bfd6eb54bb2e4420b1b709c4ed73bfe22b Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu, 17 Jun 2021 10:40:33 -0500 Subject: [PATCH 07/35] Use contains method instead of find. Rename parentFillerAnimations -> fillerAnimations --- .../Importers/AssImpAnimationImporter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index 5bdc5a8add..ed6d7dfe30 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -461,7 +461,7 @@ namespace AZ } } - decltype(boneAnimations) parentFillerAnimations; + decltype(boneAnimations) fillerAnimations; // Go through all the animations and make sure we create placeholder animations for any bones missing them for (auto&& anim : boneAnimations) @@ -470,8 +470,8 @@ namespace AZ { if (!IsPivotNode(aiString(boneName.c_str()))) { - if (boneAnimations.find(boneName) == boneAnimations.end() && - parentFillerAnimations.find(boneName) == parentFillerAnimations.end()) + if (!boneAnimations.contains(boneName) && + !fillerAnimations.contains(boneName)) { // Create 1 key for each type that just copies the current transform ConsolidatedNodeAnim emptyAnimation; @@ -494,14 +494,14 @@ namespace AZ emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale); emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); - parentFillerAnimations.insert( + fillerAnimations.insert( AZStd::make_pair(boneName, AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } } } - 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()); From b9dd7a1ecd34b9a9e8ce9204f299086fc6e79cc0 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 17 Jun 2021 16:16:38 -0700 Subject: [PATCH 08/35] Updating IsNetEntityRole helper methods for more clarity. Also added tooltip scripting and comments for code --- .../Editor/Translation/scriptcanvas_en_us.ts | 19 ++++++++ .../Components/MultiplayerComponent.h | 8 ++-- .../Multiplayer/Components/NetBindComponent.h | 21 +++++++-- .../Components/MultiplayerComponent.cpp | 16 +++---- .../Components/MultiplayerController.cpp | 4 +- .../Source/Components/NetBindComponent.cpp | 43 ++++++++++--------- .../NetworkEntity/NetworkEntityManager.cpp | 2 +- 7 files changed, 74 insertions(+), 39 deletions(-) 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/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..d5e83e5751 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 }); From f825e698c9ce4c40f2926e51aebac6c147d763d7 Mon Sep 17 00:00:00 2001 From: sconel Date: Thu, 17 Jun 2021 17:37:00 -0700 Subject: [PATCH 09/35] WIP fix for referenced assets being loaded before their registration --- .../Entity/PrefabEditorEntityOwnershipService.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index 336b56653b..0ddfdc8536 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(); @@ -536,6 +534,11 @@ namespace AzToolsFramework m_playInEditorData.m_assets.emplace_back(product.ReleaseAsset().release(), AZ::Data::AssetLoadBehavior::Default); } + 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 // (load asset) -> (notify) -> (init) -> (activate) AZ::Data::AssetManager::Instance().DispatchEvents(); From 484339c4b83ce320531cb8f1dda71be5fccc7941 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Fri, 18 Jun 2021 12:56:29 -0700 Subject: [PATCH 10/35] Update AWS android package version to rev4 --- cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index 9f63185ab3..c479463c92 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.0.25992954-rev1-android TARGETS PhysX PACKAGE_HASH 9c494576c2d4ff04dee5a9e092fcd9d5af4b2845f15ffdfcaabb0dbc5b88a7a9) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) From bb0c60d1d4f97dc18973dd53360f4df14b47c58b Mon Sep 17 00:00:00 2001 From: sconel Date: Fri, 18 Jun 2021 16:43:14 -0700 Subject: [PATCH 11/35] Correctly add generated spawnables to asset manager in game mode --- .../Entity/PrefabEditorEntityOwnershipService.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index 0ddfdc8536..1172fc7162 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp @@ -532,6 +532,14 @@ 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()) From 526a0f128906741fc8bf188c53ff86370c728de9 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sun, 20 Jun 2021 20:51:59 -0700 Subject: [PATCH 12/35] Fix for Jenkins Validation: removing tabs and removing unwanted spaces. --- .../Code/Source/Components/NetBindComponent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index d5e83e5751..352bc92d1c 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -70,7 +70,7 @@ namespace Multiplayer } return netBindComponent->IsNetEntityRoleAuthority(); }) - + ->Method("IsNetEntityRoleAutonomous", [](AZ::EntityId id) -> bool { AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); if (!entity) @@ -87,7 +87,7 @@ namespace Multiplayer } return netBindComponent->IsNetEntityRoleAutonomous(); }) - + ->Method("IsNetEntityRoleClient", [](AZ::EntityId id) -> bool { AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); if (!entity) @@ -104,8 +104,8 @@ namespace Multiplayer } return netBindComponent->IsNetEntityRoleClient(); }) - - ->Method("IsNetEntityRoleServer", [](AZ::EntityId id) -> bool { + + ->Method("IsNetEntityRoleServer", [](AZ::EntityId id) -> bool { AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); if (!entity) { From a3b7cbeffcae29cb25cad7a063848c1eb96ff741 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Mon, 21 Jun 2021 10:02:10 +0100 Subject: [PATCH 13/35] New level dialog has no way to select a different folder --- Code/Sandbox/Editor/NewLevelDialog.cpp | 151 +++++++++++++++----- Code/Sandbox/Editor/NewLevelDialog.h | 14 +- Code/Sandbox/Editor/NewLevelDialog.ui | 185 ++++++++++++++++--------- 3 files changed, 245 insertions(+), 105 deletions(-) diff --git a/Code/Sandbox/Editor/NewLevelDialog.cpp b/Code/Sandbox/Editor/NewLevelDialog.cpp index 2b727665cd..75717462b7 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.cpp +++ b/Code/Sandbox/Editor/NewLevelDialog.cpp @@ -17,7 +17,10 @@ // Qt #include +#include +#include #include +#include // Editor #include "NewTerrainDialog.h" @@ -30,11 +33,33 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING // Folder in which levels are stored static const char kNewLevelDialog_LevelsFolder[] = "Levels"; +class LevelFolderValidator : public QValidator +{ +public: + LevelFolderValidator(QObject* parent) + : QValidator(parent) + { + m_parentDialog = qobject_cast(parent); + } + + QValidator::State validate([[maybe_unused]] QString& input, [[maybe_unused]] int& pos) const override + { + if (m_parentDialog->ValidateLevel()) + { + return QValidator::Acceptable; + } + + return QValidator::Intermediate; + } + +private: + CNewLevelDialog* m_parentDialog; +}; + // CNewLevelDialog dialog CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) : QDialog(pParent) - , m_ilevelFolders(0) , m_bUpdate(false) , ui(new Ui::CNewLevelDialog) , m_initialized(false) @@ -43,46 +68,70 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowTitle(tr("New Level")); - setMaximumSize(QSize(320, 280)); + setMaximumSize(QSize(430, 180)); adjustSize(); - // Default level folder is root (Levels/) - m_ilevelFolders = 0; - m_bIsResize = false; + + ui->TITLE->setText(tr("Assign a name and location to the new level.")); + ui->STATIC1->setText(tr("Location:")); + ui->STATIC2->setText(tr("Name:")); + // Level name only supports ASCII characters QRegExp rx("[_a-zA-Z0-9-]+"); QValidator* validator = new QRegExpValidator(rx, this); ui->LEVEL->setValidator(validator); - connect(ui->LEVEL_FOLDERS, SIGNAL(activated(int)), this, SLOT(OnCbnSelendokLevelFolders())); + validator = new LevelFolderValidator(this); + ui->LEVEL_FOLDERS->lineEdit()->setValidator(validator); + ui->LEVEL_FOLDERS->setErrorToolTip( + QString("The location must be a folder underneath the current project's %1 folder. (%2)") + .arg(kNewLevelDialog_LevelsFolder) + .arg(GetLevelsFolder())); + + ui->LEVEL_FOLDERS->setClearButtonEnabled(true); + QToolButton* clearButton = AzQtComponents::LineEdit::getClearButton(ui->LEVEL_FOLDERS->lineEdit()); + assert(clearButton); + connect(clearButton, &QToolButton::clicked, this, &CNewLevelDialog::OnClearButtonClicked); + + connect(ui->LEVEL_FOLDERS->lineEdit(), &QLineEdit::textEdited, this, &CNewLevelDialog::OnLevelNameChange); + connect(ui->LEVEL_FOLDERS, &AzQtComponents::BrowseEdit::attachedButtonTriggered, this, &CNewLevelDialog::PopupAssetPicker); + connect(ui->LEVEL, &QLineEdit::textChanged, this, &CNewLevelDialog::OnLevelNameChange); + m_levelFolders = GetLevelsFolder(); + m_level = ""; // First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which // widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last. // Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system // is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus(). - QTimer::singleShot(0, ui->LEVEL, SLOT(setFocus())); + QTimer::singleShot(0, ui->LEVEL, SLOT(OnStartup())); + + ReloadLevelFolder(); } CNewLevelDialog::~CNewLevelDialog() { } +void CNewLevelDialog::OnStartup() +{ + UpdateData(false); + setFocus(); +} + void CNewLevelDialog::UpdateData(bool fromUi) { if (fromUi) { m_level = ui->LEVEL->text(); - m_levelFolders = ui->LEVEL_FOLDERS->currentText(); - m_ilevelFolders = ui->LEVEL_FOLDERS->currentIndex(); + m_levelFolders = ui->LEVEL_FOLDERS->text(); } else { ui->LEVEL->setText(m_level); - ui->LEVEL_FOLDERS->setCurrentText(m_levelFolders); - ui->LEVEL_FOLDERS->setCurrentIndex(m_ilevelFolders); + ui->LEVEL_FOLDERS->lineEdit()->setText(m_levelFolders); } } @@ -90,7 +139,7 @@ void CNewLevelDialog::UpdateData(bool fromUi) void CNewLevelDialog::OnInitDialog() { - ReloadLevelFolders(); + ReloadLevelFolder(); // Disable OK until some text is entered if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok)) @@ -104,28 +153,19 @@ void CNewLevelDialog::OnInitDialog() ////////////////////////////////////////////////////////////////////////// -void CNewLevelDialog::ReloadLevelFolders() +void CNewLevelDialog::ReloadLevelFolder() { - QString levelsFolder = QString(Path::GetEditingGameDataFolder().c_str()) + "/" + kNewLevelDialog_LevelsFolder; - m_itemFolders.clear(); - ui->LEVEL_FOLDERS->clear(); - ui->LEVEL_FOLDERS->addItem(QString(kNewLevelDialog_LevelsFolder) + '/'); - ReloadLevelFoldersRec(levelsFolder); + ui->LEVEL_FOLDERS->lineEdit()->clear(); + ui->LEVEL_FOLDERS->setText(QString(kNewLevelDialog_LevelsFolder) + '/'); } -////////////////////////////////////////////////////////////////////////// -void CNewLevelDialog::ReloadLevelFoldersRec(const QString& currentFolder) +QString CNewLevelDialog::GetLevelsFolder() const { - QDir dir(currentFolder); + QDir projectDir = QDir(Path::GetEditingGameDataFolder().c_str()); + QDir projectLevelsDir = QDir(QStringLiteral("%1/%2").arg(projectDir.absolutePath()).arg(kNewLevelDialog_LevelsFolder)); - QFileInfoList infoList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - - foreach(const QFileInfo &fi, infoList) - { - m_itemFolders.push_back(fi.baseName()); - ui->LEVEL_FOLDERS->addItem(QString(kNewLevelDialog_LevelsFolder) + '/' + fi.baseName()); - } + return projectLevelsDir.absolutePath(); } ////////////////////////////////////////////////////////////////////////// @@ -133,26 +173,47 @@ QString CNewLevelDialog::GetLevel() const { QString output = m_level; - if (m_itemFolders.size() > 0 && m_ilevelFolders > 0) + QDir projectLevelsDir = QDir(GetLevelsFolder()); + + if (!m_levelFolders.isEmpty()) { - output = m_itemFolders[m_ilevelFolders - 1] + "/" + m_level; + output = m_levelFolders + "/" + m_level; } - return output; + QString relativePath = projectLevelsDir.relativeFilePath(output); + + return relativePath; } -////////////////////////////////////////////////////////////////////////// -void CNewLevelDialog::OnCbnSelendokLevelFolders() +bool CNewLevelDialog::ValidateLevel() { - UpdateData(); + // Check that the selected folder is in or below the project/LEVELS folder. + QDir projectLevelsDir = QDir(GetLevelsFolder()); + + QString selectedFolder = ui->LEVEL_FOLDERS->text(); + QString absolutePath = QDir::cleanPath(projectLevelsDir.absoluteFilePath(selectedFolder)); + QString relativePath = projectLevelsDir.relativeFilePath(absolutePath); + + // Prevent saving to a different drive. + if (projectLevelsDir.absolutePath()[0] != absolutePath[0]) + { + return false; + } + + if (relativePath.startsWith("..")) + { + return false; + } + + return true; } void CNewLevelDialog::OnLevelNameChange() { - m_level = ui->LEVEL->text(); + UpdateData(true); // QRegExpValidator means the string will always be valid as long as it's not empty: - const bool valid = !m_level.isEmpty(); + const bool valid = !m_level.isEmpty() && ValidateLevel(); // Use the validity to dynamically change the Ok button's enabled state if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok)) @@ -161,6 +222,24 @@ void CNewLevelDialog::OnLevelNameChange() } } +void CNewLevelDialog::OnClearButtonClicked() +{ + ui->LEVEL_FOLDERS->lineEdit()->setText(GetLevelsFolder()); + UpdateData(true); + +} + +void CNewLevelDialog::PopupAssetPicker() +{ + QString newPath = QFileDialog::getExistingDirectory(nullptr, QObject::tr("Choose Destination Folder"), GetLevelsFolder()); + + if (!newPath.isEmpty()) + { + ui->LEVEL_FOLDERS->setText(newPath); + OnLevelNameChange(); + } +} + ////////////////////////////////////////////////////////////////////////// void CNewLevelDialog::IsResize(bool bIsResize) { diff --git a/Code/Sandbox/Editor/NewLevelDialog.h b/Code/Sandbox/Editor/NewLevelDialog.h index fd32c03700..f995ebd69c 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.h +++ b/Code/Sandbox/Editor/NewLevelDialog.h @@ -34,6 +34,7 @@ #include +#include #include #endif @@ -50,28 +51,29 @@ public: CNewLevelDialog(QWidget* pParent = nullptr); // standard constructor ~CNewLevelDialog(); - QString GetLevel() const; void IsResize(bool bIsResize); - + bool ValidateLevel(); protected: void UpdateData(bool fromUi = true); void OnInitDialog(); - void ReloadLevelFolders(); - void ReloadLevelFoldersRec(const QString& currentFolder); + void ReloadLevelFolder(); void showEvent(QShowEvent* event); + QString GetLevelsFolder() const; + protected slots: - void OnCbnSelendokLevelFolders(); void OnLevelNameChange(); + void OnClearButtonClicked(); + void PopupAssetPicker(); + void OnStartup(); public: QString m_level; QString m_levelFolders; - int m_ilevelFolders; bool m_bIsResize; bool m_bUpdate; diff --git a/Code/Sandbox/Editor/NewLevelDialog.ui b/Code/Sandbox/Editor/NewLevelDialog.ui index 053616c78d..14227fbb53 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.ui +++ b/Code/Sandbox/Editor/NewLevelDialog.ui @@ -6,74 +6,133 @@ 0 0 - 320 - 280 + 430 + 180 - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - - - - Level - - - - - - Name: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - LEVEL - + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + Assign a name and location to the new level. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + border: 0px; + + + + + + Name + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + LEVEL + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 100 + 0 + + + + Location + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + LEVEL_FOLDERS + + + + + + + + 0 + 0 + + + + + + + + + + + + + Qt::Vertical + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + - - - - - Folder: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - LEVEL_FOLDERS - - - - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - + + + + + AzQtComponents::BrowseEdit + QWidget +
AzQtComponents/Components/Widgets/BrowseEdit.h
+ 1 +
+
From 772a75b5bcd5e5af5949325f86942b36ba28cf14 Mon Sep 17 00:00:00 2001 From: greerdv Date: Mon, 21 Jun 2021 11:12:50 +0100 Subject: [PATCH 14/35] exposing non-uniform scale component id as a behavior constant for hydra --- .../ToolsComponents/EditorNonUniformScaleComponent.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) 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) From a8ba1a99afc854227e685d414243c7b76c781cbe Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Mon, 21 Jun 2021 11:57:14 +0100 Subject: [PATCH 15/35] Update BasicEditorWorkflows_LevelEntityComponentCRUD.py --- .../BasicEditorWorkflows_LevelEntityComponentCRUD.py | 2 -- 1 file changed, 2 deletions(-) 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() From 5e4f021d556995389d2ac3b7ea676ebe7c1daa11 Mon Sep 17 00:00:00 2001 From: John Jones-Steele Date: Mon, 21 Jun 2021 15:28:41 +0100 Subject: [PATCH 16/35] Cherry picked from development --- .../AzQtComponents/Components/Style.cpp | 25 ++++++++++++++++++- .../Images/Notifications/link.svg | 4 +-- .../Private/Editor/UI/AWSCoreEditorMenu.h | 1 + .../Source/Editor/UI/AWSCoreEditorMenu.cpp | 16 ++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) 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/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/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 From 9f934a6f63e6fb880b26e995e5c976d0c1ca72bf Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Mon, 21 Jun 2021 16:25:45 +0100 Subject: [PATCH 17/35] add Draw Helpers changed notification + physx draw helpers listens to it (#1456) --- .../Viewport/ViewportMessages.h | 13 ++++ Code/Sandbox/Editor/ViewportTitleDlg.cpp | 8 +- Gems/PhysX/Code/Editor/DebugDraw.cpp | 78 ++++++++++++++++--- Gems/PhysX/Code/Editor/DebugDraw.h | 20 ++++- 4 files changed, 104 insertions(+), 15 deletions(-) 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/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index dc4815eb6a..491d31a2ff 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() 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 From d2d588901e42cddc0a473edc1ffd3aefa59f3db1 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 21 Jun 2021 11:00:27 -0500 Subject: [PATCH 18/35] Address PR feedback --- .../Importers/AssImpAnimationImporter.cpp | 34 +++++++++++-------- .../Importers/AssImpBoneImporter.cpp | 23 ++++++++----- .../Importers/AssImpBoneImporter.h | 1 + 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index ed6d7dfe30..b81d013b87 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -449,13 +449,13 @@ namespace AZ AZStd::unordered_set boneList; - for (int i = 0; i < scene->mNumMeshes; ++i) + for (int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { - auto mesh = scene->mMeshes[i]; + aiMesh* mesh = scene->mMeshes[meshIndex]; - for (auto boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + for (int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) { - auto bone = mesh->mBones[boneIndex]; + aiBone* bone = mesh->mBones[boneIndex]; boneList.insert(bone->mName.C_Str()); } @@ -463,20 +463,22 @@ namespace AZ decltype(boneAnimations) fillerAnimations; - // Go through all the animations and make sure we create placeholder animations for any bones missing them + // 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) { - for (auto boneName : boneList) + const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); + const aiNode* parent = node->mParent; + + while (parent && parent != scene->mRootNode) { - if (!IsPivotNode(aiString(boneName.c_str()))) + if (!IsPivotNode(parent->mName)) { - if (!boneAnimations.contains(boneName) && - !fillerAnimations.contains(boneName)) + 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; - auto node = scene->mRootNode->FindNode(boneName.c_str()); - aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(node); + aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(parent); aiVector3D position, scale; aiQuaternion rotation; @@ -484,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(); @@ -493,11 +495,13 @@ namespace AZ emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale); emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); - - fillerAnimations.insert( - AZStd::make_pair(boneName, 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)))); } } + + parent = parent->mParent; } } diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 648007ca47..1958c09b3c 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -98,6 +98,20 @@ namespace AZ } } + aiMatrix4x4 AssImpBoneImporter::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"); @@ -166,14 +180,7 @@ namespace AZ createdBoneData = AZStd::make_shared(); } - aiMatrix4x4 transform{}; - const aiNode* iteratingNode = currentNode; - - while (iteratingNode) - { - transform = iteratingNode->mTransformation * transform; - iteratingNode = iteratingNode->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..47cc1922cb 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h @@ -32,6 +32,7 @@ namespace AZ static void Reflect(ReflectContext* context); + aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode); Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context); }; } // namespace FbxSceneBuilder From 22ff37ecda23c8c845ee4583132ffd84b517fd29 Mon Sep 17 00:00:00 2001 From: Eric Phister <52085794+amzn-phist@users.noreply.github.com> Date: Mon, 21 Jun 2021 11:18:03 -0500 Subject: [PATCH 19/35] Fixes issue with ACE displaying only banks (#1427) Updates to some AzCore functions a while ago made some path functions strip off a trailing slash, which caused bad paths to be used when loading middleware data. Updated the code to use better path APIs. --- .../Code/Source/Editor/AudioSystemEditor_wwise.cpp | 8 ++++---- .../Code/Source/Editor/AudioSystemEditor_wwise.h | 2 +- .../Code/Source/Editor/AudioWwiseLoader.cpp | 12 ++++++------ .../Code/Include/Editor/IAudioSystemEditor.h | 3 ++- .../Code/Source/Editor/AudioControlsEditorWindow.cpp | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) 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"); } } From 514cfc3b4c2bd2aae9704b6bfb71eb2b906ee1e9 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 21 Jun 2021 12:27:13 -0500 Subject: [PATCH 20/35] Fix compile error --- .../SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp | 2 +- .../SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 1958c09b3c..e726547c98 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -98,7 +98,7 @@ namespace AZ } } - aiMatrix4x4 AssImpBoneImporter::CalculateWorldTransform(const aiNode* currentNode) + aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode) { aiMatrix4x4 transform = {}; const aiNode* iteratingNode = currentNode; diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h index 47cc1922cb..86069cdd9e 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h @@ -31,8 +31,7 @@ namespace AZ ~AssImpBoneImporter() override = default; static void Reflect(ReflectContext* context); - - aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode); + Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context); }; } // namespace FbxSceneBuilder From 74bb2737ca3eaed752a0ebdf8ade6895076d6dcf Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Mon, 21 Jun 2021 12:50:26 -0500 Subject: [PATCH 21/35] Replaced menu icon in secondary toolbar (#1459) --- .../AzQtComponents/Images/Menu/menu.svg | 11 +++++++++++ .../AzQtComponents/Images/resources.qrc | 1 + Code/Sandbox/Editor/ViewportTitleDlg.ui | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/menu.svg 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 @@ + + + Buttons / Dropdown button with Icon / no arrow + + + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index cc66558367..bf110c1899 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -28,5 +28,6 @@ Menu/script_canvas_editor.svg Menu/trackview_editor.svg Menu/ui_editor.svg + Menu/menu.svg diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.ui b/Code/Sandbox/Editor/ViewportTitleDlg.ui index 2d547bfa99..58b4ec70c6 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.ui +++ b/Code/Sandbox/Editor/ViewportTitleDlg.ui @@ -94,7 +94,7 @@ - :/stylesheet/img/UI20/menu-centered.svg:/stylesheet/img/UI20/menu-centered.svg + :/Menu/menu.svg:/Menu/menu.svg From 40a84c3c7472fe99c618d6011b88ca017e32af25 Mon Sep 17 00:00:00 2001 From: greerdv Date: Mon, 21 Jun 2021 20:09:48 +0100 Subject: [PATCH 22/35] add editor python script to help with migrating levels with non-uniform scale --- scripts/migration/non_uniform_scale.py | 57 ++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 scripts/migration/non_uniform_scale.py diff --git a/scripts/migration/non_uniform_scale.py b/scripts/migration/non_uniform_scale.py new file mode 100644 index 0000000000..a645c6818f --- /dev/null +++ b/scripts/migration/non_uniform_scale.py @@ -0,0 +1,57 @@ +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) From 46f8c7c1ba9ccc77b09eca752062c278fa7312f6 Mon Sep 17 00:00:00 2001 From: cgalvan Date: Mon, 21 Jun 2021 16:03:49 -0500 Subject: [PATCH 23/35] [LYN-3412] Updated LandscapeCanvas component to properly serialize with prefabs. (#1224) * [LYN-3412] Updated LandscapeCanvas component to properly serialize with prefabs. * [LYN-3412] Updated PR with feedback. * [LYN-3412] Reverted unintentional changes. * [LYN-3412] Removed one more comment. * [LYN-3412] Additional PR feedback fixed. --- .../Material/MaterialAssignmentSerializer.cpp | 4 +- .../Integration/GraphCanvasMetadata.h | 1 + .../Code/Include/GraphModel/Model/Graph.h | 10 +- .../Code/Include/GraphModel/Model/Slot.h | 28 +++ .../Source/Integration/GraphController.cpp | 6 +- Gems/GraphModel/Code/Source/Model/Graph.cpp | 8 +- Gems/GraphModel/Code/Source/Model/Slot.cpp | 162 +++++++++++++++++- .../Code/Source/Editor/MainWindow.cpp | 42 ++++- .../Code/Source/Editor/MainWindow.h | 8 + 9 files changed, 248 insertions(+), 21 deletions(-) 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/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; From ca76a4d1ab29074a209b190388b2149ea0ff08b5 Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Mon, 21 Jun 2021 16:11:50 -0500 Subject: [PATCH 24/35] Moved helpers to the top level menu bar above viewport (#1464) --- .../AzQtComponents/Images/Menu/helpers.svg | 24 +++++++++++++++++++ .../AzQtComponents/Images/resources.qrc | 1 + Code/Sandbox/Editor/ViewportTitleDlg.cpp | 16 +++++++------ Code/Sandbox/Editor/ViewportTitleDlg.h | 2 +- Code/Sandbox/Editor/ViewportTitleDlg.ui | 12 ++++++++++ 5 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg 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 @@ + + + Helpers Icon + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index bf110c1899..74610dca90 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -29,5 +29,6 @@ Menu/trackview_editor.svg Menu/ui_editor.svg Menu/menu.svg + Menu/helpers.svg diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index 491d31a2ff..5b13b1d308 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp +++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp @@ -130,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); @@ -211,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); @@ -333,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() @@ -759,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 58b4ec70c6..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 + + + From b69b6af305ebbdee9cdd2e12749d485be52dfea6 Mon Sep 17 00:00:00 2001 From: greerdv Date: Mon, 21 Jun 2021 22:28:50 +0100 Subject: [PATCH 25/35] add copyright notice --- scripts/migration/non_uniform_scale.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/migration/non_uniform_scale.py b/scripts/migration/non_uniform_scale.py index a645c6818f..038cb1144b 100644 --- a/scripts/migration/non_uniform_scale.py +++ b/scripts/migration/non_uniform_scale.py @@ -1,3 +1,14 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + import sys import azlmbr from pathlib import Path From ac7ec103c8460fb155bcff67b06fda6bacb85d7f Mon Sep 17 00:00:00 2001 From: mnaumov Date: Mon, 21 Jun 2021 15:20:22 -0700 Subject: [PATCH 26/35] Fixing PDO offset tooltip --- .../Common/Assets/Materials/Types/EnhancedPBR.materialtype | 2 +- .../Assets/Materials/Types/StandardMultilayerPBR.materialtype | 2 +- .../Common/Assets/Materials/Types/StandardPBR.materialtype | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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": { From a0f4f16b9842ccf4adf58ba586419198351354f2 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 21 Jun 2021 15:47:25 -0700 Subject: [PATCH 27/35] Fix Duplicate function to correctly replace the aliases in patches that get ported over. Also correctly undo/redo link creation. (#1449) --- .../Prefab/PrefabPublicHandler.cpp | 47 +++++++++++++++---- .../Prefab/PrefabPublicHandler.h | 2 +- 2 files changed, 38 insertions(+), 11 deletions(-) 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 From 4de1d90994a01886ae6bb9df4a09bf73a8545317 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Mon, 21 Jun 2021 16:52:05 -0700 Subject: [PATCH 28/35] [ATOM-15292] Camera no longer resets when typing something --- .../MaterialEditorViewportInputController.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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..9ee8fec83f 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 "Viewport/MaterialViewportWidget.h" + +#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: From 5a276b11b0e89df5fce9e667b67776c3a55c4117 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Mon, 21 Jun 2021 16:56:06 -0700 Subject: [PATCH 29/35] Fixing includes --- .../InputController/MaterialEditorViewportInputController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9ee8fec83f..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,9 +10,9 @@ * */ -#include "Viewport/MaterialViewportWidget.h" - #include +#include + #include #include #include From bfd266db8f4e298a1fddc6525245f63ecc5a8c3b Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 21 Jun 2021 18:24:29 -0700 Subject: [PATCH 30/35] LYN-4659 OSX: Prebuilt Editor and Asset Processor fail to launch (#1446) * LYN-4657 OSX: Building AutomatedTesting project fails * forgot this file * fixing lrelease patching in mac/windows * reverting change and disabling warning, the intention of the test is to compare to unitialized values * Fix for dxc * no need to disable the warning, just remove the const * missing dependency to EditorCommon --- .../Json/JsonSerializerConformityTests.h | 2 +- Code/Sandbox/Editor/CMakeLists.txt | 1 + .../Code/Platform/Mac/lrelease_mac.cmake | 9 --------- .../Platform/Windows/lrelease_windows.cmake | 16 ---------------- .../Mac/runtime_dependencies_mac.cmake.in | 17 ++++++++++++----- 5 files changed, 14 insertions(+), 31 deletions(-) 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/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/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/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() From 2dce6954a100ca9fbec24b984714f8eeb889f62b Mon Sep 17 00:00:00 2001 From: John Jones-Steele Date: Tue, 22 Jun 2021 09:41:48 +0100 Subject: [PATCH 31/35] Cherry picked from development --- Code/Sandbox/Editor/NewLevelDialog.cpp | 2 +- Code/Sandbox/Editor/NewLevelDialog.ui | 34 +- Code/Sandbox/Editor/Style/Editor.qss | 47 +- .../WelcomeScreen/DefaultActiveProject.png | 3 + .../WelcomeScreen/WelcomeScreenDialog.cpp | 197 ++--- .../WelcomeScreen/WelcomeScreenDialog.h | 16 +- .../WelcomeScreen/WelcomeScreenDialog.qrc | 2 +- .../WelcomeScreen/WelcomeScreenDialog.ui | 719 +++++++++--------- .../WelcomeScreenDialogHeader.png | 3 - 9 files changed, 455 insertions(+), 568 deletions(-) create mode 100644 Code/Sandbox/Editor/WelcomeScreen/DefaultActiveProject.png delete mode 100644 Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialogHeader.png diff --git a/Code/Sandbox/Editor/NewLevelDialog.cpp b/Code/Sandbox/Editor/NewLevelDialog.cpp index 2b727665cd..8a1399e482 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.cpp +++ b/Code/Sandbox/Editor/NewLevelDialog.cpp @@ -43,7 +43,7 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowTitle(tr("New Level")); - setMaximumSize(QSize(320, 280)); + setMaximumSize(QSize(430, 280)); adjustSize(); // Default level folder is root (Levels/) diff --git a/Code/Sandbox/Editor/NewLevelDialog.ui b/Code/Sandbox/Editor/NewLevelDialog.ui index 053616c78d..2d04794b27 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.ui +++ b/Code/Sandbox/Editor/NewLevelDialog.ui @@ -6,30 +6,30 @@ 0 0 - 320 + 430 280 - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + - Level + Assign a name and location to the new level. - Name: + Name Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -48,8 +48,14 @@ + + + 100 + 0 + + - Folder: + Location Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 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/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 From 66c4541e14c7db8b983fca9b322f7a6c47d743cd Mon Sep 17 00:00:00 2001 From: John Jones-Steele Date: Tue, 22 Jun 2021 11:25:53 +0100 Subject: [PATCH 32/35] Fixed merge error in NewLevelDialog --- Code/Sandbox/Editor/NewLevelDialog.cpp | 151 ++++++------------------- Code/Sandbox/Editor/NewLevelDialog.h | 14 +-- Code/Sandbox/Editor/NewLevelDialog.ui | 136 ++++------------------ 3 files changed, 62 insertions(+), 239 deletions(-) diff --git a/Code/Sandbox/Editor/NewLevelDialog.cpp b/Code/Sandbox/Editor/NewLevelDialog.cpp index 7c151d1d67..2b727665cd 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.cpp +++ b/Code/Sandbox/Editor/NewLevelDialog.cpp @@ -17,10 +17,7 @@ // Qt #include -#include -#include #include -#include // Editor #include "NewTerrainDialog.h" @@ -33,33 +30,11 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING // Folder in which levels are stored static const char kNewLevelDialog_LevelsFolder[] = "Levels"; -class LevelFolderValidator : public QValidator -{ -public: - LevelFolderValidator(QObject* parent) - : QValidator(parent) - { - m_parentDialog = qobject_cast(parent); - } - - QValidator::State validate([[maybe_unused]] QString& input, [[maybe_unused]] int& pos) const override - { - if (m_parentDialog->ValidateLevel()) - { - return QValidator::Acceptable; - } - - return QValidator::Intermediate; - } - -private: - CNewLevelDialog* m_parentDialog; -}; - // CNewLevelDialog dialog CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) : QDialog(pParent) + , m_ilevelFolders(0) , m_bUpdate(false) , ui(new Ui::CNewLevelDialog) , m_initialized(false) @@ -68,70 +43,46 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowTitle(tr("New Level")); - setMaximumSize(QSize(430, 280)); + setMaximumSize(QSize(320, 280)); adjustSize(); - m_bIsResize = false; + // Default level folder is root (Levels/) + m_ilevelFolders = 0; - - ui->TITLE->setText(tr("Assign a name and location to the new level.")); - ui->STATIC1->setText(tr("Location:")); - ui->STATIC2->setText(tr("Name:")); + m_bIsResize = false; // Level name only supports ASCII characters QRegExp rx("[_a-zA-Z0-9-]+"); QValidator* validator = new QRegExpValidator(rx, this); ui->LEVEL->setValidator(validator); - validator = new LevelFolderValidator(this); - ui->LEVEL_FOLDERS->lineEdit()->setValidator(validator); - ui->LEVEL_FOLDERS->setErrorToolTip( - QString("The location must be a folder underneath the current project's %1 folder. (%2)") - .arg(kNewLevelDialog_LevelsFolder) - .arg(GetLevelsFolder())); - - ui->LEVEL_FOLDERS->setClearButtonEnabled(true); - QToolButton* clearButton = AzQtComponents::LineEdit::getClearButton(ui->LEVEL_FOLDERS->lineEdit()); - assert(clearButton); - connect(clearButton, &QToolButton::clicked, this, &CNewLevelDialog::OnClearButtonClicked); - - connect(ui->LEVEL_FOLDERS->lineEdit(), &QLineEdit::textEdited, this, &CNewLevelDialog::OnLevelNameChange); - connect(ui->LEVEL_FOLDERS, &AzQtComponents::BrowseEdit::attachedButtonTriggered, this, &CNewLevelDialog::PopupAssetPicker); - + connect(ui->LEVEL_FOLDERS, SIGNAL(activated(int)), this, SLOT(OnCbnSelendokLevelFolders())); connect(ui->LEVEL, &QLineEdit::textChanged, this, &CNewLevelDialog::OnLevelNameChange); - m_levelFolders = GetLevelsFolder(); - m_level = ""; // First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which // widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last. // Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system // is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus(). - QTimer::singleShot(0, ui->LEVEL, SLOT(OnStartup())); - - ReloadLevelFolder(); + QTimer::singleShot(0, ui->LEVEL, SLOT(setFocus())); } CNewLevelDialog::~CNewLevelDialog() { } -void CNewLevelDialog::OnStartup() -{ - UpdateData(false); - setFocus(); -} - void CNewLevelDialog::UpdateData(bool fromUi) { if (fromUi) { m_level = ui->LEVEL->text(); - m_levelFolders = ui->LEVEL_FOLDERS->text(); + m_levelFolders = ui->LEVEL_FOLDERS->currentText(); + m_ilevelFolders = ui->LEVEL_FOLDERS->currentIndex(); } else { ui->LEVEL->setText(m_level); - ui->LEVEL_FOLDERS->lineEdit()->setText(m_levelFolders); + ui->LEVEL_FOLDERS->setCurrentText(m_levelFolders); + ui->LEVEL_FOLDERS->setCurrentIndex(m_ilevelFolders); } } @@ -139,7 +90,7 @@ void CNewLevelDialog::UpdateData(bool fromUi) void CNewLevelDialog::OnInitDialog() { - ReloadLevelFolder(); + ReloadLevelFolders(); // Disable OK until some text is entered if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok)) @@ -153,19 +104,28 @@ void CNewLevelDialog::OnInitDialog() ////////////////////////////////////////////////////////////////////////// -void CNewLevelDialog::ReloadLevelFolder() +void CNewLevelDialog::ReloadLevelFolders() { + QString levelsFolder = QString(Path::GetEditingGameDataFolder().c_str()) + "/" + kNewLevelDialog_LevelsFolder; + m_itemFolders.clear(); - ui->LEVEL_FOLDERS->lineEdit()->clear(); - ui->LEVEL_FOLDERS->setText(QString(kNewLevelDialog_LevelsFolder) + '/'); + ui->LEVEL_FOLDERS->clear(); + ui->LEVEL_FOLDERS->addItem(QString(kNewLevelDialog_LevelsFolder) + '/'); + ReloadLevelFoldersRec(levelsFolder); } -QString CNewLevelDialog::GetLevelsFolder() const +////////////////////////////////////////////////////////////////////////// +void CNewLevelDialog::ReloadLevelFoldersRec(const QString& currentFolder) { - QDir projectDir = QDir(Path::GetEditingGameDataFolder().c_str()); - QDir projectLevelsDir = QDir(QStringLiteral("%1/%2").arg(projectDir.absolutePath()).arg(kNewLevelDialog_LevelsFolder)); + QDir dir(currentFolder); - return projectLevelsDir.absolutePath(); + QFileInfoList infoList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + + foreach(const QFileInfo &fi, infoList) + { + m_itemFolders.push_back(fi.baseName()); + ui->LEVEL_FOLDERS->addItem(QString(kNewLevelDialog_LevelsFolder) + '/' + fi.baseName()); + } } ////////////////////////////////////////////////////////////////////////// @@ -173,47 +133,26 @@ QString CNewLevelDialog::GetLevel() const { QString output = m_level; - QDir projectLevelsDir = QDir(GetLevelsFolder()); - - if (!m_levelFolders.isEmpty()) + if (m_itemFolders.size() > 0 && m_ilevelFolders > 0) { - output = m_levelFolders + "/" + m_level; + output = m_itemFolders[m_ilevelFolders - 1] + "/" + m_level; } - QString relativePath = projectLevelsDir.relativeFilePath(output); - - return relativePath; + return output; } -bool CNewLevelDialog::ValidateLevel() +////////////////////////////////////////////////////////////////////////// +void CNewLevelDialog::OnCbnSelendokLevelFolders() { - // Check that the selected folder is in or below the project/LEVELS folder. - QDir projectLevelsDir = QDir(GetLevelsFolder()); - - QString selectedFolder = ui->LEVEL_FOLDERS->text(); - QString absolutePath = QDir::cleanPath(projectLevelsDir.absoluteFilePath(selectedFolder)); - QString relativePath = projectLevelsDir.relativeFilePath(absolutePath); - - // Prevent saving to a different drive. - if (projectLevelsDir.absolutePath()[0] != absolutePath[0]) - { - return false; - } - - if (relativePath.startsWith("..")) - { - return false; - } - - return true; + UpdateData(); } void CNewLevelDialog::OnLevelNameChange() { - UpdateData(true); + m_level = ui->LEVEL->text(); // QRegExpValidator means the string will always be valid as long as it's not empty: - const bool valid = !m_level.isEmpty() && ValidateLevel(); + const bool valid = !m_level.isEmpty(); // Use the validity to dynamically change the Ok button's enabled state if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok)) @@ -222,24 +161,6 @@ void CNewLevelDialog::OnLevelNameChange() } } -void CNewLevelDialog::OnClearButtonClicked() -{ - ui->LEVEL_FOLDERS->lineEdit()->setText(GetLevelsFolder()); - UpdateData(true); - -} - -void CNewLevelDialog::PopupAssetPicker() -{ - QString newPath = QFileDialog::getExistingDirectory(nullptr, QObject::tr("Choose Destination Folder"), GetLevelsFolder()); - - if (!newPath.isEmpty()) - { - ui->LEVEL_FOLDERS->setText(newPath); - OnLevelNameChange(); - } -} - ////////////////////////////////////////////////////////////////////////// void CNewLevelDialog::IsResize(bool bIsResize) { diff --git a/Code/Sandbox/Editor/NewLevelDialog.h b/Code/Sandbox/Editor/NewLevelDialog.h index f995ebd69c..fd32c03700 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.h +++ b/Code/Sandbox/Editor/NewLevelDialog.h @@ -34,7 +34,6 @@ #include -#include #include #endif @@ -51,29 +50,28 @@ public: CNewLevelDialog(QWidget* pParent = nullptr); // standard constructor ~CNewLevelDialog(); + QString GetLevel() const; void IsResize(bool bIsResize); - bool ValidateLevel(); + protected: void UpdateData(bool fromUi = true); void OnInitDialog(); - void ReloadLevelFolder(); + void ReloadLevelFolders(); + void ReloadLevelFoldersRec(const QString& currentFolder); void showEvent(QShowEvent* event); - QString GetLevelsFolder() const; - protected slots: + void OnCbnSelendokLevelFolders(); void OnLevelNameChange(); - void OnClearButtonClicked(); - void PopupAssetPicker(); - void OnStartup(); public: QString m_level; QString m_levelFolders; + int m_ilevelFolders; bool m_bIsResize; bool m_bUpdate; diff --git a/Code/Sandbox/Editor/NewLevelDialog.ui b/Code/Sandbox/Editor/NewLevelDialog.ui index d000e8d77f..053616c78d 100644 --- a/Code/Sandbox/Editor/NewLevelDialog.ui +++ b/Code/Sandbox/Editor/NewLevelDialog.ui @@ -6,30 +6,30 @@ 0 0 - 430 + 320 280 - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + - Assign a name and location to the new level. + Level - Name + Name: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -38,106 +38,18 @@ LEVEL - - - - - Qt::Vertical - - - - 20 - 20 - - - - - - - - - - border: 0px; - - - - - - Name - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - LEVEL - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 100 - 0 - - - - Location - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - LEVEL_FOLDERS - - - - - - - - 0 - 0 - - - - - - - - - - - - - Qt::Vertical - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + - - - 100 - 0 - - - Location + Folder: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -162,14 +74,6 @@ - - - AzQtComponents::BrowseEdit - QWidget -
AzQtComponents/Components/Widgets/BrowseEdit.h
- 1 -
-
From 858dee22103fb454af27e7c8366112e151572c3b Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Tue, 22 Jun 2021 07:05:42 -0500 Subject: [PATCH 33/35] Need to keep full asset paths around in LuaIDE (#1470) --- .../Standalone/Source/LUA/LUAEditorMainWindow.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) 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; } From 7d5a7b47acc0d8b6d2c4553626207b666f8c4b80 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Tue, 22 Jun 2021 05:12:42 -0700 Subject: [PATCH 34/35] [LYN-3717] When pulling in an actor FBX, two entities are spawned & [ATOM-15258] Clicking and Dragging fbx file into viewport produces 2 entities (#1392) * [LYN-3717] When pulling in an actor FBX, two entities are spawned & [ATOM-15258] Clicking and Dragging fbx file into viewport produces 2 entities * Added another operation to the CanSpawnEntityForProduct that checks the other products and can veto the creation process. * The model product will not create an entity in case there is already an actor exported, which prevents the issue reported by two different teams/users. --- .../AzCore/AzCore/Asset/AssetTypeInfoBus.h | 8 ++++- .../AzAssetBrowserRequestHandler.cpp | 30 ++++++++++++++----- .../Atom/RPI.Reflect/Model/ModelAsset.h | 6 +++- .../Source/RPI.Reflect/Model/ModelAsset.cpp | 23 +++++++++++++- 4 files changed, 57 insertions(+), 10 deletions(-) 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/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/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.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 From 4f84ec90d3815e87b6dfc3bb7ed4056a9dfbf2f1 Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Tue, 22 Jun 2021 08:58:15 -0700 Subject: [PATCH 35/35] Various new metal fixes (#1465) * - Fix the second window related tabbing issue - Merge calls to UseResoources acrooaa all the SRGs - Move SamplerCache to the device to ensure only one cache to reduce duplication - Fixes to compute threading numbers getting reset to 0,0,0 - Cleanup withing BufferPoolResolver - Argument buffers are now queued to be cleaned up upon shutdown --- .../AzFramework/Windowing/NativeWindow_Mac.mm | 2 + .../Passes/ReflectionCopyFrameBuffer.pass | 2 +- .../Metal/Code/Source/RHI/ArgumentBuffer.cpp | 57 +++++++------------ .../Metal/Code/Source/RHI/ArgumentBuffer.h | 19 ++++--- .../Code/Source/RHI/BufferPoolResolver.cpp | 13 +++-- .../RHI/Metal/Code/Source/RHI/CommandList.cpp | 39 ++++++++++++- .../Metal/Code/Source/RHI/CommandListBase.cpp | 2 +- .../Atom/RHI/Metal/Code/Source/RHI/Device.cpp | 7 +++ Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h | 6 ++ .../Code/Source/RHI/ShaderResourceGroup.cpp | 9 ++- .../Code/Source/RHI/ShaderResourceGroup.h | 5 +- .../Pass/Specific/DownsampleMipChainPass.h | 7 +++ .../Pass/Specific/DownsampleMipChainPass.cpp | 20 +++++++ 13 files changed, 127 insertions(+), 61 deletions(-) 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/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/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/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