AnyAssetBuilder.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AssetBuilderSDK/SerializationDependencies.h>
  9. #include <Common/AnyAssetBuilder.h>
  10. #include <AzCore/Component/ComponentApplicationBus.h>
  11. #include <AzCore/Serialization/Utils.h>
  12. #include <AzCore/std/smart_ptr/make_shared.h>
  13. #include <AzCore/std/algorithm.h>
  14. #include <AzFramework/IO/LocalFileIO.h>
  15. #include <AzFramework/StringFunc/StringFunc.h>
  16. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  17. #include <AzCore/Serialization/Json/JsonUtils.h>
  18. #include <Atom/RPI.Edit/Common/ConvertibleSource.h>
  19. #include <Atom/RPI.Reflect/System/AnyAsset.h>
  20. namespace AZ
  21. {
  22. namespace RPI
  23. {
  24. namespace
  25. {
  26. [[maybe_unused]] const char* AnyAssetBuilderName = "AnyAssetBuilder";
  27. const char* AnyAssetBuilderJobKey = "Any Asset Builder";
  28. const char* AnyAssetBuilderDefaultExtension = "azasset";
  29. const char* AnyAssetSourceExtensions[] =
  30. {
  31. "azasset",
  32. "attimage",
  33. "azbuffer",
  34. };
  35. const uint32_t NumberOfSourceExtensions = AZ_ARRAY_SIZE(AnyAssetSourceExtensions);
  36. }
  37. void AnyAssetBuilder::RegisterBuilder()
  38. {
  39. // build source extension patterns
  40. AZStd::vector<AssetBuilderSDK::AssetBuilderPattern> patterns(NumberOfSourceExtensions);
  41. AZStd::for_each(patterns.begin(), patterns.end(), [&, index = 0](AssetBuilderSDK::AssetBuilderPattern& pattern) mutable
  42. {
  43. pattern = AssetBuilderSDK::AssetBuilderPattern(AZStd::string("*.") + AnyAssetSourceExtensions[index++], AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
  44. });
  45. // setup builder descriptor
  46. AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
  47. builderDescriptor.m_name = AnyAssetBuilderJobKey;
  48. builderDescriptor.m_patterns.insert(builderDescriptor.m_patterns.end(), patterns.begin(), patterns.end());
  49. builderDescriptor.m_busId = azrtti_typeid<AnyAssetBuilder>();
  50. builderDescriptor.m_createJobFunction = AZStd::bind(&AnyAssetBuilder::CreateJobs, this,
  51. AZStd::placeholders::_1, AZStd::placeholders::_2);
  52. builderDescriptor.m_processJobFunction = AZStd::bind(&AnyAssetBuilder::ProcessJob, this,
  53. AZStd::placeholders::_1, AZStd::placeholders::_2);
  54. builderDescriptor.m_version = 10;
  55. BusConnect(builderDescriptor.m_busId);
  56. AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
  57. }
  58. AnyAssetBuilder::~AnyAssetBuilder()
  59. {
  60. BusDisconnect();
  61. }
  62. void AnyAssetBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
  63. {
  64. if (m_isShuttingDown)
  65. {
  66. response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
  67. return;
  68. }
  69. for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms)
  70. {
  71. AssetBuilderSDK::JobDescriptor descriptor;
  72. descriptor.m_jobKey = AnyAssetBuilderJobKey;
  73. descriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str());
  74. // [GFX TODO][ATOM-2830] Set 'm_critical' back to 'false' once proper fix for Atom startup issues are in
  75. descriptor.m_critical = true;
  76. response.m_createJobOutputs.push_back(descriptor);
  77. }
  78. response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
  79. }
  80. void AnyAssetBuilder::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response)
  81. {
  82. AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
  83. if (jobCancelListener.IsCancelled() || m_isShuttingDown)
  84. {
  85. response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
  86. return;
  87. }
  88. // Get serialization context
  89. SerializeContext* context = nullptr;
  90. ComponentApplicationBus::BroadcastResult(context, &ComponentApplicationBus::Events::GetSerializeContext);
  91. if (!context)
  92. {
  93. AZ_Assert(false, "No serialize context");
  94. return;
  95. }
  96. Outcome<AZStd::any, AZStd::string> loadResult = AZ::JsonSerializationUtils::LoadAnyObjectFromFile(request.m_fullPath);
  97. if (!loadResult.IsSuccess())
  98. {
  99. AZ_Error(AnyAssetBuilderName, false, "Failed to load file [%s] as an any asset", request.m_fullPath.c_str());
  100. AZ_Error(AnyAssetBuilderName, false, "Loading issues: %s", loadResult.GetError().data());
  101. response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
  102. return ;
  103. }
  104. AZStd::any loadedClass = loadResult.GetValue();
  105. auto loadedClassId = loadedClass.get_type_info().m_id;
  106. void* loadedInstance = AZStd::any_cast<void>(&loadedClass);
  107. // Apply converter if the source data class is a ConvertibleSource
  108. bool isConvertible = false;
  109. context->EnumerateBase(
  110. [&isConvertible](const AZ::SerializeContext::ClassData* classData, AZ::Uuid)
  111. {
  112. if (classData && classData->m_typeId == ConvertibleSource::TYPEINFO_Uuid())
  113. {
  114. isConvertible = true;
  115. }
  116. return true;
  117. },
  118. loadedClassId);
  119. AZStd::shared_ptr<void> convertedData;
  120. TypeId outputTypeId = loadedClassId;
  121. void* outputData = loadedInstance;
  122. if (isConvertible)
  123. {
  124. const ConvertibleSource* convertible = reinterpret_cast<const ConvertibleSource*>(loadedInstance);
  125. // convert and save the converted data to outputData and its type id to outputTypeId
  126. bool converted = convertible->Convert(outputTypeId, convertedData);
  127. if (!converted)
  128. {
  129. AZ_Error(AnyAssetBuilderName, false, "Failed to convert asset [%s]", request.m_fullPath.c_str());
  130. response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
  131. return;
  132. }
  133. outputData = convertedData.get();
  134. }
  135. // Get file name from source file path, then replace the extension to generate product file name
  136. // Note that we preserve the file extension since it is used during reflection
  137. AZStd::string destFileName;
  138. AzFramework::StringFunc::Path::GetFullFileName(request.m_fullPath.c_str(), destFileName);
  139. // Construct product full path
  140. AZStd::string destPath;
  141. AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), destFileName.c_str(), destPath, true);
  142. // Save the asset to binary format for production
  143. bool result = Utils::SaveObjectToFile(destPath, DataStream::ST_BINARY, outputData, outputTypeId, context);
  144. if (result == false)
  145. {
  146. AZ_Error(AnyAssetBuilderName, false, "Failed to save asset to %s", destPath.c_str());
  147. response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
  148. return;
  149. }
  150. // Success. Save output product(s) to response.
  151. // Note that we use the classId we found in the source file, unless it's a standard .azasset
  152. AZStd::string sourceFileExtension;
  153. AzFramework::StringFunc::Path::GetExtension(request.m_fullPath.c_str(), sourceFileExtension, false);
  154. auto destClassId = (sourceFileExtension == AnyAssetBuilderDefaultExtension) ? AnyAsset::RTTI_Type() : loadedClassId;
  155. AssetBuilderSDK::JobProduct jobProduct(destPath, destClassId, 0);
  156. if (AssetBuilderSDK::OutputObject(outputData, outputTypeId, destPath, destClassId, 0, jobProduct))
  157. {
  158. response.m_outputProducts.push_back(jobProduct);
  159. response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
  160. }
  161. }
  162. void AnyAssetBuilder::ShutDown()
  163. {
  164. m_isShuttingDown = true;
  165. }
  166. } // namespace RPI_Builder
  167. } // namespace AZ