/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #if !defined(AZ_MONOLITHIC_BUILD) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace AZ { namespace SceneAPI { namespace SceneCore { static class EntityMonitor* g_entityMonitor = nullptr; static AZ::Entity* g_behaviors = nullptr; static AZ::EntityId g_behaviorsId; static AZStd::vector g_componentDescriptors; static AZ::SceneAPI::Import::ManifestImportRequestHandler* g_manifestImporter = nullptr; class EntityMonitor : public AZ::EntityBus::Handler { public: AZ_CLASS_ALLOCATOR(EntityMonitor, AZ::SystemAllocator, 0); EntityMonitor() { AZ::EntityBus::Handler::BusConnect(g_behaviorsId); } ~EntityMonitor() { AZ::EntityBus::Handler::BusDisconnect(g_behaviorsId); } void OnEntityDestruction(const AZ::EntityId& entityId) override { if (entityId == g_behaviorsId) { // Another part of the code has claimed and deleted this entity already. g_behaviors = nullptr; AZ::EntityBus::Handler::BusDisconnect(g_behaviorsId); g_behaviorsId.SetInvalid(); } } }; void Initialize() { // Explicitly creating this component early as this currently needs to be available to the // RC before Gems are loaded in order to know the file extension. if (!g_manifestImporter) { g_manifestImporter = aznew AZ::SceneAPI::Import::ManifestImportRequestHandler(); g_manifestImporter->Activate(); } } bool IMeshGroupConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { if (classElement.GetVersion() == 1) { // There have been 2 version of IMeshGroup, one that directly inherited from IGroup and one that // inherited as IMeshGroup : ISceneNodeGroup (was IMeshBaseGroup) : IGroup. To fix this, check // if {1D20FA11-B184-429E-8C86-745852234845} (ISceneNodeGroup) is present and if not add it. AZ::SerializeContext::DataElementNode& baseClass = classElement.GetSubElement(0); if (baseClass.GetId() != AZ::SceneAPI::DataTypes::ISceneNodeGroup::TYPEINFO_Uuid()) { if (!baseClass.Convert(context)) { AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "Failed to upgrade IMeshGroup from version 1."); return false; } } } return true; } void Reflect(AZ::SerializeContext* context) { if (!context) { AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext); } // Check if this library hasn't already been reflected. This can happen as the ResourceCompilerScene needs // to explicitly load and reflect the SceneAPI libraries to discover the available extension, while // Gems with system components need to do the same in the Project Configurator. if (context && (context->IsRemovingReflection() || !context->FindClassData(AZ::SceneAPI::DataTypes::IGroup::TYPEINFO_Uuid()))) { AZ::SceneAPI::DataTypes::IManifestObject::Reflect(context); // Register components AZ::SceneAPI::SceneCore::BehaviorComponent::Reflect(context); AZ::SceneAPI::SceneCore::LoadingComponent::Reflect(context); AZ::SceneAPI::SceneCore::ExportingComponent::Reflect(context); AZ::SceneAPI::SceneCore::RCExportingComponent::Reflect(context); AZ::SceneAPI::SceneCore::SceneSystemComponent::Reflect(context); // Register group interfaces context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(2, &IMeshGroupConverter); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); // Register rule interfaces context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); // Register graph data interfaces context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); context->Class()->Version(1); // Register base manifest types context->Class()->Version(1); // Register containers AZ::SceneAPI::Containers::RuleContainer::Reflect(context); AZ::SceneAPI::Containers::SceneManifest::Reflect(context); // Register utilities AZ::SceneAPI::SceneCore::PatternMatcher::Reflect(context); } // Descriptor registration is done in Reflect instead of Initialize because the ResourceCompilerScene initializes the libraries before // there's an application. if (g_componentDescriptors.empty()) { g_componentDescriptors.push_back(AZ::SceneAPI::Export::MaterialExporterComponent::CreateDescriptor()); g_componentDescriptors.push_back(AZ::SceneAPI::Export::RCMaterialExporterComponent::CreateDescriptor()); for (AZ::ComponentDescriptor* descriptor : g_componentDescriptors) { AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Handler::RegisterComponentDescriptor, descriptor); } } } void Activate() { if (g_behaviors) { return; } g_behaviors = AZ::SceneAPI::SceneCore::EntityConstructor::BuildEntityRaw("Scene Behaviors", AZ::SceneAPI::SceneCore::BehaviorComponent::TYPEINFO_Uuid()); g_behaviorsId = g_behaviors->GetId(); AZ_Error("SceneCore", !g_entityMonitor, "The EntityMonitor has not been deactivated properly, cannot complete activation"); if (!g_entityMonitor) { g_entityMonitor = aznew EntityMonitor(); } } void Deactivate() { if (g_entityMonitor) { delete g_entityMonitor; g_entityMonitor = nullptr; } if (g_behaviors) { g_behaviors->Deactivate(); delete g_behaviors; g_behaviors = nullptr; g_behaviorsId.SetInvalid(); } } void Uninitialize() { AZ::SerializeContext* context = nullptr; AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext); if (context) { context->EnableRemoveReflection(); Reflect(context); context->DisableRemoveReflection(); context->CleanupModuleGenericClassInfo(); } if (!g_componentDescriptors.empty()) { for (AZ::ComponentDescriptor* descriptor : g_componentDescriptors) { descriptor->ReleaseDescriptor(); } g_componentDescriptors.clear(); g_componentDescriptors.shrink_to_fit(); } if (g_manifestImporter) { g_manifestImporter->Deactivate(); delete g_manifestImporter; g_manifestImporter = nullptr; } } } // namespace SceneCore } // namespace SceneAPI } // namespace AZ #if !defined(SCENE_CORE_STATIC) extern "C" AZ_DLL_EXPORT void InitializeDynamicModule(void* env) { if (AZ::Environment::IsReady()) { return; } AZ::Environment::Attach(static_cast(env)); AZ::SceneAPI::SceneCore::Initialize(); } extern "C" AZ_DLL_EXPORT void Reflect(AZ::SerializeContext* context) { AZ::SceneAPI::SceneCore::Reflect(context); } extern "C" AZ_DLL_EXPORT void Activate() { AZ::SceneAPI::SceneCore::Activate(); } extern "C" AZ_DLL_EXPORT void Deactivate() { AZ::SceneAPI::SceneCore::Deactivate(); } extern "C" AZ_DLL_EXPORT void UninitializeDynamicModule() { if (!AZ::Environment::IsReady()) { return; } AZ::SceneAPI::SceneCore::Uninitialize(); // This module does not own these allocators, but must clear its cached EnvironmentVariables // because it is linked into other modules, and thus does not get unloaded from memory always if (AZ::AllocatorInstance::IsReady()) { AZ::AllocatorInstance::Destroy(); } if (AZ::AllocatorInstance::IsReady()) { AZ::AllocatorInstance::Destroy(); } AZ::Environment::Detach(); } #endif // !defined(SCENE_CORE_STATIC) #endif // !defined(AZ_MONOLITHIC_BUILD)