3
0

ImageProcessingSystemComponent.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
  9. #include <AzCore/Component/ComponentApplicationBus.h>
  10. #include <AzCore/Component/Entity.h>
  11. #include <AzCore/IO/FileIO.h>
  12. #include <AzCore/NativeUI/NativeUIRequests.h>
  13. #include <AzCore/Serialization/SerializeContext.h>
  14. #include <AzCore/Serialization/EditContext.h>
  15. #include <AzCore/std/string/wildcard.h>
  16. #include <AzQtComponents/Components/Widgets/FileDialog.h>
  17. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  18. #include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
  19. #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
  20. #include <AzFramework/Asset/AssetSystemBus.h>
  21. #include <AzFramework/StringFunc/StringFunc.h>
  22. #include <BuilderSettings/BuilderSettingManager.h>
  23. #include <Editor/TexturePropertyEditor.h>
  24. #include <ImageLoader/ImageLoaders.h>
  25. #include <Processing/ImageAssetProducer.h>
  26. #include <Processing/ImageConvert.h>
  27. #include <Processing/ImagePreview.h>
  28. #include <Processing/ImageToProcess.h>
  29. #include <Processing/Utils.h>
  30. #include "ImageProcessingSystemComponent.h"
  31. #include <QFileDialog>
  32. #include <QMenu>
  33. namespace ImageProcessingAtom
  34. {
  35. void ImageProcessingSystemComponent::Reflect(AZ::ReflectContext* context)
  36. {
  37. if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
  38. {
  39. serialize->Class<ImageProcessingSystemComponent, AZ::Component>()
  40. ->Version(0)
  41. ;
  42. }
  43. }
  44. void ImageProcessingSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  45. {
  46. provided.push_back(AZ_CRC("AtomImageBuilderService", 0x76ded592));
  47. }
  48. void ImageProcessingSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  49. {
  50. incompatible.push_back(AZ_CRC("AtomImageBuilderService", 0x76ded592));
  51. }
  52. void ImageProcessingSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  53. {
  54. (void)required;
  55. }
  56. void ImageProcessingSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  57. {
  58. (void)dependent;
  59. }
  60. void ImageProcessingSystemComponent::Init()
  61. {
  62. m_previewerFactory.reset(new ImagePreviewerFactory);
  63. }
  64. void ImageProcessingSystemComponent::Activate()
  65. {
  66. // Note: the editor initialization will only report incompatible components if we have two system components are incompatible.
  67. // It won't interrupt the initialization. And the CSystem::Init would continue and report totally irrelevant message
  68. // due to cinematic system pointer was empty since the ActivateEntities returned early
  69. // This is a temporary solution until we have the proper system for gem incompatible mechanism in place ( LY-105408)
  70. // Here it would pop out a message box if we found the LY ImageProcessingSystemComponent was reflected.
  71. AZ::SerializeContext* serializeContext = nullptr;
  72. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  73. if (serializeContext->FindClassData(AZ::Uuid("{13B1EB88-316F-4D44-B59C-886F023A5A58}")))
  74. {
  75. AZ::OSString errorMsg = "Incompatible gem detected. Please disable ImageProcessing Gem for Atom project";
  76. AZ_Error("ImageProcessingAtom", false, errorMsg.data());
  77. AZ::NativeUI::NativeUIRequestBus::Broadcast(&AZ::NativeUI::NativeUIRequestBus::Events::DisplayOkDialog, "", errorMsg.c_str(), false);
  78. return;
  79. }
  80. // Call to allocate BuilderSettingManager
  81. BuilderSettingManager::CreateInstance();
  82. ImageProcessingAtomEditor::ImageProcessingEditorRequestBus::Handler::BusConnect();
  83. AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
  84. AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect();
  85. ImageProcessingRequestBus::Handler::BusConnect();
  86. }
  87. void ImageProcessingSystemComponent::Deactivate()
  88. {
  89. ImageProcessingRequestBus::Handler::BusDisconnect();
  90. AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect();
  91. ImageProcessingAtomEditor::ImageProcessingEditorRequestBus::Handler::BusDisconnect();
  92. AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
  93. // Deallocate BuilderSettingManager
  94. BuilderSettingManager::DestroyInstance();
  95. CPixelFormats::DestroyInstance();
  96. }
  97. void ImageProcessingSystemComponent::OpenSourceTextureFile(const AZ::Uuid& textureSourceID)
  98. {
  99. ImageProcessingAtomEditor::TexturePropertyEditor editor(textureSourceID, QApplication::activeWindow());
  100. editor.exec();
  101. }
  102. IImageObjectPtr ImageProcessingSystemComponent::LoadImage(const AZStd::string& filePath)
  103. {
  104. return IImageObjectPtr(LoadImageFromFile(filePath));
  105. }
  106. IImageObjectPtr ImageProcessingSystemComponent::LoadImagePreview(const AZStd::string& filePath)
  107. {
  108. IImageObjectPtr image(LoadImageFromFile(filePath));
  109. if (image)
  110. {
  111. ImageToProcess imageToProcess(image);
  112. imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
  113. return imageToProcess.Get();
  114. }
  115. return image;
  116. }
  117. void ImageProcessingSystemComponent::AddContextMenuActions(QWidget* /*caller*/, QMenu* menu, const AZStd::vector<const AzToolsFramework::AssetBrowser::AssetBrowserEntry*>& entries)
  118. {
  119. // Load Texture Settings
  120. static bool isSettingLoaded = false;
  121. if (!isSettingLoaded)
  122. {
  123. // Load the preset settings before editor open
  124. auto outcome = ImageProcessingAtom::BuilderSettingManager::Instance()->LoadConfig();
  125. if (outcome.IsSuccess())
  126. {
  127. isSettingLoaded = true;
  128. }
  129. else
  130. {
  131. AZ_Error("Image Processing", false, "Failed to load default preset settings!");
  132. return;
  133. }
  134. }
  135. // Register right click menu
  136. using namespace AzToolsFramework::AssetBrowser;
  137. auto entryIt = AZStd::find_if
  138. (
  139. entries.begin(),
  140. entries.end(),
  141. [](const AssetBrowserEntry* entry) -> bool
  142. {
  143. return entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source
  144. || entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product;
  145. }
  146. );
  147. if (entryIt == entries.end())
  148. {
  149. return;
  150. }
  151. if ((*entryIt)->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
  152. {
  153. // For supported source image files, add menu item to open texture setting editor
  154. const SourceAssetBrowserEntry* source = azrtti_cast<const SourceAssetBrowserEntry*>(*entryIt);
  155. if (!HandlesSource(source))
  156. {
  157. return;
  158. }
  159. AZ::Uuid sourceId = source->GetSourceUuid();
  160. if (!sourceId.IsNull())
  161. {
  162. menu->addAction("Edit Texture Settings...", [sourceId, this]()
  163. {
  164. OpenSourceTextureFile(sourceId);
  165. });
  166. }
  167. }
  168. else if ((*entryIt)->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product)
  169. {
  170. // For product which is streaming image asset, add menu item to save it to a dds file
  171. const ProductAssetBrowserEntry* product = azrtti_cast<const ProductAssetBrowserEntry*>(*entryIt);
  172. if (product->GetAssetType() == azrtti_typeid<AZ::RPI::StreamingImageAsset>())
  173. {
  174. AZ::Data::AssetId assetId = product->GetAssetId();
  175. menu->addAction("Save as DDS...", [assetId, this]()
  176. {
  177. QString filePath = AzQtComponents::FileDialog::GetSaveFileName(nullptr, QString("Save to file"), m_lastSavedPath, QString("DDS file (*.dds)"));
  178. if (filePath.isEmpty())
  179. {
  180. return;
  181. }
  182. if (SaveStreamingImageAssetToDDS(assetId, filePath.toUtf8().data()))
  183. {
  184. AZ_Printf("Image Processing", "Image was saved to a dds file %s", filePath.toUtf8().data());
  185. m_lastSavedPath = filePath;
  186. }
  187. });
  188. }
  189. }
  190. }
  191. bool ImageProcessingSystemComponent::HandlesSource(const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry) const
  192. {
  193. AZStd::string targetExtension = entry->GetExtension();
  194. for (int i = 0; i < s_TotalSupportedImageExtensions; i++)
  195. {
  196. if (AZStd::wildcard_match(s_SupportedImageExtensions[i], targetExtension.c_str()))
  197. {
  198. return true;
  199. }
  200. }
  201. return false;
  202. }
  203. const AzToolsFramework::AssetBrowser::PreviewerFactory* ImageProcessingSystemComponent::GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
  204. {
  205. return m_previewerFactory->IsEntrySupported(entry) ? m_previewerFactory.get() : nullptr;
  206. }
  207. bool ImageProcessingSystemComponent::SaveStreamingImageAssetToDDS(const AZ::Data::AssetId& assetId, AZStd::string_view filePath)
  208. {
  209. IImageObjectPtr loadedImage = Utils::LoadImageFromImageAsset(assetId);
  210. if (!loadedImage)
  211. {
  212. AZ_Warning("ImageProcessingSystemComponent", false, "Failed to load product asset");
  213. return false;
  214. }
  215. if (!Utils::SaveImageToDdsFile(loadedImage, filePath))
  216. {
  217. AZ_Warning("ImageProcessingSystemComponent", false, "Failed to save image to dds file %s", filePath.data());
  218. return false;
  219. }
  220. return true;
  221. }
  222. } // namespace ImageProcessingAtom