123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <ImageBuilderComponent.h>
- #include <AzCore/std/string/conversions.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzFramework/StringFunc/StringFunc.h>
- #include <AzFramework/IO/LocalFileIO.h>
- #include <AzCore/Debug/Trace.h>
- #include <BuilderSettings/BuilderSettingManager.h>
- #include <BuilderSettings/CubemapSettings.h>
- #include <ImageLoader/ImageLoaders.h>
- #include <Processing/ImageAssetProducer.h>
- #include <Processing/ImageConvert.h>
- #include <Processing/ImageToProcess.h>
- #include <Processing/PixelFormatInfo.h>
- #include <AzFramework/API/ApplicationAPI.h>
- #include <AzCore/Serialization/EditContextConstants.inl>
- #include <QFile>
- #include <AzQtComponents/Utilities/QtPluginPaths.h>
- #include <Atom/RPI.Reflect/Asset/AssetHandler.h>
- #include <Atom/RPI.Reflect/Image/StreamingImageAssetHandler.h>
- #include <Atom/RPI.Reflect/Image/ImageMipChainAsset.h>
- namespace ImageProcessingAtom
- {
- BuilderPluginComponent::BuilderPluginComponent()
- {
- // AZ Components should only initialize their members to null and empty in constructor
- // after construction, they may be deserialized from file.
- }
- BuilderPluginComponent::~BuilderPluginComponent()
- {
- }
- void BuilderPluginComponent::Init()
- {
- }
- void BuilderPluginComponent::Activate()
- {
- //load qt plugins for some image file formats support
- AzQtComponents::PrepareQtPaths();
- // create and initialize BuilderSettingManager once since it's will be used for image conversion
- BuilderSettingManager::CreateInstance();
- auto outcome = BuilderSettingManager::Instance()->LoadConfig();
- AZ_Error("Image Processing", outcome.IsSuccess(), "Failed to load Atom image builder settings.");
- if (!outcome.IsSuccess())
- {
- return;
- }
- // Activate is where you'd perform registration with other objects and systems.
- // Since we want to register our builder, we do that here:
- AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
- builderDescriptor.m_name = "Atom Image Builder";
- for (int i = 0; i < s_TotalSupportedImageExtensions; i++)
- {
- builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(s_SupportedImageExtensions[i], AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
- }
- builderDescriptor.m_busId = azrtti_typeid<ImageBuilderWorker>();
- builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
- builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
- builderDescriptor.m_version = 25; // [ATOM-16575]
- builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint();
- m_imageBuilder.BusConnect(builderDescriptor.m_busId);
- AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
- m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler<AZ::RPI::ImageMipChainAssetHandler>());
- m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler<AZ::RPI::StreamingImageAssetHandler>());
- ImageProcessingRequestBus::Handler::BusConnect();
- ImageBuilderRequestBus::Handler::BusConnect();
- }
- void BuilderPluginComponent::Deactivate()
- {
- ImageProcessingRequestBus::Handler::BusDisconnect();
- ImageBuilderRequestBus::Handler::BusDisconnect();
- m_imageBuilder.BusDisconnect();
- BuilderSettingManager::DestroyInstance();
- CPixelFormats::DestroyInstance();
- }
- void BuilderPluginComponent::Reflect(AZ::ReflectContext* context)
- {
- // components also get Reflect called automatically
- // this is your opportunity to perform static reflection or type registration of any types you want the serializer to know about
- if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
- {
- serialize->Class<BuilderPluginComponent, AZ::Component>()
- ->Version(0)
- ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector<AZ::Crc32>({ AssetBuilderSDK::ComponentTags::AssetBuilder }))
- ;
- }
- BuilderSettingManager::Reflect(context);
- BuilderSettings::Reflect(context);
- MultiplatformPresetSettings::Reflect(context);
- PresetSettings::Reflect(context);
- CubemapSettings::Reflect(context);
- MipmapSettings::Reflect(context);
- TextureSettings::Reflect(context);
- }
- void BuilderPluginComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
- {
- provided.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e));
- }
- void BuilderPluginComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
- {
- incompatible.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e));
- }
- IImageObjectPtr BuilderPluginComponent::LoadImage(const AZStd::string& filePath)
- {
- return IImageObjectPtr(LoadImageFromFile(filePath));
- }
- IImageObjectPtr BuilderPluginComponent::LoadImagePreview(const AZStd::string& filePath)
- {
- IImageObjectPtr image(LoadImageFromFile(filePath));
- if (image)
- {
- ImageToProcess imageToProcess(image);
- imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
- return imageToProcess.Get();
- }
- return image;
- }
- IImageObjectPtr BuilderPluginComponent::CreateImage(
- AZ::u32 width,
- AZ::u32 height,
- AZ::u32 maxMipCount,
- EPixelFormat pixelFormat)
- {
- IImageObjectPtr image(IImageObject::CreateImage(width, height, maxMipCount, pixelFormat));
- return image;
- }
- AZStd::vector<AssetBuilderSDK::JobProduct> BuilderPluginComponent::ConvertImageObject(
- IImageObjectPtr imageObject,
- const AZStd::string& presetName,
- const AZStd::string& platformName,
- const AZStd::string& outputDir,
- const AZ::Data::AssetId& sourceAssetId,
- const AZStd::string& sourceAssetName)
- {
- AZStd::vector<AssetBuilderSDK::JobProduct> outProducts;
- AZStd::string_view presetFilePath;
- const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(PresetName(presetName), platformName, &presetFilePath);
- if (preset == nullptr)
- {
- AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str());
- return outProducts;
- }
- AZStd::unique_ptr<ImageConvertProcessDescriptor> desc = AZStd::make_unique<ImageConvertProcessDescriptor>();
- TextureSettings& textureSettings = desc->m_textureSetting;
- textureSettings.m_preset = preset->m_name;
- desc->m_inputImage = imageObject;
- desc->m_presetSetting = *preset;
- desc->m_isPreview = false;
- desc->m_platform = platformName;
- desc->m_filePath = presetFilePath;
- desc->m_isStreaming = BuilderSettingManager::Instance()->GetBuilderSetting(platformName)->m_enableStreaming;
- desc->m_imageName = sourceAssetName;
- desc->m_outputFolder = outputDir;
- desc->m_sourceAssetId = sourceAssetId;
-
- // Create an image convert process
- ImageConvertProcess process(AZStd::move(desc));
- process.ProcessAll();
- bool result = process.IsSucceed();
- if (result)
- {
- process.GetAppendOutputProducts(outProducts);
- }
- return outProducts;
- }
- bool BuilderPluginComponent::DoesSupportPlatform(const AZStd::string& platformId)
- {
- return ImageProcessingAtom::BuilderSettingManager::Instance()->DoesSupportPlatform(platformId);
- }
- bool BuilderPluginComponent::IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName)
- {
- AZStd::string_view filePath;
- const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(PresetName(presetName), platformName, &filePath);
- if (preset == nullptr)
- {
- AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str());
- return false;
- }
- const PixelFormatInfo* info = CPixelFormats::GetInstance().GetPixelFormatInfo(preset->m_pixelFormat);
- return info->bSquarePow2;
- }
- void ImageBuilderWorker::ShutDown()
- {
- // it is important to note that this will be called on a different thread than your process job thread
- m_isShuttingDown = true;
- }
- // this happens early on in the file scanning pass
- // this function should consistently always create the same jobs, and should do no checking whether the job is up to date or not - just be consistent.
- void ImageBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
- {
- if (m_isShuttingDown)
- {
- response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
- return;
- }
- // Get the extension of the file
- AZStd::string ext;
- AzFramework::StringFunc::Path::GetExtension(request.m_sourceFile.c_str(), ext, false);
- AZStd::to_upper(ext.begin(), ext.end());
- // We process the same file for all platforms
- for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms)
- {
- if (ImageProcessingAtom::BuilderSettingManager::Instance()->DoesSupportPlatform(platformInfo.m_identifier))
- {
- AssetBuilderSDK::JobDescriptor descriptor;
- descriptor.m_jobKey = ext + " Atom Compile";
- descriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str());
- descriptor.m_critical = false;
- response.m_createJobOutputs.push_back(descriptor);
- }
- }
- response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
- return;
- }
- // later on, this function will be called for jobs that actually need doing.
- // the request will contain the CreateJobResponse you constructed earlier, including any keys and values you placed into the hash table
- void ImageBuilderWorker::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response)
- {
- // Before we begin, let's make sure we are not meant to abort.
- AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
- AZStd::vector<AZStd::string> productFilepaths;
- bool imageProcessingSuccessful = false;
- bool needConversion = true;
- // Do conversion and get exported file's path
- if (needConversion)
- {
- AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Performing image conversion: %s\n", request.m_fullPath.c_str());
- ImageConvertProcess* process = CreateImageConvertProcess(request.m_fullPath, request.m_tempDirPath,
- request.m_jobDescription.GetPlatformIdentifier(), response.m_outputProducts);
- if (process != nullptr)
- {
- //the process can be stopped if the job is cancelled or the worker is shutting down
- while (!process->IsFinished() && !m_isShuttingDown && !jobCancelListener.IsCancelled())
- {
- process->UpdateProcess();
- }
- //get process result
- imageProcessingSuccessful = process->IsSucceed();
- if (imageProcessingSuccessful)
- {
- process->GetAppendOutputProducts(response.m_outputProducts);
- }
- delete process;
- }
- else
- {
- imageProcessingSuccessful = false;
- }
- }
- if (imageProcessingSuccessful)
- {
- response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
- }
- else
- {
- if (m_isShuttingDown)
- {
- AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str());
- response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
- }
- else if (jobCancelListener.IsCancelled())
- {
- AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled was requested for job %s.\n", request.m_fullPath.c_str());
- response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
- }
- else
- {
- AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Unexpected error during processing job %s.\n", request.m_fullPath.c_str());
- response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
- }
- }
- }
- } // namespace ImageProcessingAtom
|