diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h new file mode 100644 index 00000000..cc88a54d --- /dev/null +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -0,0 +1,75 @@ +/** + * Copyright (C) Robotec AI - All Rights Reserved + * + * This source code is protected under international copyright law. All rights + * reserved and protected by the copyright holders. + * This file is confidential and only available to authorized individuals with + * the permission of the copyright holders. If you encounter this file and do + * not have permission, please contact the copyright holders and delete this + * file. + */ + +#pragma once + +#include + +#include +#include + +namespace CsvSpawner +{ + /** + * @brief Interface for handling entity spawn events for Csv Spawner. + * + * CsvSpawnerInterface is an Event Bus interface that notifies multiple + * listeners when entity spawning begins and finishes. + */ + class CsvSpawnerInterface : public AZ::EBusTraits + { + public: + AZ_RTTI(CsvSpawnerInterface, CsvSpawnerInterfaceTypeId); + virtual ~CsvSpawnerInterface() = default; + + /** + * @brief Called when entity spawning begins. + * @param m_spawnInfo Struct holding information about entities to be spawned. + */ + virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo m_spawnInfo) = 0; + + /** + * @brief Called when entity spawning finishes. + * @param m_spawnInfo Struct holding information about entities to be spawned. + * @param m_statusCode Status code indicating success, failure and warnings of the spawn. + */ + virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) = 0; + + /// EBus Configuration - Allows multiple listeners to handle events. + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + }; + + // Create an EBus using the notification interface + using CsvSpawnerNotificationBus = AZ::EBus; + + class CsvSpawnerNotificationBusHandler + : public CsvSpawnerNotificationBus::Handler + , public AZ::BehaviorEBusHandler + { + public: + AZ_EBUS_BEHAVIOR_BINDER( + CsvSpawnerNotificationBusHandler, + CsvSpawnerNotificationBusHandlerTypeId, + AZ::SystemAllocator, + OnEntitiesSpawnBegin, + OnEntitiesSpawnFinished); + + void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo m_spawnInfo) override + { + Call(FN_OnEntitiesSpawnBegin, m_spawnInfo); + } + + void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) override + { + Call(FN_OnEntitiesSpawnFinished, m_spawnInfo, m_statusCode); + } + }; +} // namespace CsvSpawner diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h index a58cd3df..a265b50d 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h @@ -22,5 +22,7 @@ namespace CsvSpawner inline constexpr const char* CsvSpawnerComponentTypeId = "{59b31372-1f3c-4733-b61b-0fe94b5a8f3e}"; // Interface TypeIds - inline constexpr const char* CsvSpawnerRequestsTypeId = "{77ACBD4E-069E-4610-8154-E1AC28CEE05A}"; + inline constexpr const char* CsvSpawnerInterfaceTypeId = "{77ACBD4E-069E-4610-8154-E1AC28CEE05A}"; + inline constexpr const char* CsvSpawnerNotificationBusHandlerTypeId = "{1F142F00-4E79-431B-9C1D-3AB157838FF8}"; + inline constexpr const char* CsvSpawnerSpawnInfoTypeId = "{81E5A014-3232-4359-98F5-7F9D7152629E}"; } // namespace CsvSpawner diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h index 2385532d..397b4ab2 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h @@ -10,8 +10,10 @@ #pragma once +#include +#include + #include "AzFramework/Terrain/TerrainDataRequestBus.h" -#include "CsvSpawnerUtils.h" #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp index ffdb7997..6b9fb728 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp @@ -8,12 +8,11 @@ * permission, please contact the copyright holders and delete this file. */ -#include "CsvSpawnerUtils.h" #include #include #include #include -#include +#include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h index adf33746..8e962dbc 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h @@ -10,12 +10,8 @@ #pragma once -#include "CsvSpawnerUtils.h" -#include -#include -#include #include -#include +#include namespace CsvSpawner::CsvSpawnerUtils { diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp index fdcde419..da1e569a 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp @@ -12,6 +12,7 @@ #include "CsvSpawnerComponent.h" #include "CsvSpawnerCsvParser.h" #include "CsvSpawnerUtils.h" +#include #include #include @@ -26,6 +27,8 @@ namespace CsvSpawner { void CsvSpawnerEditorComponent::Reflect(AZ::ReflectContext* context) { + CsvSpawner::SpawnInfo::Reflect(context); + AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { @@ -70,6 +73,12 @@ namespace CsvSpawner "Settings to configure spawn behaviour in editor."); } } + + if (const auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("CsvSpawnerNotificationBus") + ->Handler(); + } } void CsvSpawnerEditorComponent::Activate() diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h index 62665e07..10aa9727 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h @@ -10,9 +10,12 @@ #pragma once -#include "CsvSpawnerUtils.h" +#include +#include + #include "EditorConfigurations/CsvSpawnerEditorTerrainSettingsConfig.h" +#include #include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index dc660beb..bbe1c1d6 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -11,11 +11,15 @@ #include "CsvSpawnerUtils.h" +#include "AzCore/std/smart_ptr/make_shared.h" + +#include +#include + #include #include #include #include -#include #include #include #include @@ -37,6 +41,32 @@ namespace CsvSpawner::CsvSpawnerUtils ->Field("Transform", &CsvSpawnableEntityInfo::m_transform) ->Field("Name", &CsvSpawnableEntityInfo::m_name) ->Field("Seed", &CsvSpawnableEntityInfo::m_seed); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Csv Spawnable Entity Info", "An entity configuration for spawning") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement(AZ::Edit::UIHandlers::Default, &CsvSpawnableEntityInfo::m_id, "ID", "Optional ID for the entity") + ->DataElement( + AZ::Edit::UIHandlers::Default, &CsvSpawnableEntityInfo::m_transform, "Transform", "Transform of the entity") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &CsvSpawnableEntityInfo::m_name, + "Name", + "Name of the spawnable entity configuration") + ->DataElement( + AZ::Edit::UIHandlers::Default, &CsvSpawnableEntityInfo::m_seed, "Seed", "Optional seed value for randomization"); + } + } + + if (auto* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("CsvSpawnableEntityInfo") + ->Constructor<>() + ->Property("Id", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_id)) + ->Property("Transform", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_transform)) + ->Property("Name", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_name)) + ->Property("Seed", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_seed)); } } void CsvSpawnableAssetConfiguration::Reflect(AZ::ReflectContext* context) @@ -193,6 +223,25 @@ namespace CsvSpawner::CsvSpawnerUtils const AZStd::string& physicsSceneName, AZ::EntityId parentId) { + SpawnInfo broadcastSpawnInfo = + SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. + + // SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - + // OnEntitiesSpawnFinished. + auto spawnStatusCode = AZStd::make_shared( + SpawnStatus::Success); // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. + + // Call CsvSpawner EBus notification - Begin + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, broadcastSpawnInfo); + + // Check if there are no entities to spawn + if (entitiesToSpawn.empty()) + { + *spawnStatusCode |= SpawnStatus::Fail; + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, *spawnStatusCode); + return {}; + } + auto sceneInterface = AZ::Interface::Get(); AZ_Assert(sceneInterface, "Unable to get physics scene interface"); const auto sceneHandle = sceneInterface->GetSceneHandle(physicsSceneName); @@ -201,6 +250,8 @@ namespace CsvSpawner::CsvSpawnerUtils auto spawner = AZ::Interface::Get(); AZ_Assert(spawner, "Unable to get spawnable entities definition"); + auto pendingSpawns = AZStd::make_shared(static_cast(entitiesToSpawn.size())); + // get parent transform AZ::Transform parentTransform = AZ::Transform::CreateIdentity(); if (parentId.IsValid()) @@ -221,6 +272,9 @@ namespace CsvSpawner::CsvSpawnerUtils if (!spawnableAssetConfiguration.contains(entityConfig.m_name)) { AZ_Error("CsvSpawner", false, "SpawnableAssetConfiguration %s not found", entityConfig.m_name.c_str()); + + // Add notify code status + *spawnStatusCode |= SpawnStatus::Warning; continue; } @@ -250,6 +304,9 @@ namespace CsvSpawner::CsvSpawnerUtils } else { + // Add notify code status + *spawnStatusCode |= SpawnStatus::Warning; + continue; // Skip this entity if we can't find a valid position and // place on terrain is enabled. } @@ -257,12 +314,16 @@ namespace CsvSpawner::CsvSpawnerUtils AZ_Assert(spawner, "Unable to get spawnable entities definition"); AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; AzFramework::EntitySpawnTicket ticket(spawnable); + // Set the pre-spawn callback to set the name of the root entity to the name // of the spawnable - optionalArgs.m_preInsertionCallback = [transform](auto id, auto view) + optionalArgs.m_preInsertionCallback = [transform, &spawnStatusCode](auto id, auto view) { if (view.empty()) { + // Add notify code status + *spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; + return; } AZ::Entity* root = *view.begin(); @@ -271,24 +332,97 @@ namespace CsvSpawner::CsvSpawnerUtils auto* transformInterface = root->FindComponent(); transformInterface->SetWorldTM(transform); }; + optionalArgs.m_completionCallback = - [parentId]( + [parentId, spawnStatusCode, pendingSpawns, broadcastSpawnInfo]( [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) { if (view.empty()) { - return; + *spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; + } + else + { + const AZ::Entity* root = *view.begin(); + AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); + } + + // Decrement the pending counter + const int remaining = --(*pendingSpawns); + if (remaining == 0) + { + // All spawns are finished, now broadcast finished notification + CsvSpawnerNotificationBus::Broadcast( + &CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, *spawnStatusCode); } - const AZ::Entity* root = *view.begin(); - AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); }; + optionalArgs.m_priority = AzFramework::SpawnablePriority_Lowest; spawner->SpawnAllEntities(ticket, optionalArgs); tickets[entityConfig.m_id] = AZStd::move(ticket); } + return tickets; } + void SpawnInfo::Reflect(AZ::ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + // Reflect SpawnStatus enum + serializeContext->Enum() + ->Version(0) + ->Value("Success", SpawnStatus::Success) + ->Value("Fail", SpawnStatus::Fail) + ->Value("Stopped", SpawnStatus::Stopped) + ->Value("Warning", SpawnStatus::Warning); + + // Reflect SpawnInfo struct + serializeContext->Class() + ->Version(0) + ->Field("EntitiesToSpawn", &SpawnInfo::m_entitiesToSpawn) + ->Field("PhysicsSceneName", &SpawnInfo::m_physicsSceneName) + ->Field("SpawnerParentEntityId", &SpawnInfo::m_spawnerParentEntityId); + + if (auto* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Spawn Info", "Information about entities being spawned") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SpawnInfo::m_entitiesToSpawn, + "Entities to Spawn", + "List of entities to be spawned.") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SpawnInfo::m_physicsSceneName, + "Physics Scene", + "Name of the physics scene where entities will be spawned.") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SpawnInfo::m_spawnerParentEntityId, + "Parent Entity", + "Parent entity ID responsible for spawning."); + } + } + + if (auto* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Success)>("SpawnStatus_Success"); + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Fail)>("SpawnStatus_Fail"); + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Stopped)>("SpawnStatus_Stopped"); + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Warning)>("SpawnStatus_Warning"); + + behaviorContext->Class("SpawnInfo") + ->Constructor() + ->Attribute(AZ::Script::Attributes::Category, "CsvSpawner") + ->Attribute(AZ::Script::Attributes::Module, "editor") + ->Property("m_entitiesToSpawn", BehaviorValueProperty(&SpawnInfo::m_entitiesToSpawn)) + ->Property("m_physicsSceneName", BehaviorValueProperty(&SpawnInfo::m_physicsSceneName)) + ->Property("m_spawnerParentEntityId", BehaviorValueProperty(&SpawnInfo::m_spawnerParentEntityId)); + } + } + bool IsTerrainAvailable() { return AzFramework::Terrain::TerrainDataRequestBus::HasHandlers(); diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h index d9313537..3b828fc8 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h @@ -11,14 +11,13 @@ #pragma once -#include "CsvSpawner/CsvSpawnerTypeIds.h" +#include #include #include #include #include #include -#include #include #include @@ -99,6 +98,38 @@ namespace CsvSpawner::CsvSpawnerUtils const AZStd::string& physicsSceneName = AZStd::string(), AZ::EntityId parentId = AZ::EntityId()); - [[nodiscard]] bool IsTerrainAvailable(); //!< @returns True if level has any valid Terrain handlers, false otherwise. + /** + * @brief Flags representing the status of an CsvSpawner::Spawn() operation. + * + * SpawnStatus provides various status indicators for entity spawning. + * These flags help track whether spawning was successful, stopped, or failed. + */ + enum class SpawnStatus : uint8_t + { + Success = 0, ///< Operation succeeded. + Fail = 1 << 0, ///< Generic failure. + Stopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. + Warning = 1 << 2, ///< An warning or error occurred during spawning (potentially recoverable). + }; + + /// Enable bitwise operations for SpawnStatus. + AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatus); + + /** + * @brief Structure holding data related to CsvSpawner entity spawning. + * + * SpawnInfo contains information about the entities to be spawned, the physics scene + * they belong to, and the parent entity responsible for the spawn operation. + */ + struct SpawnInfo + { + AZ_TYPE_INFO(SpawnInfo, CsvSpawnerSpawnInfoTypeId); + static void Reflect(AZ::ReflectContext* context); -}; // namespace CsvSpawner::CsvSpawnerUtils + AZStd::vector m_entitiesToSpawn; ///< List of entities to spawn. + AZStd::string m_physicsSceneName; ///< Name of the physics scene where entities will be spawned. + AZ::EntityId m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. + }; + + [[nodiscard]] bool IsTerrainAvailable(); //!< @returns True if level has any valid Terrain handlers, false otherwise. +} // namespace CsvSpawner::CsvSpawnerUtils diff --git a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake index c4fb100e..cd4cc9fe 100644 --- a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake +++ b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake @@ -1,4 +1,5 @@ set(FILES + Include/CsvSpawner/CsvSpawnerInterface.h Include/CsvSpawner/CsvSpawnerTypeIds.h ) diff --git a/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp b/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp index 9c855dae..9116fc1d 100644 --- a/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp +++ b/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -314,7 +314,7 @@ namespace GeoJSONSpawner::GeoJSONUtils const AZStd::vector& featureObjects, const AZStd::unordered_map& spawnableAssetConfigurations) { - if (!ROS2::GeoreferenceRequestsBus::HasHandlers()) + if (!Georeferencing::GeoreferenceRequestsBus::HasHandlers()) { AZ_Error("GeoJSONSpawnerUtils", false, "Cannot convert WGS84 coordinates - Level is not geographically positioned."); return {}; @@ -336,14 +336,14 @@ namespace GeoJSONSpawner::GeoJSONUtils { constexpr float defaultScale = 1.0f; const AZ::Quaternion rotation = AZ::Quaternion::CreateIdentity(); - ROS2::WGS::WGS84Coordinate coordinate; + Georeferencing::WGS::WGS84Coordinate coordinate; AZ::Vector3 coordinateInLevel = AZ::Vector3(-1); coordinate.m_longitude = point[0]; coordinate.m_latitude = point[1]; coordinate.m_altitude = spawnableAssetConfig.m_raytraceStartingHeight; - ROS2::GeoreferenceRequestsBus::BroadcastResult( - coordinateInLevel, &ROS2::GeoreferenceRequestsBus::Events::ConvertFromWGS84ToLevel, coordinate); + Georeferencing::GeoreferenceRequestsBus::BroadcastResult( + coordinateInLevel, &Georeferencing::GeoreferenceRequestsBus::Events::ConvertFromWGS84ToLevel, coordinate); AZ::Transform transform{ coordinateInLevel, rotation, defaultScale }; spawnableEntityInfo.m_positions.emplace_back(AZStd::move(transform)); diff --git a/Gems/GeoJSONSpawner/gem.json b/Gems/GeoJSONSpawner/gem.json index 4e4dc340..edc9e747 100644 --- a/Gems/GeoJSONSpawner/gem.json +++ b/Gems/GeoJSONSpawner/gem.json @@ -18,10 +18,10 @@ "" ], "icon_path": "preview.png", - "requirements": "Requires ROS2 Gem", + "requirements": "Requires LevelGeoreferencing Gem", "documentation_url": "", "dependencies": [ - "ROS2" + "LevelGeoreferencing" ], "repo_uri": "", "compatible_engines": [], diff --git a/Gems/ImGuiProvider/Code/CMakeLists.txt b/Gems/ImGuiProvider/Code/CMakeLists.txt index 73fc8e7e..08945df6 100644 --- a/Gems/ImGuiProvider/Code/CMakeLists.txt +++ b/Gems/ImGuiProvider/Code/CMakeLists.txt @@ -30,7 +30,7 @@ ly_add_target( BUILD_DEPENDENCIES INTERFACE AZ::AzCore - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public ) # The ${gem_name}.Private.Object target is an internal target @@ -51,7 +51,7 @@ ly_add_target( PUBLIC AZ::AzCore AZ::AzFramework - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public ) @@ -138,7 +138,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC AZ::AzToolsFramework ${gem_name}.Private.Object - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public ) ly_add_target( diff --git a/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp b/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp index 10f635af..f6eea723 100644 --- a/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp +++ b/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp @@ -12,8 +12,6 @@ #include #include #include -#include - #include #include #include @@ -125,18 +123,19 @@ namespace ImGuiProvider // if current context is not available through Imgui system bus, get context from pass and push is to imgui system bus if (!m_currentImGuiContext) { - AZ::Render::ImGuiPass* pass; - AZ::Render::ImGuiSystemRequestBus::BroadcastResult(pass, &AZ::Render::ImGuiSystemRequests::GetDefaultImGuiPass); - if (pass) + bool success; + AZ::Render::ImGuiSystemRequestBus::BroadcastResult( + success, &AZ::Render::ImGuiSystemRequests::PushActiveContextFromDefaultPass); + if (success) { - auto context = pass->GetContext(); - if (context) - { - AZ_Info("ImGuiProviderSystemComponent", "Gathering pass context and pushing as active"); - m_currentImGuiContext = context; - m_previousImGuiContext = context; - ImGui::SetCurrentContext(context); - } + AZ::Render::ImGuiSystemRequestBus::BroadcastResult( + m_currentImGuiContext, &AZ::Render::ImGuiSystemRequests::GetActiveContext); + m_previousImGuiContext = m_currentImGuiContext; + } + else + { + AZ_Error("ImGuiProviderSystemComponent::OnTick", false, "Failed to get active context from ImGuiSystemBus"); + return; } } // if needed move viewport icons diff --git a/Gems/ImGuizmo/Code/CMakeLists.txt b/Gems/ImGuizmo/Code/CMakeLists.txt index 1ba8071f..8b6ab5a7 100644 --- a/Gems/ImGuizmo/Code/CMakeLists.txt +++ b/Gems/ImGuizmo/Code/CMakeLists.txt @@ -52,7 +52,7 @@ ly_add_target( PUBLIC AZ::AzCore AZ::AzFramework - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public Gem::ImGui.Static ) diff --git a/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl b/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl index 844a6d60..7c0d6b9e 100644 --- a/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl +++ b/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl @@ -8,8 +8,8 @@ #include #include -#include -#include +#include +#include ShaderResourceGroup PerDrawSrg : SRG_PerDraw { diff --git a/Gems/Pointcloud/Code/CMakeLists.txt b/Gems/Pointcloud/Code/CMakeLists.txt index 92d88c28..c288f08b 100644 --- a/Gems/Pointcloud/Code/CMakeLists.txt +++ b/Gems/Pointcloud/Code/CMakeLists.txt @@ -39,7 +39,6 @@ ly_add_target( Gem::Atom_RPI.Public Gem::Atom_Feature_Common Gem::Atom_Feature_Common.Public - Gem::Atom_Feature_Common.Static ) # The ${gem_name}.Private.Object target is an internal target @@ -64,7 +63,6 @@ ly_add_target( Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Feature_Common - Gem::AtomLyIntegration_CommonFeatures.Static ) # Here add ${gem_name} target, it depends on the Private Object library and Public API interface @@ -140,7 +138,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework $ Gem::Atom_Utils.Static - Gem::Atom_Feature_Common.Static Gem::AtomLyIntegration_CommonFeatures.Static PRIVATE AZ::AssetBuilderSDK diff --git a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp index e06a42c0..f6c37178 100644 --- a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp +++ b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp @@ -99,7 +99,7 @@ namespace Pointcloud else { AZ::RPI::CommonBufferDescriptor desc; - desc.m_poolType = AZ::RPI::CommonBufferPoolType::ReadWrite; + desc.m_poolType = AZ::RPI::CommonBufferPoolType::DynamicInputAssembly; desc.m_bufferName = AZStd::string::format("PointcloudFeatureProcessor, %d", pcData.m_index); desc.m_byteCount = bufferSize; desc.m_elementSize = elementSize; @@ -158,7 +158,12 @@ namespace Pointcloud if (m_meshPipelineState && pcData.m_drawSrg && pcData.m_meshStreamBufferViews.front().GetByteCount() != 0) { pcData.m_drawPacket = BuildDrawPacket( - pcData.m_drawSrg, m_meshPipelineState, m_drawListTag, pcData.m_meshStreamBufferViews, pcData.m_vertices); + pcData.m_drawSrg, + m_meshPipelineState, + m_drawListTag, + pcData.m_meshStreamBufferViews, + pcData.m_geometryView, + pcData.m_vertices); } } } @@ -236,23 +241,33 @@ namespace Pointcloud const AZ::RPI::Ptr& pipelineState, const AZ::RHI::DrawListTag& drawListTag, const AZStd::span& streamBufferViews, + AZ::RHI::GeometryView& geometryView, uint32_t vertexCount) { + geometryView.Reset(); AZ::RHI::DrawLinear drawLinear; drawLinear.m_vertexCount = vertexCount; drawLinear.m_vertexOffset = 0; - drawLinear.m_instanceCount = 1; - drawLinear.m_instanceOffset = 0; + AZ::RHI::DrawInstanceArguments drawInstanceArgs; + drawInstanceArgs.m_instanceCount = 1; + drawInstanceArgs.m_instanceOffset = 0; + geometryView.SetDrawArguments(drawLinear); - AZ::RHI::DrawPacketBuilder drawPacketBuilder; + for (size_t i = 0; i < streamBufferViews.size(); ++i) + { + geometryView.AddStreamBufferView(streamBufferViews[i]); + } + AZ::RHI::DrawPacketBuilder drawPacketBuilder{ AZ::RHI::MultiDevice::AllDevices }; drawPacketBuilder.Begin(nullptr); - drawPacketBuilder.SetDrawArguments(drawLinear); + drawPacketBuilder.SetGeometryView(&geometryView); + drawPacketBuilder.SetDrawInstanceArguments(drawInstanceArgs); drawPacketBuilder.AddShaderResourceGroup(srg->GetRHIShaderResourceGroup()); AZ::RHI::DrawPacketBuilder::DrawRequest drawRequest; drawRequest.m_listTag = drawListTag; drawRequest.m_pipelineState = pipelineState->GetRHIPipelineState(); - drawRequest.m_streamBufferViews = streamBufferViews; + drawRequest.m_streamIndices = geometryView.GetFullStreamBufferIndices(); + drawPacketBuilder.AddDrawItem(drawRequest); return drawPacketBuilder.End(); } @@ -367,6 +382,7 @@ namespace Pointcloud } return AZStd::nullopt; } + void PointcloudFeatureProcessor::ConnectChangeEventHandler( const PointcloudHandle& pointcloudHandle, PointcloudChangedEvent::Handler& handler) { diff --git a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h index 5387ee25..59f1b9a0 100644 --- a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h +++ b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h @@ -62,7 +62,7 @@ namespace Pointcloud PointcloudHandle m_index = 0; AZ::Data::Asset m_cloudVertexBufferAsset; AZ::Data::Instance m_cloudVertexBuffer = nullptr; - + AZ::RHI::GeometryView m_geometryView; AZStd::array m_meshStreamBufferViews; AZStd::vector m_pointData; uint32_t m_vertices = 0; @@ -92,6 +92,7 @@ namespace Pointcloud const AZ::RPI::Ptr& pipelineState, const AZ::RHI::DrawListTag& drawListTag, const AZStd::span& streamBufferViews, + AZ::RHI::GeometryView& geometryView, uint32_t vertexCount); AZ::RPI::Ptr m_meshPipelineState; diff --git a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp index 3fe621ae..7914dbe2 100644 --- a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp +++ b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp @@ -96,27 +96,24 @@ namespace Pointcloud AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - if (auto serializeContext = azrtti_cast(context)) + serializeContext->Class()->Version(1)->Field( + "Configuration", &PointcloudComponentController::m_config); + + AZ::EditContext* editContext = serializeContext->GetEditContext(); + if (editContext) { - serializeContext->Class()->Version(1)->Field( - "Configuration", &PointcloudComponentController::m_config); + editContext->Class("PointcloudComponentController", "PointcloudComponentController") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "PointcloudComponentController") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) + ->Attribute(AZ::Edit::Attributes::Category, "RobotecTools") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - AZ::EditContext* editContext = serializeContext->GetEditContext(); - if (editContext) - { - editContext->Class("PointcloudComponentController", "PointcloudComponentController") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "PointcloudComponentController") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) - ->Attribute(AZ::Edit::Attributes::Category, "RobotecTools") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - - ->DataElement( - AZ::Edit::UIHandlers::Default, - &PointcloudComponentController::m_config, - "Configuration", - "Configuration of the pointcloud") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &PointcloudComponentController::OnAssetChanged); - } + ->DataElement( + AZ::Edit::UIHandlers::Default, + &PointcloudComponentController::m_config, + "Configuration", + "Configuration of the pointcloud") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &PointcloudComponentController::OnAssetChanged); } } } @@ -138,13 +135,18 @@ namespace Pointcloud AZ_Assert(m_featureProcessor, "Failed to enable PointcloudFeatureProcessorInterface."); } } - m_featureProcessor->ConnectChangeEventHandler(m_config.m_pointcloudHandle, m_changeEventHandler); + + if (m_featureProcessor) + { + m_featureProcessor->ConnectChangeEventHandler(m_config.m_pointcloudHandle, m_changeEventHandler); + } OnAssetChanged(); }); } void PointcloudComponentController::Deactivate() { + m_changeEventHandler.Disconnect(); PointcloudConfigurationBus::Handler::BusDisconnect(); AZ::TransformNotificationBus::Handler::BusDisconnect(); if (m_featureProcessor) diff --git a/Gems/Pointcloud/gem.json b/Gems/Pointcloud/gem.json index ed62806c..8563bfb5 100644 --- a/Gems/Pointcloud/gem.json +++ b/Gems/Pointcloud/gem.json @@ -18,14 +18,14 @@ "" ], "icon_path": "preview.png", - "requirements": "Notice of any requirements for this Gem i.e. This requires X other gem", - "documentation_url": "Link to any documentation of your Gem", + "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI", "Atom" ], "repo_uri": "https://github.com/RobotecAI/robotec-o3de-tools", - "compatible_engines": ["o3de>=2.3.0"], + "compatible_engines": ["o3de>=4.2.0"], "engine_api_dependencies": [], "restricted": "Pointcloud" } diff --git a/readme.md b/readme.md index a98c0408..1b845e89 100644 --- a/readme.md +++ b/readme.md @@ -103,6 +103,18 @@ Useful for robots' movement smoothing. Component that spawns prefabs using coordinates stored in CSV file. It supports XYZ format as well as WGS84 coordinate system. ![](doc/CsvSpawner.png) +## API +This Gem has defined notification bus - `CsvSpawnerNotificationBus`. + +Available functions: + +| Name | Parameters | Description | +|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------| +| `OnEntitiesSpawnBegin` | `SpawnInfo` - Struct holding information about entities to be spawned | Called when entity spawning begins. | +| `OnEntitiesSpawnFinished` | `SpawnInfo` - Struct holding information about entities to be spawned
`SpawnStatus` - Status code of the spawn (success, warnings, fail). | Called when entity spawning finishes. | + +> *Supports **Lua** and **Script Canvas*** + ## Load object from CSV file CSV file format for coordinates in XYZ system: @@ -115,7 +127,6 @@ x y z name 5.1 65 0 object_name 5.1 72 0 object_name 5.1 79 0 object_name - ``` CSV file format for coordinates in WGS84 system: @@ -128,7 +139,6 @@ alt lat lon name 0 12.5897180240288 30.1932813604207 ball 0 12.5897414039641 30.1933370085065 ball 0 12.5897646831551 30.1933927129084 ball - ``` # ExposeConsoleToRos