Merge branch 'stabilization/2106' into JsonSerialization/UnsupportedWarnings
This commit is contained in:
@@ -41,7 +41,7 @@ def PrefabLevel_OpensLevelWithEntities():
|
|||||||
EXPECTED_EMPTY_ENTITY_POS = Vector3(10.00, 20.0, 30.0)
|
EXPECTED_EMPTY_ENTITY_POS = Vector3(10.00, 20.0, 30.0)
|
||||||
|
|
||||||
helper.init_idle()
|
helper.init_idle()
|
||||||
helper.open_level("prefab", "PrefabLevel_OpensLevelWithEntities")
|
helper.open_level("Prefab", "PrefabLevel_OpensLevelWithEntities")
|
||||||
|
|
||||||
def find_entity(entity_name):
|
def find_entity(entity_name):
|
||||||
searchFilter = entity.SearchFilter()
|
searchFilter = entity.SearchFilter()
|
||||||
|
|||||||
+3
-2
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"Source": "Levels/PrefabLevel_OpensLevelWithEntities/PrefabLevel_OpensLevelWithEntities.prefab",
|
"Source": "Levels/Prefab/PrefabLevel_OpensLevelWithEntities/PrefabLevel_OpensLevelWithEntities.prefab",
|
||||||
"ContainerEntity": {
|
"ContainerEntity": {
|
||||||
"Id": "Entity_[403811863694]",
|
"Id": "Entity_[403811863694]",
|
||||||
"Name": "Level",
|
"Name": "Level",
|
||||||
@@ -15,7 +15,8 @@
|
|||||||
"Component_[13764860261821571747]": {
|
"Component_[13764860261821571747]": {
|
||||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||||
"Id": 13764860261821571747,
|
"Id": 13764860261821571747,
|
||||||
"Parent Entity": ""
|
"Parent Entity": "",
|
||||||
|
"Cached World Transform Parent": ""
|
||||||
},
|
},
|
||||||
"Component_[15844324401733835865]": {
|
"Component_[15844324401733835865]": {
|
||||||
"$type": "EditorEntitySortComponent",
|
"$type": "EditorEntitySortComponent",
|
||||||
|
|||||||
+18
-18
@@ -88,28 +88,28 @@ if(NOT INSTALLED_ENGINE)
|
|||||||
# Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
|
# Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
|
||||||
# external subdirectories
|
# external subdirectories
|
||||||
add_engine_json_external_subdirectories()
|
add_engine_json_external_subdirectories()
|
||||||
get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS)
|
|
||||||
list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs})
|
|
||||||
|
|
||||||
# Loop over the additional external subdirectories and invoke add_subdirectory on them
|
|
||||||
foreach(external_directory ${LY_EXTERNAL_SUBDIRS})
|
|
||||||
# Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory
|
|
||||||
# This is to deal with potential situations where multiple external directories has the same last directory name
|
|
||||||
# For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory
|
|
||||||
file(REAL_PATH ${external_directory} full_directory_path)
|
|
||||||
string(SHA256 full_directory_hash ${full_directory_path})
|
|
||||||
# Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit
|
|
||||||
# when the external subdirectory contains relative paths of significant length
|
|
||||||
string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash)
|
|
||||||
# Use the last directory as the suffix path to use for the Binary Directory
|
|
||||||
get_filename_component(directory_name ${external_directory} NAME)
|
|
||||||
add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
else()
|
else()
|
||||||
ly_find_o3de_packages()
|
ly_find_o3de_packages()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS)
|
||||||
|
list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs})
|
||||||
|
|
||||||
|
# Loop over the additional external subdirectories and invoke add_subdirectory on them
|
||||||
|
foreach(external_directory ${LY_EXTERNAL_SUBDIRS})
|
||||||
|
# Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory
|
||||||
|
# This is to deal with potential situations where multiple external directories has the same last directory name
|
||||||
|
# For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory
|
||||||
|
file(REAL_PATH ${external_directory} full_directory_path)
|
||||||
|
string(SHA256 full_directory_hash ${full_directory_path})
|
||||||
|
# Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit
|
||||||
|
# when the external subdirectory contains relative paths of significant length
|
||||||
|
string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash)
|
||||||
|
# Use the last directory as the suffix path to use for the Binary Directory
|
||||||
|
get_filename_component(directory_name ${external_directory} NAME)
|
||||||
|
add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Post-processing
|
# Post-processing
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -162,6 +162,55 @@ namespace AZ
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void GetTypeNamesFold(AZStd::vector<AZStd::string>& result, AZ::BehaviorContext& context)
|
||||||
|
{
|
||||||
|
result.push_back(OnDemandPrettyName<T>::Get(context));
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
void GetTypeNames(AZStd::vector<AZStd::string>& result, AZ::BehaviorContext& context)
|
||||||
|
{
|
||||||
|
(GetTypeNamesFold<T>(result, context), ...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void GetTypeNamesFold(AZStd::string& result, AZ::BehaviorContext& context)
|
||||||
|
{
|
||||||
|
if (!result.empty())
|
||||||
|
{
|
||||||
|
result += ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
result += OnDemandPrettyName<T>::Get(context);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
void GetTypeNames(AZStd::string& result, AZ::BehaviorContext& context)
|
||||||
|
{
|
||||||
|
(GetTypeNamesFold<T>(result, context), ...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
struct OnDemandPrettyName<AZStd::tuple<T...>>
|
||||||
|
{
|
||||||
|
static AZStd::string Get(AZ::BehaviorContext& context)
|
||||||
|
{
|
||||||
|
AZStd::string typeNames;
|
||||||
|
GetTypeNames<T...>(typeNames, context);
|
||||||
|
return AZStd::string::format("Tuple<%s>", typeNames.c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
struct OnDemandToolTip<AZStd::tuple<T...>>
|
||||||
|
{
|
||||||
|
static AZStd::string Get(AZ::BehaviorContext&)
|
||||||
|
{
|
||||||
|
return "A tuple is an fixed size collection of any number of any type of element.";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<class Key, class MappedType, class Hasher, class EqualKey, class Allocator>
|
template<class Key, class MappedType, class Hasher, class EqualKey, class Allocator>
|
||||||
struct OnDemandPrettyName< AZStd::unordered_map<Key, MappedType, Hasher, EqualKey, Allocator> >
|
struct OnDemandPrettyName< AZStd::unordered_map<Key, MappedType, Hasher, EqualKey, Allocator> >
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -813,20 +813,27 @@ namespace AZ
|
|||||||
{
|
{
|
||||||
using ContainerType = AZStd::tuple<T...>;
|
using ContainerType = AZStd::tuple<T...>;
|
||||||
|
|
||||||
template<size_t Index>
|
template<typename Targ, size_t Index>
|
||||||
static void ReflectUnpackMethodFold(BehaviorContext::ClassBuilder<ContainerType>& builder)
|
static void ReflectUnpackMethodFold(BehaviorContext::ClassBuilder<ContainerType>& builder, const AZStd::vector<AZStd::string>& typeNames)
|
||||||
{
|
{
|
||||||
const AZStd::string methodName = AZStd::string::format("Get%zu", Index);
|
const AZStd::string methodName = AZStd::string::format("Get%zu", Index);
|
||||||
builder->Method(methodName.data(), [](ContainerType& value) { return AZStd::get<Index>(value); })
|
builder->Method(methodName.data(), [](ContainerType& thisPointer) { return AZStd::get<Index>(thisPointer); })
|
||||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
|
||||||
->Attribute(AZ::ScriptCanvasAttributes::TupleGetFunctionIndex, Index)
|
->Attribute(AZ::ScriptCanvasAttributes::TupleGetFunctionIndex, Index)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
builder->Property
|
||||||
|
( AZStd::string::format("element_%zu_%s", Index, typeNames[Index].c_str()).c_str()
|
||||||
|
, [](ContainerType& thisPointer) { return AZStd::get<Index>(thisPointer); }
|
||||||
|
, [](ContainerType& thisPointer, const Targ& element) { AZStd::get<Index>(thisPointer) = element; });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t... Indices>
|
template<typename... Targ, size_t... Indices>
|
||||||
static void ReflectUnpackMethods(BehaviorContext::ClassBuilder<ContainerType>& builder, AZStd::index_sequence<Indices...>)
|
static void ReflectUnpackMethods(BehaviorContext::ClassBuilder<ContainerType>& builder, AZStd::index_sequence<Indices...>)
|
||||||
{
|
{
|
||||||
(ReflectUnpackMethodFold<Indices>(builder), ...);
|
AZStd::vector<AZStd::string> typeNames;
|
||||||
|
ScriptCanvasOnDemandReflection::GetTypeNames<T...>(typeNames, *builder.m_context);
|
||||||
|
(ReflectUnpackMethodFold<Targ, Indices>(builder, typeNames), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Reflect(ReflectContext* context)
|
static void Reflect(ReflectContext* context)
|
||||||
@@ -851,9 +858,10 @@ namespace AZ
|
|||||||
->Attribute(AZ::ScriptCanvasAttributes::TupleConstructorFunction, constructorHolder)
|
->Attribute(AZ::ScriptCanvasAttributes::TupleConstructorFunction, constructorHolder)
|
||||||
;
|
;
|
||||||
|
|
||||||
ReflectUnpackMethods(builder, AZStd::make_index_sequence<sizeof...(T)>{});
|
ReflectUnpackMethods<T...>(builder, AZStd::make_index_sequence<sizeof...(T)>{});
|
||||||
|
|
||||||
builder->Method("GetSize", []() { return AZStd::tuple_size<ContainerType>::value; })
|
builder->Method("GetSize", []() { return AZStd::tuple_size<ContainerType>::value; })
|
||||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ namespace AZ
|
|||||||
//! Save a string to a file. Otherwise returns a failure with error message.
|
//! Save a string to a file. Otherwise returns a failure with error message.
|
||||||
AZ::Outcome<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath);
|
AZ::Outcome<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath);
|
||||||
|
|
||||||
//! Read a file into a string. Returns a failure with error message if the content could not be loaded.
|
//! Read a file into a string. Returns a failure with error message if the content could not be loaded or if
|
||||||
|
//! the file size is larger than the max file size provided.
|
||||||
template<typename Container = AZStd::string>
|
template<typename Container = AZStd::string>
|
||||||
AZ::Outcome<Container, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize = DefaultMaxFileSize);
|
AZ::Outcome<Container, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize = DefaultMaxFileSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,10 @@ namespace AzPhysics
|
|||||||
if (auto* behaviorContext = azdynamic_cast<AZ::BehaviorContext*>(context))
|
if (auto* behaviorContext = azdynamic_cast<AZ::BehaviorContext*>(context))
|
||||||
{
|
{
|
||||||
behaviorContext->Class<TriggerEvent>()
|
behaviorContext->Class<TriggerEvent>()
|
||||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
->Attribute(AZ::Script::Attributes::Module, "physics")
|
||||||
->Method("GetTriggerEntityId", &TriggerEvent::GetTriggerEntityId)
|
->Attribute(AZ::Script::Attributes::Category, "Physics")
|
||||||
->Method("GetOtherEntityId", &TriggerEvent::GetOtherEntityId)
|
->Method("Get Trigger EntityId", &TriggerEvent::GetTriggerEntityId)
|
||||||
|
->Method("Get Other EntityId", &TriggerEvent::GetOtherEntityId)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,10 +105,11 @@ namespace AzPhysics
|
|||||||
if (auto* behaviorContext = azdynamic_cast<AZ::BehaviorContext*>(context))
|
if (auto* behaviorContext = azdynamic_cast<AZ::BehaviorContext*>(context))
|
||||||
{
|
{
|
||||||
behaviorContext->Class<CollisionEvent>()
|
behaviorContext->Class<CollisionEvent>()
|
||||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
->Attribute(AZ::Script::Attributes::Module, "physics")
|
||||||
->Property("Contacts", BehaviorValueProperty(&CollisionEvent::m_contacts))
|
->Attribute(AZ::Script::Attributes::Category, "Physics")
|
||||||
->Method("GetBody1EntityId", &CollisionEvent::GetBody1EntityId)
|
->Property("Contacts", BehaviorValueGetter(&CollisionEvent::m_contacts), nullptr)
|
||||||
->Method("GetBody2EntityId", &CollisionEvent::GetBody2EntityId)
|
->Method("Get Body 1 EntityId", &CollisionEvent::GetBody1EntityId)
|
||||||
|
->Method("Get Body 2 EntityId", &CollisionEvent::GetBody2EntityId)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,28 +9,24 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME})
|
||||||
|
|
||||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME})
|
ly_add_target(
|
||||||
|
NAME AzTest STATIC
|
||||||
ly_add_target(
|
NAMESPACE AZ
|
||||||
NAME AzTest STATIC
|
FILES_CMAKE
|
||||||
NAMESPACE AZ
|
AzTest/aztest_files.cmake
|
||||||
FILES_CMAKE
|
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||||
AzTest/aztest_files.cmake
|
INCLUDE_DIRECTORIES
|
||||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
PUBLIC
|
||||||
INCLUDE_DIRECTORIES
|
.
|
||||||
PUBLIC
|
${pal_dir}
|
||||||
.
|
BUILD_DEPENDENCIES
|
||||||
${pal_dir}
|
PUBLIC
|
||||||
BUILD_DEPENDENCIES
|
3rdParty::googletest::GMock
|
||||||
PUBLIC
|
3rdParty::googletest::GTest
|
||||||
3rdParty::googletest::GMock
|
3rdParty::GoogleBenchmark
|
||||||
3rdParty::googletest::GTest
|
AZ::AzCore
|
||||||
3rdParty::GoogleBenchmark
|
PLATFORM_INCLUDE_FILES
|
||||||
AZ::AzCore
|
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
|
||||||
PLATFORM_INCLUDE_FILES
|
)
|
||||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
|
|
||||||
)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
bool detachedWindow = false; ///< set to true if the view pane should use a detached, non-dockable widget. This is to workaround a problem with QOpenGLWidget on macOS. Currently this has no effect on other platforms.
|
bool detachedWindow = false; ///< set to true if the view pane should use a detached, non-dockable widget. This is to workaround a problem with QOpenGLWidget on macOS. Currently this has no effect on other platforms.
|
||||||
bool isDisabledInSimMode = false; ///< set to true if the view pane should not be openable from level editor menu when editor is in simulation mode.
|
bool isDisabledInSimMode = false; ///< set to true if the view pane should not be openable from level editor menu when editor is in simulation mode.
|
||||||
|
|
||||||
|
bool showOnToolsToolbar = false; ///< set to true if the view pane should create a button on the tools toolbar to open/close the pane
|
||||||
|
QString toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AzToolsFramework
|
} // namespace AzToolsFramework
|
||||||
|
|||||||
+1
-7
@@ -185,13 +185,7 @@ namespace AzToolsFramework
|
|||||||
bool PrefabEditorEntityOwnershipService::LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename)
|
bool PrefabEditorEntityOwnershipService::LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
// Make loading from stream to behave the same in terms of filesize as regular loading of prefabs
|
|
||||||
// This may need to be revisited in the future for supporting higher sizes along with prefab loading
|
|
||||||
if (stream.GetLength() > Prefab::MaxPrefabFileSize)
|
|
||||||
{
|
|
||||||
AZ_Error("Prefab", false, "'%.*s' prefab content is bigger than the max supported size (%f MB)", AZ_STRING_ARG(filename), Prefab::MaxPrefabFileSize / (1024.f * 1024.f));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const size_t bufSize = stream.GetLength();
|
const size_t bufSize = stream.GetLength();
|
||||||
AZStd::unique_ptr<char[]> buf(new char[bufSize]);
|
AZStd::unique_ptr<char[]> buf(new char[bufSize]);
|
||||||
AZ::IO::SizeType bytes = stream.Read(bufSize, buf.get());
|
AZ::IO::SizeType bytes = stream.Read(bufSize, buf.get());
|
||||||
|
|||||||
+7
-2
@@ -47,8 +47,13 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
virtual void AppendEntityAliasToPatchPaths(PrefabDom& providedPatch, const AZ::EntityId& entityId) = 0;
|
virtual void AppendEntityAliasToPatchPaths(PrefabDom& providedPatch, const AZ::EntityId& entityId) = 0;
|
||||||
|
|
||||||
//! Updates the template links (updating instances) for the given templateId using the providedPatch
|
//! Updates the template links (updating instances) for the given template and triggers propagation on its instances.
|
||||||
virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId) = 0;
|
//! @param providedPatch The patch to apply to the template.
|
||||||
|
//! @param templateId The id of the template to update.
|
||||||
|
//! @param instanceToExclude An optional reference to an instance of the template being updated that should not be refreshes as part of propagation.
|
||||||
|
//! Defaults to nullopt, which means that all instances will be refreshed.
|
||||||
|
//! @return True if the template was patched correctly, false if the operation failed.
|
||||||
|
virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0;
|
||||||
|
|
||||||
virtual void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) = 0;
|
virtual void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) = 0;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -172,7 +172,7 @@ namespace AzToolsFramework
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId)
|
bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude)
|
||||||
{
|
{
|
||||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ namespace AzToolsFramework
|
|||||||
if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success)
|
if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success)
|
||||||
{
|
{
|
||||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
|
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
|
||||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId);
|
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
InstanceOptionalReference GetTopMostInstanceInHierarchy(AZ::EntityId entityId);
|
InstanceOptionalReference GetTopMostInstanceInHierarchy(AZ::EntityId entityId);
|
||||||
|
|
||||||
bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId) override;
|
bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override;
|
||||||
|
|
||||||
void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) override;
|
void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) override;
|
||||||
|
|
||||||
|
|||||||
+68
-21
@@ -56,7 +56,7 @@ namespace AzToolsFramework
|
|||||||
AZ::Interface<InstanceUpdateExecutorInterface>::Unregister(this);
|
AZ::Interface<InstanceUpdateExecutorInterface>::Unregister(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceUpdateExecutor::AddTemplateInstancesToQueue(TemplateId instanceTemplateId)
|
void InstanceUpdateExecutor::AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude)
|
||||||
{
|
{
|
||||||
auto findInstancesResult =
|
auto findInstancesResult =
|
||||||
m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId);
|
m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId);
|
||||||
@@ -70,9 +70,18 @@ namespace AzToolsFramework
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instance* instanceToExcludePtr = nullptr;
|
||||||
|
if (instanceToExclude.has_value())
|
||||||
|
{
|
||||||
|
instanceToExcludePtr = &(instanceToExclude->get());
|
||||||
|
}
|
||||||
|
|
||||||
for (auto instance : findInstancesResult->get())
|
for (auto instance : findInstancesResult->get())
|
||||||
{
|
{
|
||||||
m_instancesUpdateQueue.emplace_back(instance);
|
if (instance != instanceToExcludePtr)
|
||||||
|
{
|
||||||
|
m_instancesUpdateQueue.emplace_back(instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +112,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
EntityIdList selectedEntityIds;
|
EntityIdList selectedEntityIds;
|
||||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
|
ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
|
||||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, EntityIdList());
|
PrefabDom instanceDomFromRootDocument;
|
||||||
|
|
||||||
// Process all instances in the queue, capped to the batch size.
|
// Process all instances in the queue, capped to the batch size.
|
||||||
// Even though we potentially initialized the batch size to the queue, it's possible for the queue size to shrink
|
// Even though we potentially initialized the batch size to the queue, it's possible for the queue size to shrink
|
||||||
@@ -148,13 +157,62 @@ namespace AzToolsFramework
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Template& currentTemplate = currentTemplateReference->get();
|
|
||||||
Instance::EntityList newEntities;
|
Instance::EntityList newEntities;
|
||||||
if (PrefabDomUtils::LoadInstanceFromPrefabDom(*instanceToUpdate, newEntities, currentTemplate.GetPrefabDom()))
|
|
||||||
|
// Climb up to the root of the instance hierarchy from this instance
|
||||||
|
InstanceOptionalConstReference rootInstance = *instanceToUpdate;
|
||||||
|
AZStd::vector<InstanceOptionalConstReference> pathOfInstances;
|
||||||
|
|
||||||
|
while (rootInstance->get().GetParentInstance() != AZStd::nullopt)
|
||||||
{
|
{
|
||||||
// If a link was created for a nested instance before the changes were propagated,
|
pathOfInstances.emplace_back(rootInstance);
|
||||||
// then we associate it correctly here
|
rootInstance = rootInstance->get().GetParentInstance();
|
||||||
instanceToUpdate->GetNestedInstances([&](AZStd::unique_ptr<Instance>& nestedInstance) {
|
}
|
||||||
|
|
||||||
|
AZStd::string aliasPathResult = "";
|
||||||
|
for (auto instanceIter = pathOfInstances.rbegin(); instanceIter != pathOfInstances.rend(); ++instanceIter)
|
||||||
|
{
|
||||||
|
aliasPathResult.append("/Instances/");
|
||||||
|
aliasPathResult.append((*instanceIter)->get().GetInstanceAlias());
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefabDomPath rootPrefabDomPath(aliasPathResult.c_str());
|
||||||
|
|
||||||
|
PrefabDom& rootPrefabTemplateDom =
|
||||||
|
m_prefabSystemComponentInterface->FindTemplateDom(rootInstance->get().GetTemplateId());
|
||||||
|
|
||||||
|
auto instanceDomFromRootValue = rootPrefabDomPath.Get(rootPrefabTemplateDom);
|
||||||
|
if (!instanceDomFromRootValue)
|
||||||
|
{
|
||||||
|
AZ_Assert(
|
||||||
|
false,
|
||||||
|
"InstanceUpdateExecutor::UpdateTemplateInstancesInQueue - "
|
||||||
|
"Could not load Instance DOM from the top level ancestor's DOM.");
|
||||||
|
|
||||||
|
isUpdateSuccessful = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefabDomValueReference instanceDomFromRoot = *instanceDomFromRootValue;
|
||||||
|
if (!instanceDomFromRoot.has_value())
|
||||||
|
{
|
||||||
|
AZ_Assert(
|
||||||
|
false,
|
||||||
|
"InstanceUpdateExecutor::UpdateTemplateInstancesInQueue - "
|
||||||
|
"Could not load Instance DOM from the top level ancestor's DOM.");
|
||||||
|
|
||||||
|
isUpdateSuccessful = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a link was created for a nested instance before the changes were propagated,
|
||||||
|
// then we associate it correctly here
|
||||||
|
instanceDomFromRootDocument.CopyFrom(instanceDomFromRoot->get(), instanceDomFromRootDocument.GetAllocator());
|
||||||
|
if (PrefabDomUtils::LoadInstanceFromPrefabDom(*instanceToUpdate, newEntities, instanceDomFromRootDocument))
|
||||||
|
{
|
||||||
|
Template& currentTemplate = currentTemplateReference->get();
|
||||||
|
instanceToUpdate->GetNestedInstances([&](AZStd::unique_ptr<Instance>& nestedInstance)
|
||||||
|
{
|
||||||
if (nestedInstance->GetLinkId() != InvalidLinkId)
|
if (nestedInstance->GetLinkId() != InvalidLinkId)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -179,22 +237,11 @@ namespace AzToolsFramework
|
|||||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||||
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, newEntities);
|
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, newEntities);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error(
|
|
||||||
"Prefab", false,
|
|
||||||
"InstanceUpdateExecutor::UpdateTemplateInstancesInQueue - "
|
|
||||||
"Could not load Instance from Prefab DOM of Template with Id '%llu' on file path '%s'.",
|
|
||||||
currentTemplateId, currentTemplate.GetFilePath().c_str());
|
|
||||||
|
|
||||||
isUpdateSuccessful = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto entityIdIterator = selectedEntityIds.begin(); entityIdIterator != selectedEntityIds.end(); entityIdIterator++)
|
for (auto entityIdIterator = selectedEntityIds.begin(); entityIdIterator != selectedEntityIds.end(); entityIdIterator++)
|
||||||
{
|
{
|
||||||
// Since entities get recreated during propagation, we need to check whether the entities correspoding to the list
|
// Since entities get recreated during propagation, we need to check whether the entities
|
||||||
// of selected entity ids are present or not.
|
// corresponding to the list of selected entity ids are present or not.
|
||||||
AZ::Entity* entity = GetEntityById(*entityIdIterator);
|
AZ::Entity* entity = GetEntityById(*entityIdIterator);
|
||||||
if (entity == nullptr)
|
if (entity == nullptr)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
explicit InstanceUpdateExecutor(int instanceCountToUpdateInBatch = 0);
|
explicit InstanceUpdateExecutor(int instanceCountToUpdateInBatch = 0);
|
||||||
|
|
||||||
void AddTemplateInstancesToQueue(TemplateId instanceTemplateId) override;
|
void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override;
|
||||||
bool UpdateTemplateInstancesInQueue() override;
|
bool UpdateTemplateInstancesInQueue() override;
|
||||||
virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) override;
|
virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) override;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ namespace AzToolsFramework
|
|||||||
virtual ~InstanceUpdateExecutorInterface() = default;
|
virtual ~InstanceUpdateExecutorInterface() = default;
|
||||||
|
|
||||||
// Add all Instances of Template with given Id into a queue for updating them later.
|
// Add all Instances of Template with given Id into a queue for updating them later.
|
||||||
virtual void AddTemplateInstancesToQueue(TemplateId instanceTemplateId) = 0;
|
virtual void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0;
|
||||||
|
|
||||||
// Update Instances in the waiting queue.
|
// Update Instances in the waiting queue.
|
||||||
virtual bool UpdateTemplateInstancesInQueue() = 0;
|
virtual bool UpdateTemplateInstancesInQueue() = 0;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace AzToolsFramework
|
|||||||
return InvalidTemplateId;
|
return InvalidTemplateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readResult = AZ::Utils::ReadFile(GetFullPath(filePath).Native(), MaxPrefabFileSize);
|
auto readResult = AZ::Utils::ReadFile(GetFullPath(filePath).Native(), AZStd::numeric_limits<size_t>::max());
|
||||||
if (!readResult.IsSuccess())
|
if (!readResult.IsSuccess())
|
||||||
{
|
{
|
||||||
AZ_Error(
|
AZ_Error(
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ namespace AzToolsFramework
|
|||||||
{
|
{
|
||||||
namespace Prefab
|
namespace Prefab
|
||||||
{
|
{
|
||||||
constexpr size_t MaxPrefabFileSize = 1024 * 1024;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* PrefabLoaderInterface
|
* PrefabLoaderInterface
|
||||||
* Interface for saving/loading Prefab files.
|
* Interface for saving/loading Prefab files.
|
||||||
|
|||||||
@@ -242,11 +242,13 @@ namespace AzToolsFramework
|
|||||||
m_instanceToTemplateInterface->GenerateDomForEntity(containerAfterReset, *containerEntity);
|
m_instanceToTemplateInterface->GenerateDomForEntity(containerAfterReset, *containerEntity);
|
||||||
|
|
||||||
// Update the state of the entity
|
// Update the state of the entity
|
||||||
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(containerEntityId)));
|
auto templateId = instanceToCreate->get().GetTemplateId();
|
||||||
state->SetParent(undoBatch.GetUndoBatch());
|
|
||||||
state->Capture(containerBeforeReset, containerAfterReset, containerEntityId);
|
|
||||||
|
|
||||||
state->Redo();
|
PrefabDom transformPatch;
|
||||||
|
m_instanceToTemplateInterface->GeneratePatch(transformPatch, containerBeforeReset, containerAfterReset);
|
||||||
|
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(transformPatch, containerEntityId);
|
||||||
|
|
||||||
|
m_instanceToTemplateInterface->PatchTemplate(transformPatch, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This clears any entities marked as dirty due to reparenting of entities during the process of creating a prefab.
|
// This clears any entities marked as dirty due to reparenting of entities during the process of creating a prefab.
|
||||||
@@ -661,12 +663,12 @@ namespace AzToolsFramework
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Internal_HandleContainerOverride(
|
Internal_HandleContainerOverride(
|
||||||
parentUndoBatch, entityId, patch, owningInstance->get().GetLinkId());
|
parentUndoBatch, entityId, patch, owningInstance->get().GetLinkId(), owningInstance->get().GetParentInstance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Internal_HandleEntityChange(parentUndoBatch, entityId, beforeState, afterState);
|
Internal_HandleEntityChange(parentUndoBatch, entityId, beforeState, afterState, owningInstance);
|
||||||
|
|
||||||
if (isNewParentOwnedByDifferentInstance)
|
if (isNewParentOwnedByDifferentInstance)
|
||||||
{
|
{
|
||||||
@@ -679,25 +681,27 @@ namespace AzToolsFramework
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PrefabPublicHandler::Internal_HandleContainerOverride(
|
void PrefabPublicHandler::Internal_HandleContainerOverride(
|
||||||
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, const PrefabDom& patch, const LinkId linkId)
|
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, const PrefabDom& patch,
|
||||||
|
const LinkId linkId, InstanceOptionalReference parentInstance)
|
||||||
{
|
{
|
||||||
// Save these changes as patches to the link
|
// Save these changes as patches to the link
|
||||||
PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
|
PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
|
||||||
linkUpdate->SetParent(undoBatch);
|
linkUpdate->SetParent(undoBatch);
|
||||||
linkUpdate->Capture(patch, linkId);
|
linkUpdate->Capture(patch, linkId);
|
||||||
|
|
||||||
linkUpdate->Redo();
|
linkUpdate->Redo(parentInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabPublicHandler::Internal_HandleEntityChange(
|
void PrefabPublicHandler::Internal_HandleEntityChange(
|
||||||
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, PrefabDom& beforeState, PrefabDom& afterState)
|
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, PrefabDom& beforeState,
|
||||||
|
PrefabDom& afterState, InstanceOptionalReference instance)
|
||||||
{
|
{
|
||||||
// Update the state of the entity
|
// Update the state of the entity
|
||||||
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
|
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
|
||||||
state->SetParent(undoBatch);
|
state->SetParent(undoBatch);
|
||||||
state->Capture(beforeState, afterState, entityId);
|
state->Capture(beforeState, afterState, entityId);
|
||||||
|
|
||||||
state->Redo();
|
state->Redo(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabPublicHandler::Internal_HandleInstanceChange(
|
void PrefabPublicHandler::Internal_HandleInstanceChange(
|
||||||
@@ -897,7 +901,13 @@ namespace AzToolsFramework
|
|||||||
return AZ::Failure(AZStd::string("No entities to duplicate."));
|
return AZ::Failure(AZStd::string("No entities to duplicate."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EntitiesBelongToSameInstance(entityIds))
|
const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds);
|
||||||
|
if (entityIdsNoLevelInstance.empty())
|
||||||
|
{
|
||||||
|
return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the level instance."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance))
|
||||||
{
|
{
|
||||||
return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation."
|
return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation."
|
||||||
"Change your selection to contain entities in the same instance."));
|
"Change your selection to contain entities in the same instance."));
|
||||||
@@ -905,7 +915,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
// We've already verified the entities are all owned by the same instance,
|
// We've already verified the entities are all owned by the same instance,
|
||||||
// so we can just retrieve our instance from the first entity in the list.
|
// so we can just retrieve our instance from the first entity in the list.
|
||||||
AZ::EntityId firstEntityIdToDuplicate = entityIds[0];
|
AZ::EntityId firstEntityIdToDuplicate = entityIdsNoLevelInstance[0];
|
||||||
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate);
|
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate);
|
||||||
if (!commonOwningInstance.has_value())
|
if (!commonOwningInstance.has_value())
|
||||||
{
|
{
|
||||||
@@ -925,7 +935,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
// This will cull out any entities that have ancestors in the list, since we will end up duplicating
|
// This will cull out any entities that have ancestors in the list, since we will end up duplicating
|
||||||
// the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances
|
// the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances
|
||||||
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIds);
|
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIdsNoLevelInstance);
|
||||||
|
|
||||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||||
|
|
||||||
@@ -1000,17 +1010,19 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants)
|
PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants)
|
||||||
{
|
{
|
||||||
if (entityIds.empty())
|
const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds);
|
||||||
|
|
||||||
|
if (entityIdsNoLevelInstance.empty())
|
||||||
{
|
{
|
||||||
return AZ::Success();
|
return AZ::Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EntitiesBelongToSameInstance(entityIds))
|
if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance))
|
||||||
{
|
{
|
||||||
return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation."));
|
return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation."));
|
||||||
}
|
}
|
||||||
|
|
||||||
AZ::EntityId firstEntityIdToDelete = entityIds[0];
|
AZ::EntityId firstEntityIdToDelete = entityIdsNoLevelInstance[0];
|
||||||
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete);
|
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete);
|
||||||
|
|
||||||
// If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
|
// If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
|
||||||
@@ -1021,7 +1033,7 @@ namespace AzToolsFramework
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve entityList from entityIds
|
// Retrieve entityList from entityIds
|
||||||
EntityList inputEntityList = EntityIdListToEntityList(entityIds);
|
EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoLevelInstance);
|
||||||
|
|
||||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||||
|
|
||||||
@@ -1077,7 +1089,7 @@ namespace AzToolsFramework
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (AZ::EntityId entityId : entityIds)
|
for (AZ::EntityId entityId : entityIdsNoLevelInstance)
|
||||||
{
|
{
|
||||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||||
// If this is the container entity, it actually represents the instance so get its owner
|
// If this is the container entity, it actually represents the instance so get its owner
|
||||||
@@ -1433,6 +1445,22 @@ namespace AzToolsFramework
|
|||||||
return (outEntities.size() + outInstances.size()) > 0;
|
return (outEntities.size() + outInstances.size()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutLevelInstance(
|
||||||
|
const EntityIdList& entityIds) const
|
||||||
|
{
|
||||||
|
EntityIdList outEntityIds;
|
||||||
|
outEntityIds.reserve(entityIds.size()); // Actual size could be smaller.
|
||||||
|
|
||||||
|
for (const AZ::EntityId& entityId : entityIds)
|
||||||
|
{
|
||||||
|
if (!IsLevelInstanceContainerEntity(entityId))
|
||||||
|
{
|
||||||
|
outEntityIds.emplace_back(entityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outEntityIds;
|
||||||
|
}
|
||||||
|
|
||||||
bool PrefabPublicHandler::EntitiesBelongToSameInstance(const EntityIdList& entityIds) const
|
bool PrefabPublicHandler::EntitiesBelongToSameInstance(const EntityIdList& entityIds) const
|
||||||
{
|
{
|
||||||
if (entityIds.size() <= 1)
|
if (entityIds.size() <= 1)
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ namespace AzToolsFramework
|
|||||||
PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants);
|
PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants);
|
||||||
bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
|
bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
|
||||||
EntityList& outEntities, AZStd::vector<Instance*>& outInstances) const;
|
EntityList& outEntities, AZStd::vector<Instance*>& outInstances) const;
|
||||||
|
EntityIdList GenerateEntityIdListWithoutLevelInstance(const EntityIdList& entityIds) const;
|
||||||
|
|
||||||
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
|
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
|
||||||
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
|
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
|
||||||
@@ -162,9 +163,11 @@ namespace AzToolsFramework
|
|||||||
InstanceOptionalConstReference instance, const AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths);
|
InstanceOptionalConstReference instance, const AZStd::unordered_set<AZ::IO::Path>& templateSourcePaths);
|
||||||
|
|
||||||
static void Internal_HandleContainerOverride(
|
static void Internal_HandleContainerOverride(
|
||||||
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, const PrefabDom& patch, const LinkId linkId);
|
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, const PrefabDom& patch,
|
||||||
|
const LinkId linkId, InstanceOptionalReference parentInstance = AZStd::nullopt);
|
||||||
static void Internal_HandleEntityChange(
|
static void Internal_HandleEntityChange(
|
||||||
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, PrefabDom& beforeState, PrefabDom& afterState);
|
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, PrefabDom& beforeState,
|
||||||
|
PrefabDom& afterState, InstanceOptionalReference instance = AZStd::nullopt);
|
||||||
void Internal_HandleInstanceChange(UndoSystem::URSequencePoint* undoBatch, AZ::Entity* entity, AZ::EntityId beforeParentId, AZ::EntityId afterParentId);
|
void Internal_HandleInstanceChange(UndoSystem::URSequencePoint* undoBatch, AZ::Entity* entity, AZ::EntityId beforeParentId, AZ::EntityId afterParentId);
|
||||||
|
|
||||||
void UpdateLinkPatchesWithNewEntityAliases(
|
void UpdateLinkPatchesWithNewEntityAliases(
|
||||||
|
|||||||
@@ -141,8 +141,10 @@ namespace AzToolsFramework
|
|||||||
return newInstance;
|
return newInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId)
|
void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude)
|
||||||
{
|
{
|
||||||
|
UpdatePrefabInstances(templateId, instanceToExclude);
|
||||||
|
|
||||||
auto templateIdToLinkIdsIterator = m_templateToLinkIdsMap.find(templateId);
|
auto templateIdToLinkIdsIterator = m_templateToLinkIdsMap.find(templateId);
|
||||||
if (templateIdToLinkIdsIterator != m_templateToLinkIdsMap.end())
|
if (templateIdToLinkIdsIterator != m_templateToLinkIdsMap.end())
|
||||||
{
|
{
|
||||||
@@ -153,10 +155,6 @@ namespace AzToolsFramework
|
|||||||
templateIdToLinkIdsIterator->second.end()));
|
templateIdToLinkIdsIterator->second.end()));
|
||||||
UpdateLinkedInstances(linkIdsToUpdateQueue);
|
UpdateLinkedInstances(linkIdsToUpdateQueue);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdatePrefabInstances(templateId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabSystemComponent::UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom)
|
void PrefabSystemComponent::UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom)
|
||||||
@@ -174,9 +172,9 @@ namespace AzToolsFramework
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabSystemComponent::UpdatePrefabInstances(const TemplateId& templateId)
|
void PrefabSystemComponent::UpdatePrefabInstances(const TemplateId& templateId, InstanceOptionalReference instanceToExclude)
|
||||||
{
|
{
|
||||||
m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId);
|
m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, instanceToExclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabSystemComponent::UpdateLinkedInstances(AZStd::queue<LinkIds>& linkIdsQueue)
|
void PrefabSystemComponent::UpdateLinkedInstances(AZStd::queue<LinkIds>& linkIdsQueue)
|
||||||
@@ -250,8 +248,6 @@ namespace AzToolsFramework
|
|||||||
if (targetTemplateIdToLinkIdMap[targetTemplateId].first.empty() &&
|
if (targetTemplateIdToLinkIdMap[targetTemplateId].first.empty() &&
|
||||||
targetTemplateIdToLinkIdMap[targetTemplateId].second)
|
targetTemplateIdToLinkIdMap[targetTemplateId].second)
|
||||||
{
|
{
|
||||||
UpdatePrefabInstances(targetTemplateId);
|
|
||||||
|
|
||||||
auto templateToLinkIter = m_templateToLinkIdsMap.find(targetTemplateId);
|
auto templateToLinkIter = m_templateToLinkIdsMap.find(targetTemplateId);
|
||||||
if (templateToLinkIter != m_templateToLinkIdsMap.end())
|
if (templateToLinkIter != m_templateToLinkIdsMap.end())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -215,14 +215,14 @@ namespace AzToolsFramework
|
|||||||
*/
|
*/
|
||||||
void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) override;
|
void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) override;
|
||||||
|
|
||||||
void PropagateTemplateChanges(TemplateId templateId) override;
|
void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates all Instances owned by a Template.
|
* Updates all Instances owned by a Template.
|
||||||
*
|
*
|
||||||
* @param templateId The id of the Template owning Instances to update.
|
* @param templateId The id of the Template owning Instances to update.
|
||||||
*/
|
*/
|
||||||
void UpdatePrefabInstances(const TemplateId& templateId);
|
void UpdatePrefabInstances(const TemplateId& templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AZ_DISABLE_COPY_MOVE(PrefabSystemComponent);
|
AZ_DISABLE_COPY_MOVE(PrefabSystemComponent);
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
virtual PrefabDom& FindTemplateDom(TemplateId templateId) = 0;
|
virtual PrefabDom& FindTemplateDom(TemplateId templateId) = 0;
|
||||||
virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0;
|
virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0;
|
||||||
virtual void PropagateTemplateChanges(TemplateId templateId) = 0;
|
virtual void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0;
|
||||||
|
|
||||||
virtual AZStd::unique_ptr<Instance> InstantiatePrefab(AZ::IO::PathView filePath) = 0;
|
virtual AZStd::unique_ptr<Instance> InstantiatePrefab(AZ::IO::PathView filePath) = 0;
|
||||||
virtual AZStd::unique_ptr<Instance> InstantiatePrefab(const TemplateId& templateId) = 0;
|
virtual AZStd::unique_ptr<Instance> InstantiatePrefab(const TemplateId& templateId) = 0;
|
||||||
|
|||||||
@@ -70,10 +70,10 @@ namespace AzToolsFramework
|
|||||||
const AZ::EntityId& entityId)
|
const AZ::EntityId& entityId)
|
||||||
{
|
{
|
||||||
//get the entity alias for future undo/redo
|
//get the entity alias for future undo/redo
|
||||||
InstanceOptionalReference instanceOptionalReference = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
auto instanceReference = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||||
AZ_Error("Prefab", instanceOptionalReference,
|
AZ_Error("Prefab", instanceReference,
|
||||||
"Failed to find an owning instance for the entity with id %llu.", static_cast<AZ::u64>(entityId));
|
"Failed to find an owning instance for the entity with id %llu.", static_cast<AZ::u64>(entityId));
|
||||||
Instance& instance = instanceOptionalReference->get();
|
Instance& instance = instanceReference->get();
|
||||||
m_templateId = instance.GetTemplateId();
|
m_templateId = instance.GetTemplateId();
|
||||||
m_entityAlias = (instance.GetEntityAlias(entityId)).value();
|
m_entityAlias = (instance.GetEntityAlias(entityId)).value();
|
||||||
|
|
||||||
@@ -106,6 +106,17 @@ namespace AzToolsFramework
|
|||||||
m_templateId);
|
m_templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrefabUndoEntityUpdate::Redo(InstanceOptionalReference instanceToExclude)
|
||||||
|
{
|
||||||
|
[[maybe_unused]] bool isPatchApplicationSuccessful =
|
||||||
|
m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, instanceToExclude);
|
||||||
|
|
||||||
|
AZ_Error(
|
||||||
|
"Prefab", isPatchApplicationSuccessful,
|
||||||
|
"Applying the patch on the entity with alias '%s' in template with id '%llu' was unsuccessful", m_entityAlias.c_str(),
|
||||||
|
m_templateId);
|
||||||
|
}
|
||||||
|
|
||||||
//PrefabInstanceLinkUndo
|
//PrefabInstanceLinkUndo
|
||||||
PrefabUndoInstanceLink::PrefabUndoInstanceLink(const AZStd::string& undoOperationName)
|
PrefabUndoInstanceLink::PrefabUndoInstanceLink(const AZStd::string& undoOperationName)
|
||||||
: PrefabUndoBase(undoOperationName)
|
: PrefabUndoBase(undoOperationName)
|
||||||
@@ -290,7 +301,12 @@ namespace AzToolsFramework
|
|||||||
UpdateLink(m_linkDomNext);
|
UpdateLink(m_linkDomNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrefabUndoLinkUpdate::UpdateLink(PrefabDom& linkDom)
|
void PrefabUndoLinkUpdate::Redo(InstanceOptionalReference instanceToExclude)
|
||||||
|
{
|
||||||
|
UpdateLink(m_linkDomNext, instanceToExclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrefabUndoLinkUpdate::UpdateLink(PrefabDom& linkDom, InstanceOptionalReference instanceToExclude)
|
||||||
{
|
{
|
||||||
LinkReference link = m_prefabSystemComponentInterface->FindLink(m_linkId);
|
LinkReference link = m_prefabSystemComponentInterface->FindLink(m_linkId);
|
||||||
|
|
||||||
@@ -304,7 +320,7 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
//propagate the link changes
|
//propagate the link changes
|
||||||
link->get().UpdateTarget();
|
link->get().UpdateTarget();
|
||||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(link->get().GetTargetTemplateId());
|
m_prefabSystemComponentInterface->PropagateTemplateChanges(link->get().GetTargetTemplateId(), instanceToExclude);
|
||||||
|
|
||||||
//mark as dirty
|
//mark as dirty
|
||||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(link->get().GetTargetTemplateId(), true);
|
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(link->get().GetTargetTemplateId(), true);
|
||||||
|
|||||||
@@ -71,11 +71,12 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
void Capture(
|
void Capture(
|
||||||
PrefabDom& initialState,
|
PrefabDom& initialState,
|
||||||
PrefabDom& endState,
|
PrefabDom& endState, const AZ::EntityId& entity);
|
||||||
const AZ::EntityId& entity);
|
|
||||||
|
|
||||||
void Undo() override;
|
void Undo() override;
|
||||||
void Redo() override;
|
void Redo() override;
|
||||||
|
//! Overload to allow to apply the change, but prevent instanceToExclude from being refreshed.
|
||||||
|
void Redo(InstanceOptionalReference instanceToExclude);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
|
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
|
||||||
@@ -139,9 +140,11 @@ namespace AzToolsFramework
|
|||||||
|
|
||||||
void Undo() override;
|
void Undo() override;
|
||||||
void Redo() override;
|
void Redo() override;
|
||||||
|
//! Overload to allow to apply the change, but prevent instanceToExclude from being refreshed.
|
||||||
|
void Redo(InstanceOptionalReference instanceToExclude);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateLink(PrefabDom& linkDom);
|
void UpdateLink(PrefabDom& linkDom, InstanceOptionalReference instanceToExclude = AZStd::nullopt);
|
||||||
|
|
||||||
LinkId m_linkId;
|
LinkId m_linkId;
|
||||||
PrefabDom m_linkDomNext; //data for delete/update
|
PrefabDom m_linkDomNext; //data for delete/update
|
||||||
|
|||||||
+20
-31
@@ -2240,42 +2240,31 @@ namespace AzToolsFramework
|
|||||||
RegenerateManipulators();
|
RegenerateManipulators();
|
||||||
});
|
});
|
||||||
|
|
||||||
bool isPrefabSystemEnabled = false;
|
// duplicate selection
|
||||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
AddAction(
|
||||||
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_D) },
|
||||||
|
/*ID_EDIT_CLONE =*/33525, s_duplicateTitle, s_duplicateDesc,
|
||||||
|
[]()
|
||||||
|
{
|
||||||
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||||
|
|
||||||
bool prefabWipFeaturesEnabled = false;
|
// Clear Widget selection - Prevents issues caused by cloning entities while a property in the Reflected Property Editor
|
||||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
// is being edited.
|
||||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
if (QApplication::focusWidget())
|
||||||
|
|
||||||
if (!isPrefabSystemEnabled || (isPrefabSystemEnabled && prefabWipFeaturesEnabled))
|
|
||||||
{
|
|
||||||
// duplicate selection
|
|
||||||
AddAction(
|
|
||||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_D) },
|
|
||||||
/*ID_EDIT_CLONE =*/33525, s_duplicateTitle, s_duplicateDesc,
|
|
||||||
[]()
|
|
||||||
{
|
{
|
||||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
QApplication::focusWidget()->clearFocus();
|
||||||
|
}
|
||||||
|
|
||||||
// Clear Widget selection - Prevents issues caused by cloning entities while a property in the Reflected Property Editor
|
ScopedUndoBatch undoBatch(s_duplicateUndoRedoDesc);
|
||||||
// is being edited.
|
auto selectionCommand = AZStd::make_unique<SelectionCommand>(EntityIdList(), s_duplicateUndoRedoDesc);
|
||||||
if (QApplication::focusWidget())
|
selectionCommand->SetParent(undoBatch.GetUndoBatch());
|
||||||
{
|
selectionCommand.release();
|
||||||
QApplication::focusWidget()->clearFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedUndoBatch undoBatch(s_duplicateUndoRedoDesc);
|
bool handled = false;
|
||||||
auto selectionCommand = AZStd::make_unique<SelectionCommand>(EntityIdList(), s_duplicateUndoRedoDesc);
|
EditorRequestBus::Broadcast(&EditorRequests::CloneSelection, handled);
|
||||||
selectionCommand->SetParent(undoBatch.GetUndoBatch());
|
|
||||||
selectionCommand.release();
|
|
||||||
|
|
||||||
bool handled = false;
|
// selection update handled in AfterEntitySelectionChanged
|
||||||
EditorRequestBus::Broadcast(&EditorRequests::CloneSelection, handled);
|
});
|
||||||
|
|
||||||
// selection update handled in AfterEntitySelectionChanged
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete selection
|
// delete selection
|
||||||
AddAction(
|
AddAction(
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ namespace UnitTest
|
|||||||
|
|
||||||
// Patch the nested prefab to reference an entity in its parent
|
// Patch the nested prefab to reference an entity in its parent
|
||||||
ASSERT_TRUE(m_instanceToTemplateInterface->PatchEntityInTemplate(patch, newEntity->GetId()));
|
ASSERT_TRUE(m_instanceToTemplateInterface->PatchEntityInTemplate(patch, newEntity->GetId()));
|
||||||
|
m_instanceUpdateExecutorInterface->AddTemplateInstancesToQueue(rootInstance->GetTemplateId());
|
||||||
m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
|
m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
|
||||||
|
|
||||||
// Using the aliases we saved grab the updated entities so we can verify the entity reference is still preserved
|
// Using the aliases we saved grab the updated entities so we can verify the entity reference is still preserved
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ set_property(GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR ${CMAKE_CURRENT_BINARY_
|
|||||||
# When using an installed engine, this file will be included by the FindLauncherGenerator.cmake script
|
# When using an installed engine, this file will be included by the FindLauncherGenerator.cmake script
|
||||||
get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
|
get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
|
||||||
foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS)
|
foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS)
|
||||||
|
|
||||||
# Computes the realpath to the project
|
# Computes the realpath to the project
|
||||||
# If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER}
|
# If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER}
|
||||||
# Otherwise the the absolute project_path is returned with symlinks resolved
|
# Otherwise the the absolute project_path is returned with symlinks resolved
|
||||||
@@ -35,6 +36,28 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
|
|||||||
"to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur")
|
"to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Assets
|
||||||
|
################################################################################
|
||||||
|
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||||
|
add_custom_target(${project_name}.Assets
|
||||||
|
COMMENT "Processing ${project_name} assets..."
|
||||||
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>/project_assets.lock
|
||||||
|
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
|
||||||
|
EXEC_COMMAND $<TARGET_FILE:AZ::AssetProcessorBatch>
|
||||||
|
--zeroAnalysisMode
|
||||||
|
--project-path=${project_real_path}
|
||||||
|
--platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
|
||||||
|
)
|
||||||
|
set_target_properties(${project_name}.Assets
|
||||||
|
PROPERTIES
|
||||||
|
EXCLUDE_FROM_ALL TRUE
|
||||||
|
FOLDER ${project_name}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Monolithic game
|
# Monolithic game
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -473,18 +473,8 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe
|
|||||||
// editMenu->addAction(ID_EDIT_PASTE);
|
// editMenu->addAction(ID_EDIT_PASTE);
|
||||||
// editMenu.AddSeparator();
|
// editMenu.AddSeparator();
|
||||||
|
|
||||||
bool isPrefabSystemEnabled = false;
|
// Duplicate
|
||||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
editMenu.AddAction(ID_EDIT_CLONE);
|
||||||
|
|
||||||
bool prefabWipFeaturesEnabled = false;
|
|
||||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
|
||||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
|
||||||
|
|
||||||
if (!isPrefabSystemEnabled || (isPrefabSystemEnabled && prefabWipFeaturesEnabled))
|
|
||||||
{
|
|
||||||
// Duplicate
|
|
||||||
editMenu.AddAction(ID_EDIT_CLONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
editMenu.AddAction(ID_EDIT_DELETE);
|
editMenu.AddAction(ID_EDIT_DELETE);
|
||||||
@@ -912,6 +902,12 @@ QAction* LevelEditorMenuHandler::CreateViewPaneAction(const QtViewPane* view)
|
|||||||
action = new QAction(menuText, this);
|
action = new QAction(menuText, this);
|
||||||
action->setObjectName(view->m_name);
|
action->setObjectName(view->m_name);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
|
|
||||||
|
if (view->m_options.showOnToolsToolbar)
|
||||||
|
{
|
||||||
|
action->setIcon(QIcon(view->m_options.toolbarIcon));
|
||||||
|
}
|
||||||
|
|
||||||
m_actionManager->AddAction(view->m_id, action);
|
m_actionManager->AddAction(view->m_id, action);
|
||||||
|
|
||||||
if (!view->m_options.shortcut.isEmpty())
|
if (!view->m_options.shortcut.isEmpty())
|
||||||
@@ -941,6 +937,11 @@ QAction* LevelEditorMenuHandler::CreateViewPaneMenuItem(
|
|||||||
|
|
||||||
menu->addAction(action);
|
menu->addAction(action);
|
||||||
|
|
||||||
|
if (view->m_options.showOnToolsToolbar)
|
||||||
|
{
|
||||||
|
m_mainWindow->GetToolbarManager()->AddButtonToEditToolbar(action);
|
||||||
|
}
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -470,9 +470,11 @@ void MainWindow::Initialize()
|
|||||||
|
|
||||||
InitToolActionHandlers();
|
InitToolActionHandlers();
|
||||||
|
|
||||||
|
// Initialize toolbars before we setup the menu so that any tools can be added to the toolbar as needed
|
||||||
|
InitToolBars();
|
||||||
|
|
||||||
m_levelEditorMenuHandler->Initialize();
|
m_levelEditorMenuHandler->Initialize();
|
||||||
|
|
||||||
InitToolBars();
|
|
||||||
InitStatusBar();
|
InitStatusBar();
|
||||||
|
|
||||||
AzToolsFramework::SourceControlNotificationBus::Handler::BusConnect();
|
AzToolsFramework::SourceControlNotificationBus::Handler::BusConnect();
|
||||||
|
|||||||
@@ -623,6 +623,20 @@ AmazonToolbar ToolbarManager::GetMiscToolbar() const
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ToolbarManager::AddButtonToEditToolbar(QAction* action)
|
||||||
|
{
|
||||||
|
QString toolbarName = "EditMode";
|
||||||
|
const AmazonToolbar* toolbar = FindToolbar(toolbarName);
|
||||||
|
|
||||||
|
if (toolbar)
|
||||||
|
{
|
||||||
|
if (toolbar->Toolbar())
|
||||||
|
{
|
||||||
|
toolbar->Toolbar()->addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const AmazonToolbar* ToolbarManager::FindDefaultToolbar(const QString& toolbarName) const
|
const AmazonToolbar* ToolbarManager::FindDefaultToolbar(const QString& toolbarName) const
|
||||||
{
|
{
|
||||||
for (const AmazonToolbar& toolbar : m_standardToolbars)
|
for (const AmazonToolbar& toolbar : m_standardToolbars)
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ public:
|
|||||||
AmazonToolbar GetMiscToolbar() const;
|
AmazonToolbar GetMiscToolbar() const;
|
||||||
AmazonToolbar GetPlayConsoleToolbar() const;
|
AmazonToolbar GetPlayConsoleToolbar() const;
|
||||||
|
|
||||||
|
void AddButtonToEditToolbar(QAction* action);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(ToolbarManager);
|
Q_DISABLE_COPY(ToolbarManager);
|
||||||
void SaveToolbars();
|
void SaveToolbars();
|
||||||
|
|||||||
@@ -670,18 +670,11 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con
|
|||||||
AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, menu);
|
AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool prefabWipFeaturesEnabled = false;
|
action = menu->addAction(QObject::tr("Duplicate"));
|
||||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); });
|
||||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
if (selected.size() == 0)
|
||||||
|
|
||||||
if (!prefabSystemEnabled || (prefabSystemEnabled && prefabWipFeaturesEnabled))
|
|
||||||
{
|
{
|
||||||
action = menu->addAction(QObject::tr("Duplicate"));
|
action->setDisabled(true);
|
||||||
QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); });
|
|
||||||
if (selected.size() == 0)
|
|
||||||
{
|
|
||||||
action->setDisabled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prefabSystemEnabled)
|
if (!prefabSystemEnabled)
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
|
||||||
|
|
||||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
|
include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||||
|
|
||||||
include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
if(PAL_TRAIT_AZTESTRUNNER_SUPPORTED)
|
||||||
|
|
||||||
ly_add_target(
|
ly_add_target(
|
||||||
NAME AzTestRunner ${PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE}
|
NAME AzTestRunner ${PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE}
|
||||||
@@ -33,18 +33,22 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
|||||||
AZ::AzFramework
|
AZ::AzFramework
|
||||||
)
|
)
|
||||||
|
|
||||||
ly_add_target(
|
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||||
NAME AzTestRunner.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
|
||||||
NAMESPACE AZ
|
|
||||||
FILES_CMAKE
|
|
||||||
aztestrunner_test_files.cmake
|
|
||||||
BUILD_DEPENDENCIES
|
|
||||||
PRIVATE
|
|
||||||
AZ::AzTest
|
|
||||||
)
|
|
||||||
|
|
||||||
ly_add_googletest(
|
ly_add_target(
|
||||||
NAME AZ::AzTestRunner.Tests
|
NAME AzTestRunner.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||||
)
|
NAMESPACE AZ
|
||||||
|
FILES_CMAKE
|
||||||
|
aztestrunner_test_files.cmake
|
||||||
|
BUILD_DEPENDENCIES
|
||||||
|
PRIVATE
|
||||||
|
AZ::AzTest
|
||||||
|
)
|
||||||
|
|
||||||
|
ly_add_googletest(
|
||||||
|
NAME AZ::AzTestRunner.Tests
|
||||||
|
)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
|
||||||
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE MODULE)
|
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE MODULE)
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
|
||||||
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
|
||||||
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
|
||||||
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
|
||||||
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ namespace O3DE::ProjectManager
|
|||||||
|
|
||||||
void ProjectButton::ReadySetup()
|
void ProjectButton::ReadySetup()
|
||||||
{
|
{
|
||||||
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
|
|
||||||
connect(m_projectImageLabel->GetBuildButton(), &QPushButton::clicked, [this](){ emit BuildProject(m_projectInfo); });
|
connect(m_projectImageLabel->GetBuildButton(), &QPushButton::clicked, [this](){ emit BuildProject(m_projectInfo); });
|
||||||
|
|
||||||
QMenu* menu = new QMenu(this);
|
QMenu* menu = new QMenu(this);
|
||||||
|
|||||||
@@ -135,6 +135,12 @@ namespace AZ
|
|||||||
{
|
{
|
||||||
const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex);
|
const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex);
|
||||||
auto bufViews = groupData.GetBufferViewUnboundedArray(index);
|
auto bufViews = groupData.GetBufferViewUnboundedArray(index);
|
||||||
|
if (bufViews.empty())
|
||||||
|
{
|
||||||
|
// skip empty unbounded arrays
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray);
|
uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray);
|
||||||
descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
|
descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
|
||||||
}
|
}
|
||||||
@@ -144,6 +150,12 @@ namespace AZ
|
|||||||
{
|
{
|
||||||
const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex);
|
const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex);
|
||||||
auto imgViews = groupData.GetImageViewUnboundedArray(index);
|
auto imgViews = groupData.GetImageViewUnboundedArray(index);
|
||||||
|
if (imgViews.empty())
|
||||||
|
{
|
||||||
|
// skip empty unbounded arrays
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray);
|
uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray);
|
||||||
descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type);
|
descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
AZ::AtomCore
|
AZ::AtomCore
|
||||||
AZ::AzTest
|
AZ::AzTest
|
||||||
|
AZ::AzTestShared
|
||||||
AZ::AzFramework
|
AZ::AzFramework
|
||||||
AZ::AzToolsFramework
|
AZ::AzToolsFramework
|
||||||
Legacy::CryCommon
|
Legacy::CryCommon
|
||||||
|
|||||||
@@ -61,12 +61,13 @@ namespace AZ
|
|||||||
//! Important: only to be used in the Editor, it may kick off a job to calculate spatial information.
|
//! Important: only to be used in the Editor, it may kick off a job to calculate spatial information.
|
||||||
//! [GFX TODO][ATOM-4343 Bake mesh spatial during AP processing]
|
//! [GFX TODO][ATOM-4343 Bake mesh spatial during AP processing]
|
||||||
//!
|
//!
|
||||||
//! @param rayStart position where the ray starts
|
//! @param rayStart The starting point of the ray.
|
||||||
//! @param dir direction where the ray ends (does not have to be unit length)
|
//! @param rayDir The direction and length of the ray (magnitude is encoded in the direction).
|
||||||
//! @param distanceFactor if an intersection is detected, this will be set such that distanceFactor * dir.length == distance to intersection
|
//! @param[out] distanceNormalized If an intersection is found, will be set to the normalized distance of the intersection
|
||||||
//! @param normal if an intersection is detected, this will be set to the normal at the point of intersection
|
//! (in the range 0.0-1.0) - to calculate the actual distance, multiply distanceNormalized by the magnitude of rayDir.
|
||||||
//! @return true if the ray intersects the mesh
|
//! @param[out] normal If an intersection is found, will be set to the normal at the point of collision.
|
||||||
bool LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const;
|
//! @return True if the ray intersects the mesh.
|
||||||
|
bool LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const;
|
||||||
|
|
||||||
//! Checks a ray for intersection against this model, where the ray is in a different coordinate space.
|
//! Checks a ray for intersection against this model, where the ray is in a different coordinate space.
|
||||||
//! Important: only to be used in the Editor, it may kick off a job to calculate spatial information.
|
//! Important: only to be used in the Editor, it may kick off a job to calculate spatial information.
|
||||||
@@ -74,13 +75,19 @@ namespace AZ
|
|||||||
//!
|
//!
|
||||||
//! @param modelTransform a transform that puts the model into the ray's coordinate space
|
//! @param modelTransform a transform that puts the model into the ray's coordinate space
|
||||||
//! @param nonUniformScale Non-uniform scale applied in the model's local frame.
|
//! @param nonUniformScale Non-uniform scale applied in the model's local frame.
|
||||||
//! @param rayStart position where the ray starts
|
//! @param rayStart The starting point of the ray.
|
||||||
//! @param dir direction where the ray ends (does not have to be unit length)
|
//! @param rayDir The direction and length of the ray (magnitude is encoded in the direction).
|
||||||
//! @param distanceFactor if an intersection is detected, this will be set such that distanceFactor * dir.length == distance to intersection
|
//! @param[out] distanceNormalized If an intersection is found, will be set to the normalized distance of the intersection
|
||||||
//! @param normal if an intersection is detected, this will be set to the normal at the point of intersection
|
//! (in the range 0.0-1.0) - to calculate the actual distance, multiply distanceNormalized by the magnitude of rayDir.
|
||||||
//! @return true if the ray intersects the mesh
|
//! @param[out] normal If an intersection is found, will be set to the normal at the point of collision.
|
||||||
bool RayIntersection(const AZ::Transform& modelTransform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayStart,
|
//! @return True if the ray intersects the mesh.
|
||||||
const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const;
|
bool RayIntersection(
|
||||||
|
const AZ::Transform& modelTransform,
|
||||||
|
const AZ::Vector3& nonUniformScale,
|
||||||
|
const AZ::Vector3& rayStart,
|
||||||
|
const AZ::Vector3& rayDir,
|
||||||
|
float& distanceNormalized,
|
||||||
|
AZ::Vector3& normal) const;
|
||||||
|
|
||||||
//! Get available UV names from the model and its lods.
|
//! Get available UV names from the model and its lods.
|
||||||
const AZStd::unordered_set<AZ::Name>& GetUvNames() const;
|
const AZStd::unordered_set<AZ::Name>& GetUvNames() const;
|
||||||
|
|||||||
@@ -63,12 +63,14 @@ namespace AZ
|
|||||||
//! Important: only to be used in the Editor, it may kick off a job to calculate spatial information.
|
//! Important: only to be used in the Editor, it may kick off a job to calculate spatial information.
|
||||||
//! [GFX TODO][ATOM-4343 Bake mesh spatial information during AP processing]
|
//! [GFX TODO][ATOM-4343 Bake mesh spatial information during AP processing]
|
||||||
//!
|
//!
|
||||||
//! @param rayStart position where the ray starts
|
//! @param rayStart The starting point of the ray.
|
||||||
//! @param dir direction where the ray ends (does not have to be unit length)
|
//! @param rayDir The direction and length of the ray (magnitude is encoded in the direction).
|
||||||
//! @param distance if an intersection is detected, this will be set such that distanceFactor * dir.length == distance to intersection
|
//! @param[out] distanceNormalized If an intersection is found, will be set to the normalized distance of the intersection
|
||||||
//! @param normal if an intersection is detected, this will be set to the normal at the point of collision
|
//! (in the range 0.0-1.0) - to calculate the actual distance, multiply distanceNormalized by the magnitude of rayDir.
|
||||||
//! @return true if the ray intersects the mesh
|
//! @param[out] normal If an intersection is found, will be set to the normal at the point of collision.
|
||||||
virtual bool LocalRayIntersectionAgainstModel(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const;
|
//! @return True if the ray intersects the mesh.
|
||||||
|
virtual bool LocalRayIntersectionAgainstModel(
|
||||||
|
const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetReady();
|
void SetReady();
|
||||||
@@ -79,9 +81,15 @@ namespace AZ
|
|||||||
|
|
||||||
// mutable method
|
// mutable method
|
||||||
void BuildKdTree() const;
|
void BuildKdTree() const;
|
||||||
bool BruteForceRayIntersect(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const;
|
bool BruteForceRayIntersect(
|
||||||
|
const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const;
|
||||||
|
|
||||||
bool LocalRayIntersectionAgainstMesh(const ModelLodAsset::Mesh& mesh, const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const;
|
bool LocalRayIntersectionAgainstMesh(
|
||||||
|
const ModelLodAsset::Mesh& mesh,
|
||||||
|
const AZ::Vector3& rayStart,
|
||||||
|
const AZ::Vector3& rayDir,
|
||||||
|
float& distanceNormalized,
|
||||||
|
AZ::Vector3& normal) const;
|
||||||
|
|
||||||
// Various model information used in raycasting
|
// Various model information used in raycasting
|
||||||
AZ::Name m_positionName{ "POSITION" };
|
AZ::Name m_positionName{ "POSITION" };
|
||||||
|
|||||||
@@ -137,12 +137,12 @@ namespace AZ
|
|||||||
return m_modelAsset;
|
return m_modelAsset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const
|
bool Model::LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
|
||||||
{
|
{
|
||||||
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
|
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
|
||||||
float start;
|
float start;
|
||||||
float end;
|
float end;
|
||||||
const int result = Intersect::IntersectRayAABB2(rayStart, dir.GetReciprocal(), m_aabb, start, end);
|
const int result = Intersect::IntersectRayAABB2(rayStart, rayDir.GetReciprocal(), m_aabb, start, end);
|
||||||
if (Intersect::ISECT_RAY_AABB_NONE != result)
|
if (Intersect::ISECT_RAY_AABB_NONE != result)
|
||||||
{
|
{
|
||||||
if (ModelAsset* modelAssetPtr = m_modelAsset.Get())
|
if (ModelAsset* modelAssetPtr = m_modelAsset.Get())
|
||||||
@@ -151,7 +151,7 @@ namespace AZ
|
|||||||
AZ::Debug::Timer timer;
|
AZ::Debug::Timer timer;
|
||||||
timer.Stamp();
|
timer.Stamp();
|
||||||
#endif
|
#endif
|
||||||
const bool hit = modelAssetPtr->LocalRayIntersectionAgainstModel(rayStart, dir, distance, normal);
|
const bool hit = modelAssetPtr->LocalRayIntersectionAgainstModel(rayStart, rayDir, distanceNormalized, normal);
|
||||||
#if defined(AZ_RPI_PROFILE_RAYCASTING_AGAINST_MODELS)
|
#if defined(AZ_RPI_PROFILE_RAYCASTING_AGAINST_MODELS)
|
||||||
if (hit)
|
if (hit)
|
||||||
{
|
{
|
||||||
@@ -166,8 +166,12 @@ namespace AZ
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Model::RayIntersection(
|
bool Model::RayIntersection(
|
||||||
const AZ::Transform& modelTransform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayStart, const AZ::Vector3& dir,
|
const AZ::Transform& modelTransform,
|
||||||
float& distanceFactor, AZ::Vector3& normal) const
|
const AZ::Vector3& nonUniformScale,
|
||||||
|
const AZ::Vector3& rayStart,
|
||||||
|
const AZ::Vector3& rayDir,
|
||||||
|
float& distanceNormalized,
|
||||||
|
AZ::Vector3& normal) const
|
||||||
{
|
{
|
||||||
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
|
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
|
||||||
const AZ::Vector3 clampedScale = nonUniformScale.GetMax(AZ::Vector3(AZ::MinTransformScale));
|
const AZ::Vector3 clampedScale = nonUniformScale.GetMax(AZ::Vector3(AZ::MinTransformScale));
|
||||||
@@ -175,12 +179,13 @@ namespace AZ
|
|||||||
const AZ::Transform inverseTM = modelTransform.GetInverse();
|
const AZ::Transform inverseTM = modelTransform.GetInverse();
|
||||||
const AZ::Vector3 raySrcLocal = inverseTM.TransformPoint(rayStart) / clampedScale;
|
const AZ::Vector3 raySrcLocal = inverseTM.TransformPoint(rayStart) / clampedScale;
|
||||||
|
|
||||||
// Instead of just rotating 'dir' we need it to be scaled too, so that 'distanceFactor' will be in the target units rather than object local units.
|
// Instead of just rotating 'rayDir' we need it to be scaled too, so that 'distanceNormalized' will be in the target units rather
|
||||||
const AZ::Vector3 rayDest = rayStart + dir;
|
// than object local units.
|
||||||
|
const AZ::Vector3 rayDest = rayStart + rayDir;
|
||||||
const AZ::Vector3 rayDestLocal = inverseTM.TransformPoint(rayDest) / clampedScale;
|
const AZ::Vector3 rayDestLocal = inverseTM.TransformPoint(rayDest) / clampedScale;
|
||||||
const AZ::Vector3 rayDirLocal = rayDestLocal - raySrcLocal;
|
const AZ::Vector3 rayDirLocal = rayDestLocal - raySrcLocal;
|
||||||
|
|
||||||
bool result = LocalRayIntersection(raySrcLocal, rayDirLocal, distanceFactor, normal);
|
const bool result = LocalRayIntersection(raySrcLocal, rayDirLocal, distanceNormalized, normal);
|
||||||
normal = (normal * clampedScale).GetNormalized();
|
normal = (normal * clampedScale).GetNormalized();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <AzCore/Debug/EventTrace.h>
|
#include <AzCore/Debug/EventTrace.h>
|
||||||
#include <AzCore/Jobs/JobFunction.h>
|
#include <AzCore/Jobs/JobFunction.h>
|
||||||
#include <AzCore/Math/IntersectSegment.h>
|
#include <AzCore/Math/IntersectSegment.h>
|
||||||
|
#include <AzCore/std/limits.h>
|
||||||
|
|
||||||
#include <AzCore/RTTI/ReflectContext.h>
|
#include <AzCore/RTTI/ReflectContext.h>
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
@@ -75,7 +76,8 @@ namespace AZ
|
|||||||
m_status = Data::AssetData::AssetStatus::Ready;
|
m_status = Data::AssetData::AssetStatus::Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelAsset::LocalRayIntersectionAgainstModel(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const
|
bool ModelAsset::LocalRayIntersectionAgainstModel(
|
||||||
|
const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
|
||||||
{
|
{
|
||||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ namespace AZ
|
|||||||
m_modelTriangleCount = CalculateTriangleCount();
|
m_modelTriangleCount = CalculateTriangleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the total vertex count for this model and skip kdtree if the model is simple enough
|
// check the total vertex count for this model and skip kd-tree if the model is simple enough
|
||||||
if (*m_modelTriangleCount > s_minimumModelTriangleCountToOptimize)
|
if (*m_modelTriangleCount > s_minimumModelTriangleCountToOptimize)
|
||||||
{
|
{
|
||||||
if (!m_kdTree)
|
if (!m_kdTree)
|
||||||
@@ -97,11 +99,11 @@ namespace AZ
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return m_kdTree->RayIntersection(rayStart, dir, distance, normal);
|
return m_kdTree->RayIntersection(rayStart, rayDir, distanceNormalized, normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BruteForceRayIntersect(rayStart, dir, distance, normal);
|
return BruteForceRayIntersect(rayStart, rayDir, distanceNormalized, normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelAsset::BuildKdTree() const
|
void ModelAsset::BuildKdTree() const
|
||||||
@@ -136,7 +138,8 @@ namespace AZ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelAsset::BruteForceRayIntersect(const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const
|
bool ModelAsset::BruteForceRayIntersect(
|
||||||
|
const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
|
||||||
{
|
{
|
||||||
// brute force - check every triangle
|
// brute force - check every triangle
|
||||||
if (GetLodAssets().empty() == false)
|
if (GetLodAssets().empty() == false)
|
||||||
@@ -144,27 +147,27 @@ namespace AZ
|
|||||||
// intersect against the highest level of detail
|
// intersect against the highest level of detail
|
||||||
if (ModelLodAsset* loadAssetPtr = GetLodAssets()[0].Get())
|
if (ModelLodAsset* loadAssetPtr = GetLodAssets()[0].Get())
|
||||||
{
|
{
|
||||||
float shortestDistance = std::numeric_limits<float>::max();
|
|
||||||
bool anyHit = false;
|
bool anyHit = false;
|
||||||
|
|
||||||
AZ::Vector3 intersectionNormal;
|
AZ::Vector3 intersectionNormal;
|
||||||
|
float shortestDistanceNormalized = AZStd::numeric_limits<float>::max();
|
||||||
for (const ModelLodAsset::Mesh& mesh : loadAssetPtr->GetMeshes())
|
for (const ModelLodAsset::Mesh& mesh : loadAssetPtr->GetMeshes())
|
||||||
{
|
{
|
||||||
if (LocalRayIntersectionAgainstMesh(mesh, rayStart, dir, distance, intersectionNormal))
|
float currentDistanceNormalized;
|
||||||
|
if (LocalRayIntersectionAgainstMesh(mesh, rayStart, rayDir, currentDistanceNormalized, intersectionNormal))
|
||||||
{
|
{
|
||||||
anyHit = true;
|
anyHit = true;
|
||||||
if (distance < shortestDistance)
|
|
||||||
|
if (currentDistanceNormalized < shortestDistanceNormalized)
|
||||||
{
|
{
|
||||||
normal = intersectionNormal;
|
normal = intersectionNormal;
|
||||||
shortestDistance = distance;
|
shortestDistanceNormalized = currentDistanceNormalized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyHit)
|
if (anyHit)
|
||||||
{
|
{
|
||||||
distance = shortestDistance;
|
distanceNormalized = shortestDistanceNormalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
return anyHit;
|
return anyHit;
|
||||||
@@ -174,7 +177,12 @@ namespace AZ
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelAsset::LocalRayIntersectionAgainstMesh(const ModelLodAsset::Mesh& mesh, const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distance, AZ::Vector3& normal) const
|
bool ModelAsset::LocalRayIntersectionAgainstMesh(
|
||||||
|
const ModelLodAsset::Mesh& mesh,
|
||||||
|
const AZ::Vector3& rayStart,
|
||||||
|
const AZ::Vector3& rayDir,
|
||||||
|
float& distanceNormalized,
|
||||||
|
AZ::Vector3& normal) const
|
||||||
{
|
{
|
||||||
const BufferAssetView& indexBufferView = mesh.GetIndexBufferAssetView();
|
const BufferAssetView& indexBufferView = mesh.GetIndexBufferAssetView();
|
||||||
const AZStd::array_view<ModelLodAsset::Mesh::StreamBufferInfo>& streamBufferList = mesh.GetStreamBufferInfoList();
|
const AZStd::array_view<ModelLodAsset::Mesh::StreamBufferInfo>& streamBufferList = mesh.GetStreamBufferInfoList();
|
||||||
@@ -217,14 +225,13 @@ namespace AZ
|
|||||||
AZStd::array_view<uint8_t> indexRawBuffer = indexAssetViewPtr->GetBuffer();
|
AZStd::array_view<uint8_t> indexRawBuffer = indexAssetViewPtr->GetBuffer();
|
||||||
RHI::BufferViewDescriptor indexRawDesc = indexAssetViewPtr->GetBufferViewDescriptor();
|
RHI::BufferViewDescriptor indexRawDesc = indexAssetViewPtr->GetBufferViewDescriptor();
|
||||||
|
|
||||||
float closestNormalizedDistance = 1.f;
|
|
||||||
bool anyHit = false;
|
bool anyHit = false;
|
||||||
|
|
||||||
const AZ::Vector3 rayEnd = rayStart + dir * distance;
|
const AZ::Vector3 rayEnd = rayStart + rayDir;
|
||||||
AZ::Vector3 a, b, c;
|
AZ::Vector3 a, b, c;
|
||||||
AZ::Vector3 intersectionNormal;
|
AZ::Vector3 intersectionNormal;
|
||||||
float normalizedDistance = 1.f;
|
|
||||||
|
|
||||||
|
float shortestDistanceNormalized = AZStd::numeric_limits<float>::max();
|
||||||
const AZ::u32* indexPtr = reinterpret_cast<const AZ::u32*>(indexRawBuffer.data());
|
const AZ::u32* indexPtr = reinterpret_cast<const AZ::u32*>(indexRawBuffer.data());
|
||||||
for (uint32_t indexIter = 0; indexIter <= indexRawDesc.m_elementCount - 3; indexIter += 3, indexPtr += 3)
|
for (uint32_t indexIter = 0; indexIter <= indexRawDesc.m_elementCount - 3; indexIter += 3, indexPtr += 3)
|
||||||
{
|
{
|
||||||
@@ -247,20 +254,22 @@ namespace AZ
|
|||||||
p = reinterpret_cast<const float*>(&positionRawBuffer[index2 * positionElementSize]);
|
p = reinterpret_cast<const float*>(&positionRawBuffer[index2 * positionElementSize]);
|
||||||
c.Set(const_cast<float*>(p));
|
c.Set(const_cast<float*>(p));
|
||||||
|
|
||||||
if (AZ::Intersect::IntersectSegmentTriangleCCW(rayStart, rayEnd, a, b, c, intersectionNormal, normalizedDistance))
|
float currentDistanceNormalized;
|
||||||
|
if (AZ::Intersect::IntersectSegmentTriangleCCW(rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized))
|
||||||
{
|
{
|
||||||
if (normalizedDistance < closestNormalizedDistance)
|
anyHit = true;
|
||||||
|
|
||||||
|
if (currentDistanceNormalized < shortestDistanceNormalized)
|
||||||
{
|
{
|
||||||
normal = intersectionNormal;
|
normal = intersectionNormal;
|
||||||
closestNormalizedDistance = normalizedDistance;
|
shortestDistanceNormalized = currentDistanceNormalized;
|
||||||
}
|
}
|
||||||
anyHit = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyHit)
|
if (anyHit)
|
||||||
{
|
{
|
||||||
distance = closestNormalizedDistance * distance;
|
distanceNormalized = shortestDistanceNormalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
return anyHit;
|
return anyHit;
|
||||||
|
|||||||
@@ -208,10 +208,10 @@ namespace AZ
|
|||||||
bool ModelKdTree::RayIntersection(
|
bool ModelKdTree::RayIntersection(
|
||||||
const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
|
const AZ::Vector3& raySrc, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
|
||||||
{
|
{
|
||||||
float closestDistanceNormalized = AZStd::numeric_limits<float>::max();
|
float shortestDistanceNormalized = AZStd::numeric_limits<float>::max();
|
||||||
if (RayIntersectionRecursively(m_pRootNode.get(), raySrc, rayDir, closestDistanceNormalized, normal))
|
if (RayIntersectionRecursively(m_pRootNode.get(), raySrc, rayDir, shortestDistanceNormalized, normal))
|
||||||
{
|
{
|
||||||
distanceNormalized = closestDistanceNormalized;
|
distanceNormalized = shortestDistanceNormalized;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <AzCore/std/limits.h>
|
#include <AzCore/std/limits.h>
|
||||||
#include <AzCore/Component/Entity.h>
|
#include <AzCore/Component/Entity.h>
|
||||||
|
|
||||||
|
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||||
#include <AzTest/AzTest.h>
|
#include <AzTest/AzTest.h>
|
||||||
|
|
||||||
#include <Common/RPITestFixture.h>
|
#include <Common/RPITestFixture.h>
|
||||||
@@ -955,6 +956,20 @@ namespace UnitTest
|
|||||||
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x70000F51);
|
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x70000F51);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// +----+
|
||||||
|
// / /|
|
||||||
|
// +----+ |
|
||||||
|
// | | +
|
||||||
|
// | |/
|
||||||
|
// +----+
|
||||||
|
//
|
||||||
|
static constexpr AZStd::array CubePositions = { -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
|
||||||
|
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f };
|
||||||
|
static constexpr AZStd::array CubeIndices = {
|
||||||
|
uint32_t{ 0 }, 2, 1, 1, 2, 3, 4, 5, 6, 5, 7, 6, 0, 4, 2, 4, 6, 2, 1, 3, 5, 5, 3, 7, 0, 1, 4, 4, 1, 5, 2, 6, 3, 6, 7, 3,
|
||||||
|
};
|
||||||
|
|
||||||
// This class creates a Model with one LOD, whose mesh contains 2 planes. Plane 1 is in the XY plane at Z=-0.5, and
|
// This class creates a Model with one LOD, whose mesh contains 2 planes. Plane 1 is in the XY plane at Z=-0.5, and
|
||||||
// plane 2 is in the XY plane at Z=0.5. The two planes each have 9 quads which have been triangulated. It only has
|
// plane 2 is in the XY plane at Z=0.5. The two planes each have 9 quads which have been triangulated. It only has
|
||||||
// a position and index buffer.
|
// a position and index buffer.
|
||||||
@@ -972,52 +987,75 @@ namespace UnitTest
|
|||||||
// *---*---*---*
|
// *---*---*---*
|
||||||
// \ / \ / \ / \
|
// \ / \ / \ / \
|
||||||
// *---*---*---*
|
// *---*---*---*
|
||||||
|
static constexpr AZStd::array TwoSeparatedPlanesPositions{
|
||||||
|
-1.0f, -0.333f, -0.5f, -0.333f, -1.0f, -0.5f, -0.333f, -0.333f, -0.5f, 0.333f, -0.333f, -0.5f, 1.0f, -1.0f, -0.5f,
|
||||||
|
1.0f, -0.333f, -0.5f, 0.333f, -1.0f, -0.5f, 0.333f, 1.0f, -0.5f, 1.0f, 0.333f, -0.5f, 1.0f, 1.0f, -0.5f,
|
||||||
|
0.333f, 0.333f, -0.5f, -0.333f, 1.0f, -0.5f, -0.333f, 0.333f, -0.5f, -1.0f, 1.0f, -0.5f, -1.0f, 0.333f, -0.5f,
|
||||||
|
-1.0f, -0.333f, 0.5f, -0.333f, -1.0f, 0.5f, -0.333f, -0.333f, 0.5f, 0.333f, -0.333f, 0.5f, 1.0f, -1.0f, 0.5f,
|
||||||
|
1.0f, -0.333f, 0.5f, -0.333f, -0.333f, 0.5f, 0.333f, -1.0f, 0.5f, 0.333f, -0.333f, 0.5f, 0.333f, 1.0f, 0.5f,
|
||||||
|
1.0f, 0.333f, 0.5f, 1.0f, 1.0f, 0.5f, 0.333f, 0.333f, 0.5f, 1.0f, -0.333f, 0.5f, -0.333f, 1.0f, 0.5f,
|
||||||
|
-0.333f, 0.333f, 0.5f, 0.333f, -0.333f, 0.5f, 0.333f, 0.333f, 0.5f, -1.0f, 1.0f, 0.5f, -0.333f, 0.333f, 0.5f,
|
||||||
|
-1.0f, 0.333f, 0.5f, -1.0f, -1.0f, -0.5f, -1.0f, -1.0f, 0.5f, 0.333f, -0.333f, 0.5f, 0.333f, -1.0f, 0.5f,
|
||||||
|
1.0f, -1.0f, 0.5f, 0.333f, -1.0f, 0.5f, 0.333f, 0.333f, 0.5f, 0.333f, -0.333f, 0.5f, 1.0f, -0.333f, 0.5f,
|
||||||
|
-0.333f, 0.333f, 0.5f, -0.333f, -0.333f, 0.5f, 0.333f, -0.333f, 0.5f,
|
||||||
|
};
|
||||||
|
// clang-format off
|
||||||
|
static constexpr AZStd::array TwoSeparatedPlanesIndices{
|
||||||
|
uint32_t{ 0 }, 1, 2, 3, 4, 5, 2, 6, 3, 7, 8, 9, 10, 5, 8, 11, 10, 7, 12, 3, 10, 13, 12, 11, 14, 2, 12,
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 25, 29, 27, 24, 30, 31, 32, 33, 34, 29, 35, 17, 34,
|
||||||
|
0, 36, 1, 3, 6, 4, 2, 1, 6, 7, 10, 8, 10, 3, 5, 11, 12, 10, 12, 2, 3, 13, 14, 12, 14, 0, 2,
|
||||||
|
15, 37, 16, 38, 39, 40, 17, 16, 41, 24, 27, 25, 42, 43, 44, 29, 34, 27, 45, 46, 47, 33, 35, 34, 35, 15, 17,
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Ensure that the index buffer references all the positions in the position buffer
|
||||||
|
static constexpr inline auto minmaxElement = AZStd::minmax_element(begin(TwoSeparatedPlanesIndices), end(TwoSeparatedPlanesIndices));
|
||||||
|
static_assert(*minmaxElement.second == (TwoSeparatedPlanesPositions.size() / 3) - 1);
|
||||||
|
|
||||||
template<class x> class TD;
|
template<class x> class TD;
|
||||||
class TwoSeparatedPlanesMesh
|
class TestMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TwoSeparatedPlanesMesh()
|
TestMesh(const float* positions, size_t positionCount, const uint32_t* indices, size_t indicesCount)
|
||||||
{
|
{
|
||||||
using namespace AZ;
|
AZ::RPI::ModelLodAssetCreator lodCreator;
|
||||||
|
lodCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
|
||||||
RPI::ModelLodAssetCreator lodCreator;
|
|
||||||
lodCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()));
|
|
||||||
|
|
||||||
lodCreator.BeginMesh();
|
lodCreator.BeginMesh();
|
||||||
lodCreator.SetMeshAabb(Aabb::CreateFromMinMax({-1.0f, -1.0f, -0.5f}, {1.0f, 1.0f, 0.5f}));
|
lodCreator.SetMeshAabb(AZ::Aabb::CreateFromMinMax({-1.0f, -1.0f, -0.5f}, {1.0f, 1.0f, 0.5f}));
|
||||||
lodCreator.SetMeshMaterialAsset(
|
lodCreator.SetMeshMaterialAsset(
|
||||||
AZ::Data::Asset<AZ::RPI::MaterialAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0),
|
AZ::Data::Asset<AZ::RPI::MaterialAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0),
|
||||||
AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid(), "")
|
AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid(), "")
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
AZ::Data::Asset<AZ::RPI::BufferAsset> indexBuffer = BuildTestBuffer(s_indexes.size(), sizeof(uint32_t));
|
AZ::Data::Asset<AZ::RPI::BufferAsset> indexBuffer = BuildTestBuffer(indicesCount, sizeof(uint32_t));
|
||||||
AZStd::copy(s_indexes.begin(), s_indexes.end(), reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(indexBuffer->GetBuffer().data())));
|
AZStd::copy(indices, indices + indicesCount, reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(indexBuffer->GetBuffer().data())));
|
||||||
lodCreator.SetMeshIndexBuffer({
|
lodCreator.SetMeshIndexBuffer({
|
||||||
indexBuffer,
|
indexBuffer,
|
||||||
RHI::BufferViewDescriptor::CreateStructured(0, s_indexes.size(), sizeof(uint32_t))
|
AZ::RHI::BufferViewDescriptor::CreateStructured(0, indicesCount, sizeof(uint32_t))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
AZ::Data::Asset<AZ::RPI::BufferAsset> positionBuffer = BuildTestBuffer(s_positions.size() / 3, sizeof(float) * 3);
|
AZ::Data::Asset<AZ::RPI::BufferAsset> positionBuffer = BuildTestBuffer(positionCount / 3, sizeof(float) * 3);
|
||||||
AZStd::copy(s_positions.begin(), s_positions.end(), reinterpret_cast<float*>(const_cast<uint8_t*>(positionBuffer->GetBuffer().data())));
|
AZStd::copy(positions, positions + positionCount, reinterpret_cast<float*>(const_cast<uint8_t*>(positionBuffer->GetBuffer().data())));
|
||||||
lodCreator.AddMeshStreamBuffer(
|
lodCreator.AddMeshStreamBuffer(
|
||||||
AZ::RHI::ShaderSemantic(AZ::Name("POSITION")),
|
AZ::RHI::ShaderSemantic(AZ::Name("POSITION")),
|
||||||
AZ::Name(),
|
AZ::Name(),
|
||||||
{
|
{
|
||||||
positionBuffer,
|
positionBuffer,
|
||||||
RHI::BufferViewDescriptor::CreateStructured(0, s_positions.size() / 3, sizeof(float) * 3)
|
AZ::RHI::BufferViewDescriptor::CreateStructured(0, positionCount / 3, sizeof(float) * 3)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
lodCreator.EndMesh();
|
lodCreator.EndMesh();
|
||||||
|
|
||||||
Data::Asset<RPI::ModelLodAsset> lodAsset;
|
AZ::Data::Asset<AZ::RPI::ModelLodAsset> lodAsset;
|
||||||
lodCreator.End(lodAsset);
|
lodCreator.End(lodAsset);
|
||||||
|
|
||||||
RPI::ModelAssetCreator modelCreator;
|
AZ::RPI::ModelAssetCreator modelCreator;
|
||||||
modelCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()));
|
modelCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
|
||||||
modelCreator.SetName("TestModel");
|
modelCreator.SetName("TestModel");
|
||||||
modelCreator.AddLodAsset(AZStd::move(lodAsset));
|
modelCreator.AddLodAsset(AZStd::move(lodAsset));
|
||||||
modelCreator.End(m_modelAsset);
|
modelCreator.End(m_modelAsset);
|
||||||
@@ -1030,40 +1068,20 @@ namespace UnitTest
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
AZ::Data::Asset<AZ::RPI::ModelAsset> m_modelAsset;
|
AZ::Data::Asset<AZ::RPI::ModelAsset> m_modelAsset;
|
||||||
|
|
||||||
static constexpr AZStd::array s_positions{
|
|
||||||
-1.0f, -0.333f, -0.5f, -0.333f, -1.0f, -0.5f, -0.333f, -0.333f, -0.5f, 0.333f, -0.333f, -0.5f, 1.0f, -1.0f, -0.5f,
|
|
||||||
1.0f, -0.333f, -0.5f, 0.333f, -1.0f, -0.5f, 0.333f, 1.0f, -0.5f, 1.0f, 0.333f, -0.5f, 1.0f, 1.0f, -0.5f,
|
|
||||||
0.333f, 0.333f, -0.5f, -0.333f, 1.0f, -0.5f, -0.333f, 0.333f, -0.5f, -1.0f, 1.0f, -0.5f, -1.0f, 0.333f, -0.5f,
|
|
||||||
-1.0f, -0.333f, 0.5f, -0.333f, -1.0f, 0.5f, -0.333f, -0.333f, 0.5f, 0.333f, -0.333f, 0.5f, 1.0f, -1.0f, 0.5f,
|
|
||||||
1.0f, -0.333f, 0.5f, -0.333f, -0.333f, 0.5f, 0.333f, -1.0f, 0.5f, 0.333f, -0.333f, 0.5f, 0.333f, 1.0f, 0.5f,
|
|
||||||
1.0f, 0.333f, 0.5f, 1.0f, 1.0f, 0.5f, 0.333f, 0.333f, 0.5f, 1.0f, -0.333f, 0.5f, -0.333f, 1.0f, 0.5f,
|
|
||||||
-0.333f, 0.333f, 0.5f, 0.333f, -0.333f, 0.5f, 0.333f, 0.333f, 0.5f, -1.0f, 1.0f, 0.5f, -0.333f, 0.333f, 0.5f,
|
|
||||||
-1.0f, 0.333f, 0.5f, -1.0f, -1.0f, -0.5f, -1.0f, -1.0f, 0.5f, 0.333f, -0.333f, 0.5f, 0.333f, -1.0f, 0.5f,
|
|
||||||
1.0f, -1.0f, 0.5f, 0.333f, -1.0f, 0.5f, 0.333f, 0.333f, 0.5f, 0.333f, -0.333f, 0.5f, 1.0f, -0.333f, 0.5f,
|
|
||||||
-0.333f, 0.333f, 0.5f, -0.333f, -0.333f, 0.5f, 0.333f, -0.333f, 0.5f,
|
|
||||||
};
|
|
||||||
static constexpr AZStd::array s_indexes{
|
|
||||||
uint32_t{0}, 1, 2, 3, 4, 5, 2, 6, 3, 7, 8, 9, 10, 5, 8, 11, 10, 7, 12, 3, 10, 13, 12, 11, 14, 2, 12,
|
|
||||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 25, 29, 27, 24, 30, 31, 32, 33, 34, 29, 35, 17, 34,
|
|
||||||
0, 36, 1, 3, 6, 4, 2, 1, 6, 7, 10, 8, 10, 3, 5, 11, 12, 10, 12, 2, 3, 13, 14, 12, 14, 0, 2,
|
|
||||||
15, 37, 16, 38, 39, 40, 17, 16, 41, 24, 27, 25, 42, 43, 44, 29, 34, 27, 45, 46, 47, 33, 35, 34, 35, 15, 17,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ensure that the index buffer references all the positions in the position buffer
|
|
||||||
static constexpr inline auto minmaxElement = AZStd::minmax_element(begin(s_indexes), end(s_indexes));
|
|
||||||
static_assert(*minmaxElement.second == (s_positions.size() / 3) - 1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KdTreeIntersectParams
|
struct IntersectParams
|
||||||
{
|
{
|
||||||
float xpos;
|
float xpos;
|
||||||
float ypos;
|
float ypos;
|
||||||
float zpos;
|
float zpos;
|
||||||
|
float xdir;
|
||||||
|
float ydir;
|
||||||
|
float zdir;
|
||||||
float expectedDistance;
|
float expectedDistance;
|
||||||
bool expectedShouldIntersect;
|
bool expectedShouldIntersect;
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const KdTreeIntersectParams& param)
|
friend std::ostream& operator<<(std::ostream& os, const IntersectParams& param)
|
||||||
{
|
{
|
||||||
return os
|
return os
|
||||||
<< "xpos:" << param.xpos
|
<< "xpos:" << param.xpos
|
||||||
@@ -1076,13 +1094,15 @@ namespace UnitTest
|
|||||||
|
|
||||||
class KdTreeIntersectsParameterizedFixture
|
class KdTreeIntersectsParameterizedFixture
|
||||||
: public ModelTests
|
: public ModelTests
|
||||||
, public ::testing::WithParamInterface<KdTreeIntersectParams>
|
, public ::testing::WithParamInterface<IntersectParams>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(KdTreeIntersectsParameterizedFixture, KdTreeIntersects)
|
TEST_P(KdTreeIntersectsParameterizedFixture, KdTreeIntersects)
|
||||||
{
|
{
|
||||||
TwoSeparatedPlanesMesh mesh;
|
TestMesh mesh(
|
||||||
|
TwoSeparatedPlanesPositions.data(), TwoSeparatedPlanesPositions.size(), TwoSeparatedPlanesIndices.data(),
|
||||||
|
TwoSeparatedPlanesIndices.size());
|
||||||
|
|
||||||
AZ::RPI::ModelKdTree kdTree;
|
AZ::RPI::ModelKdTree kdTree;
|
||||||
ASSERT_TRUE(kdTree.Build(mesh.GetModel().Get()));
|
ASSERT_TRUE(kdTree.Build(mesh.GetModel().Get()));
|
||||||
@@ -1092,38 +1112,40 @@ namespace UnitTest
|
|||||||
|
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
kdTree.RayIntersection(
|
kdTree.RayIntersection(
|
||||||
AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos), AZ::Vector3::CreateAxisZ(-1.0f), distance, normal),
|
AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos),
|
||||||
|
AZ::Vector3(GetParam().xdir, GetParam().ydir, GetParam().zdir), distance, normal),
|
||||||
testing::Eq(GetParam().expectedShouldIntersect));
|
testing::Eq(GetParam().expectedShouldIntersect));
|
||||||
EXPECT_THAT(distance, testing::FloatEq(GetParam().expectedDistance));
|
EXPECT_THAT(distance, testing::FloatEq(GetParam().expectedDistance));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr inline AZStd::array<KdTreeIntersectParams, 21> intersectTestData{
|
static constexpr AZStd::array KdTreeIntersectTestData{
|
||||||
KdTreeIntersectParams{ -0.1f, 0.0f, 1.0f, 0.5f, true },
|
IntersectParams{ -0.1f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{ 0.0f, 0.0f, 1.0f, 0.5f, true },
|
IntersectParams{ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{ 0.1f, 0.0f, 1.0f, 0.5f, true },
|
IntersectParams{ 0.1f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
|
|
||||||
// Test the center of each triangle
|
// Test the center of each triangle
|
||||||
KdTreeIntersectParams{-0.111f, -0.111f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.111f, -0.111f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{-0.111f, -0.778f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.111f, -0.778f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{-0.111f, 0.555f, 1.0f, 0.5f, true}, // Should intersect triangle with indices {29, 34, 27} and {11, 12, 10}
|
IntersectParams{ -0.111f, 0.555f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f,
|
||||||
KdTreeIntersectParams{-0.555f, -0.555f, 1.0f, 0.5f, true},
|
true }, // Should intersect triangle with indices {29, 34, 27} and {11, 12, 10}
|
||||||
KdTreeIntersectParams{-0.555f, 0.111f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.555f, -0.555f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{-0.555f, 0.778f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.555f, 0.111f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{-0.778f, -0.111f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.555f, 0.778f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{-0.778f, -0.778f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.778f, -0.111f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{-0.778f, 0.555f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.778f, -0.778f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.111f, -0.555f, 1.0f, 0.5f, true},
|
IntersectParams{ -0.778f, 0.555f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.111f, 0.111f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.111f, -0.555f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.111f, 0.778f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.111f, 0.111f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.555f, -0.111f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.111f, 0.778f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.555f, -0.778f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.555f, -0.111f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.555f, 0.555f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.555f, -0.778f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.778f, -0.555f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.555f, 0.555f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.778f, 0.111f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.778f, -0.555f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
KdTreeIntersectParams{0.778f, 0.778f, 1.0f, 0.5f, true},
|
IntersectParams{ 0.778f, 0.111f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
|
IntersectParams{ 0.778f, 0.778f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(KdTreeIntersectsPlane, KdTreeIntersectsParameterizedFixture, ::testing::ValuesIn(intersectTestData));
|
INSTANTIATE_TEST_CASE_P(KdTreeIntersectsPlane, KdTreeIntersectsParameterizedFixture, ::testing::ValuesIn(KdTreeIntersectTestData));
|
||||||
|
|
||||||
class KdTreeIntersectsFixture
|
class KdTreeIntersectsFixture
|
||||||
: public ModelTests
|
: public ModelTests
|
||||||
@@ -1133,7 +1155,10 @@ namespace UnitTest
|
|||||||
{
|
{
|
||||||
ModelTests::SetUp();
|
ModelTests::SetUp();
|
||||||
|
|
||||||
m_mesh = AZStd::make_unique<TwoSeparatedPlanesMesh>();
|
m_mesh = AZStd::make_unique<TestMesh>(
|
||||||
|
TwoSeparatedPlanesPositions.data(), TwoSeparatedPlanesPositions.size(), TwoSeparatedPlanesIndices.data(),
|
||||||
|
TwoSeparatedPlanesIndices.size());
|
||||||
|
|
||||||
m_kdTree = AZStd::make_unique<AZ::RPI::ModelKdTree>();
|
m_kdTree = AZStd::make_unique<AZ::RPI::ModelKdTree>();
|
||||||
ASSERT_TRUE(m_kdTree->Build(m_mesh->GetModel().Get()));
|
ASSERT_TRUE(m_kdTree->Build(m_mesh->GetModel().Get()));
|
||||||
}
|
}
|
||||||
@@ -1146,7 +1171,7 @@ namespace UnitTest
|
|||||||
ModelTests::TearDown();
|
ModelTests::TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
AZStd::unique_ptr<TwoSeparatedPlanesMesh> m_mesh;
|
AZStd::unique_ptr<TestMesh> m_mesh;
|
||||||
AZStd::unique_ptr<AZ::RPI::ModelKdTree> m_kdTree;
|
AZStd::unique_ptr<AZ::RPI::ModelKdTree> m_kdTree;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1181,4 +1206,85 @@ namespace UnitTest
|
|||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(), t, normal), testing::Eq(false));
|
m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(), t, normal), testing::Eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BruteForceIntersectsParameterizedFixture
|
||||||
|
: public ModelTests
|
||||||
|
, public ::testing::WithParamInterface<IntersectParams>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_P(BruteForceIntersectsParameterizedFixture, BruteForceIntersectsCube)
|
||||||
|
{
|
||||||
|
TestMesh mesh(CubePositions.data(), CubePositions.size(), CubeIndices.data(), CubeIndices.size());
|
||||||
|
|
||||||
|
float distance = AZStd::numeric_limits<float>::max();
|
||||||
|
AZ::Vector3 normal;
|
||||||
|
|
||||||
|
EXPECT_THAT(
|
||||||
|
mesh.GetModel()->LocalRayIntersectionAgainstModel(
|
||||||
|
AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos),
|
||||||
|
AZ::Vector3(GetParam().xdir, GetParam().ydir, GetParam().zdir), distance, normal),
|
||||||
|
testing::Eq(GetParam().expectedShouldIntersect));
|
||||||
|
EXPECT_THAT(distance, testing::FloatEq(GetParam().expectedDistance));
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr AZStd::array BruteForceIntersectTestData{
|
||||||
|
IntersectParams{ 5.0f, 0.0f, 5.0f, 0.0f, 0.0f, -1.0f, AZStd::numeric_limits<float>::max(), false },
|
||||||
|
IntersectParams{ 0.0f, 0.0f, 1.5f, 0.0f, 0.0f, -1.0f, 0.5f, true },
|
||||||
|
IntersectParams{ 5.0f, 0.0f, 0.0f, -10.0f, 0.0f, 0.0f, 0.4f, true },
|
||||||
|
IntersectParams{ -5.0f, 0.0f, 0.0f, 20.0f, 0.0f, 0.0f, 0.2f, true },
|
||||||
|
IntersectParams{ 0.0f, -10.0f, 0.0f, 0.0f, 20.0f, 0.0f, 0.45f, true },
|
||||||
|
IntersectParams{ 0.0f, 20.0f, 0.0f, 0.0f, -40.0f, 0.0f, 0.475f, true },
|
||||||
|
IntersectParams{ 0.0f, 20.0f, 0.0f, 0.0f, -19.0f, 0.0f, 1.0f, true },
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(
|
||||||
|
BruteForceIntersects, BruteForceIntersectsParameterizedFixture, ::testing::ValuesIn(BruteForceIntersectTestData));
|
||||||
|
|
||||||
|
class BruteForceModelIntersectsFixture
|
||||||
|
: public ModelTests
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
ModelTests::SetUp();
|
||||||
|
m_mesh = AZStd::make_unique<TestMesh>(CubePositions.data(), CubePositions.size(), CubeIndices.data(), CubeIndices.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
m_mesh.reset();
|
||||||
|
ModelTests::TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
AZStd::unique_ptr<TestMesh> m_mesh;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(BruteForceModelIntersectsFixture, BruteForceIntersectionDetectedWithCube)
|
||||||
|
{
|
||||||
|
float t = 0.0f;
|
||||||
|
AZ::Vector3 normal;
|
||||||
|
|
||||||
|
// firing down the negative z axis, positioned 5 units from cube (cube is 2x2x2 so intersection
|
||||||
|
// happens at 1 in z)
|
||||||
|
EXPECT_THAT(
|
||||||
|
m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
|
||||||
|
AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(10.0f), t, normal),
|
||||||
|
testing::Eq(true));
|
||||||
|
EXPECT_THAT(t, testing::FloatEq(0.4f));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(BruteForceModelIntersectsFixture, BruteForceIntersectionDetectedAndNormalSetAtEndOfRay)
|
||||||
|
{
|
||||||
|
float t = 0.0f;
|
||||||
|
AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal
|
||||||
|
|
||||||
|
// ensure the intersection happens right at the end of the ray
|
||||||
|
EXPECT_THAT(
|
||||||
|
m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
|
||||||
|
AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(9.0f), t, normal),
|
||||||
|
testing::Eq(true));
|
||||||
|
EXPECT_THAT(t, testing::FloatEq(1.0f));
|
||||||
|
EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisY()));
|
||||||
|
}
|
||||||
} // namespace UnitTest
|
} // namespace UnitTest
|
||||||
|
|||||||
@@ -693,7 +693,7 @@ namespace ImGui
|
|||||||
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Left Stick");
|
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Left Stick");
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::Bullet();
|
ImGui::Bullet();
|
||||||
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Mova Mouse Pointer");
|
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Move Mouse Pointer");
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <PhysX_precompiled.h>
|
#include <PhysX_precompiled.h>
|
||||||
#include <AzCore/Serialization/EditContext.h>
|
#include <AzCore/Serialization/EditContext.h>
|
||||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||||
|
#include <AzCore/std/parallel/scoped_lock.h>
|
||||||
#include <AzFramework/Physics/PhysicsScene.h>
|
#include <AzFramework/Physics/PhysicsScene.h>
|
||||||
#include <AzFramework/Physics/PhysicsSystem.h>
|
#include <AzFramework/Physics/PhysicsSystem.h>
|
||||||
#include <AzFramework/Physics/SystemBus.h>
|
#include <AzFramework/Physics/SystemBus.h>
|
||||||
@@ -40,6 +41,8 @@ namespace PhysX
|
|||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
// PhysX::Ragdoll
|
// PhysX::Ragdoll
|
||||||
|
/*static*/ AZStd::mutex Ragdoll::m_sceneEventMutex;
|
||||||
|
|
||||||
void Ragdoll::Reflect(AZ::ReflectContext* context)
|
void Ragdoll::Reflect(AZ::ReflectContext* context)
|
||||||
{
|
{
|
||||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
@@ -114,7 +117,10 @@ namespace PhysX
|
|||||||
|
|
||||||
Ragdoll::~Ragdoll()
|
Ragdoll::~Ragdoll()
|
||||||
{
|
{
|
||||||
m_sceneStartSimHandler.Disconnect();
|
{
|
||||||
|
AZStd::scoped_lock lock(m_sceneEventMutex);
|
||||||
|
m_sceneStartSimHandler.Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
m_nodes.clear(); //the nodes destructor will remove the simulated body from the scene.
|
m_nodes.clear(); //the nodes destructor will remove the simulated body from the scene.
|
||||||
}
|
}
|
||||||
@@ -212,7 +218,13 @@ namespace PhysX
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
|
// the handler is also connected in EnableSimulationQueued(),
|
||||||
|
// which will call this function, so if called from that path dont connect here.
|
||||||
|
if (!m_sceneStartSimHandler.IsConnected())
|
||||||
|
{
|
||||||
|
AZStd::scoped_lock lock(m_sceneEventMutex);
|
||||||
|
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
|
||||||
|
}
|
||||||
sceneInterface->EnableSimulationOfBody(m_sceneOwner, m_bodyHandle);
|
sceneInterface->EnableSimulationOfBody(m_sceneOwner, m_bodyHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +237,7 @@ namespace PhysX
|
|||||||
|
|
||||||
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
|
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
|
||||||
{
|
{
|
||||||
|
AZStd::scoped_lock lock(m_sceneEventMutex);
|
||||||
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
|
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +257,10 @@ namespace PhysX
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sceneStartSimHandler.Disconnect();
|
{
|
||||||
|
AZStd::scoped_lock lock(m_sceneEventMutex);
|
||||||
|
m_sceneStartSimHandler.Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
physx::PxScene* pxScene = Internal::GetPxScene(m_sceneOwner);
|
physx::PxScene* pxScene = Internal::GetPxScene(m_sceneOwner);
|
||||||
const size_t numNodes = m_nodes.size();
|
const size_t numNodes = m_nodes.size();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/std/parallel/mutex.h>
|
||||||
#include <AzFramework/Physics/RagdollPhysicsBus.h>
|
#include <AzFramework/Physics/RagdollPhysicsBus.h>
|
||||||
#include <AzFramework/Physics/Ragdoll.h>
|
#include <AzFramework/Physics/Ragdoll.h>
|
||||||
#include <AzFramework/Physics/Common/PhysicsEvents.h>
|
#include <AzFramework/Physics/Common/PhysicsEvents.h>
|
||||||
@@ -84,5 +85,6 @@ namespace PhysX
|
|||||||
bool m_queuedDisableSimulation = false;
|
bool m_queuedDisableSimulation = false;
|
||||||
|
|
||||||
AzPhysics::SceneEvents::OnSceneSimulationStartHandler m_sceneStartSimHandler;
|
AzPhysics::SceneEvents::OnSceneSimulationStartHandler m_sceneStartSimHandler;
|
||||||
|
static AZStd::mutex m_sceneEventMutex;
|
||||||
};
|
};
|
||||||
} // namespace PhysX
|
} // namespace PhysX
|
||||||
|
|||||||
@@ -3356,23 +3356,27 @@ namespace ScriptCanvas
|
|||||||
|
|
||||||
if (executionIf->GetId().m_node->IsIfBranchPrefacedWithBooleanExpression())
|
if (executionIf->GetId().m_node->IsIfBranchPrefacedWithBooleanExpression())
|
||||||
{
|
{
|
||||||
auto removeChildOutcome = RemoveChild(executionIf->ModParent(), executionIf);
|
ExecutionTreePtr booleanExpression;
|
||||||
if (!removeChildOutcome.IsSuccess())
|
|
||||||
{
|
{
|
||||||
AddError(executionIf->GetNodeId(), executionIf, ScriptCanvas::ParseErrors::FailedToRemoveChild);
|
auto removeChildOutcome = RemoveChild(executionIf->ModParent(), executionIf);
|
||||||
|
if (!removeChildOutcome.IsSuccess())
|
||||||
|
{
|
||||||
|
AddError(executionIf->GetNodeId(), executionIf, ScriptCanvas::ParseErrors::FailedToRemoveChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsErrorFree())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexAndChild = removeChildOutcome.TakeValue();
|
||||||
|
|
||||||
|
booleanExpression = CreateChild(executionIf->ModParent(), executionIf->GetId().m_node, executionIf->GetId().m_slot);
|
||||||
|
executionIf->ModParent()->InsertChild(indexAndChild.first, { indexAndChild.second.m_slot, indexAndChild.second.m_output, booleanExpression });
|
||||||
|
executionIf->SetParent(booleanExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsErrorFree())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto indexAndChild = removeChildOutcome.TakeValue();
|
|
||||||
|
|
||||||
ExecutionTreePtr booleanExpression = CreateChild(executionIf->ModParent(), executionIf->GetId().m_node, executionIf->GetId().m_slot);
|
|
||||||
executionIf->ModParent()->InsertChild(indexAndChild.first, { indexAndChild.second.m_slot, indexAndChild.second.m_output, booleanExpression });
|
|
||||||
executionIf->SetParent(booleanExpression);
|
|
||||||
|
|
||||||
// make a condition here
|
// make a condition here
|
||||||
auto symbol = CheckLogicalExpressionSymbol(booleanExpression);
|
auto symbol = CheckLogicalExpressionSymbol(booleanExpression);
|
||||||
if (symbol != Symbol::FunctionCall && symbol != Symbol::Count)
|
if (symbol != Symbol::FunctionCall && symbol != Symbol::Count)
|
||||||
@@ -3402,7 +3406,7 @@ namespace ScriptCanvas
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto indexAndChild2 = removeChildOutcome.TakeValue();
|
const auto indexAndChild2 = removeChildOutcome2.TakeValue();
|
||||||
|
|
||||||
// parse if statement internal function
|
// parse if statement internal function
|
||||||
ExecutionTreePtr internalFunction = CreateChild(booleanExpression->ModParent(), booleanExpression->GetId().m_node, booleanExpression->GetId().m_slot);
|
ExecutionTreePtr internalFunction = CreateChild(booleanExpression->ModParent(), booleanExpression->GetId().m_node, booleanExpression->GetId().m_slot);
|
||||||
@@ -4782,7 +4786,7 @@ namespace ScriptCanvas
|
|||||||
{
|
{
|
||||||
PropertyExtractionPtr extraction = AZStd::make_shared<PropertyExtraction>();
|
PropertyExtractionPtr extraction = AZStd::make_shared<PropertyExtraction>();
|
||||||
extraction->m_slot = slot;
|
extraction->m_slot = slot;
|
||||||
extraction->m_name = propertyField.first;
|
extraction->m_name = AZ::ReplaceCppArtifacts(propertyField.first);
|
||||||
execution->AddPropertyExtractionSource(slot, extraction);
|
execution->AddPropertyExtractionSource(slot, extraction);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+2499
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,11 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST_F(ScriptCanvasTestFixture, ParseFunctionIfBranchWithConnectedInput)
|
||||||
|
{
|
||||||
|
RunUnitTestGraph("LY_SC_UnitTest_ParseFunctionIfBranchWithConnectedInput");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ScriptCanvasTestFixture, UseRawBehaviorProperties)
|
TEST_F(ScriptCanvasTestFixture, UseRawBehaviorProperties)
|
||||||
{
|
{
|
||||||
RunUnitTestGraph("LY_SC_UnitTest_UseRawBehaviorProperties");
|
RunUnitTestGraph("LY_SC_UnitTest_UseRawBehaviorProperties");
|
||||||
|
|||||||
@@ -162,7 +162,18 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME)
|
|||||||
elseif(target_type STREQUAL MODULE_LIBRARY)
|
elseif(target_type STREQUAL MODULE_LIBRARY)
|
||||||
set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
|
set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
|
||||||
elseif(target_type STREQUAL SHARED_LIBRARY)
|
elseif(target_type STREQUAL SHARED_LIBRARY)
|
||||||
string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$<CONFIG> \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\")\n")
|
string(APPEND target_file_contents
|
||||||
|
"set_property(TARGET ${TARGET_NAME}
|
||||||
|
APPEND_STRING PROPERTY IMPORTED_IMPLIB
|
||||||
|
$<$<CONFIG:$<CONFIG>$<ANGLE-R>:\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"$<ANGLE-R>
|
||||||
|
)
|
||||||
|
")
|
||||||
|
string(APPEND target_file_contents
|
||||||
|
"set_property(TARGET ${TARGET_NAME}
|
||||||
|
PROPERTY IMPORTED_IMPLIB_$<UPPER_CASE:$<CONFIG>>
|
||||||
|
\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"
|
||||||
|
)
|
||||||
|
")
|
||||||
set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
|
set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
|
||||||
else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY
|
else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY
|
||||||
set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>")
|
set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>")
|
||||||
|
|||||||
@@ -10,5 +10,5 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
if(CMAKE_GENERATOR MATCHES "Visual Studio 16")
|
if(CMAKE_GENERATOR MATCHES "Visual Studio 16")
|
||||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/Directory.Build.props" "${CMAKE_CURRENT_BINARY_DIR}/Directory.Build.props" COPYONLY)
|
configure_file("${CMAKE_CURRENT_LIST_DIR}/Directory.Build.props" "${CMAKE_BINARY_DIR}/Directory.Build.props" COPYONLY)
|
||||||
endif()
|
endif()
|
||||||
@@ -16,35 +16,6 @@ if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
|||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Asset Processing Target
|
|
||||||
# i.e. Tests depend on AutomatedTesting.Assets
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
|
||||||
get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
|
|
||||||
foreach(project_target_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS)
|
|
||||||
file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER})
|
|
||||||
# With the lock file, asset processing jobs are serialized to avoid race conditions
|
|
||||||
# on files that are created temporarily in source folders during shader processing.
|
|
||||||
add_custom_target(${project_target_name}.Assets
|
|
||||||
COMMENT "Processing ${project_target_name} assets..."
|
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
|
||||||
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>/project_assets.lock
|
|
||||||
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
|
|
||||||
EXEC_COMMAND $<TARGET_FILE:AZ::AssetProcessorBatch>
|
|
||||||
--zeroAnalysisMode
|
|
||||||
--project-path=${project_real_path}
|
|
||||||
--platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
|
|
||||||
)
|
|
||||||
set_target_properties(${project_target_name}.Assets
|
|
||||||
PROPERTIES
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
FOLDER ${project_target_name}
|
|
||||||
)
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Tests
|
# Tests
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
Reference in New Issue
Block a user