Files
o3de/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Previewer/ImagePreviewer.cpp
T
Esteban Papp 1f9b284de2 Merge branch 'development' into cmake/SPEC-7179
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

# Conflicts:
#	Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.h
#	Code/Editor/Plugins/EditorCommon/EditorCommon_precompiled.h
#	Code/Editor/Plugins/EditorCommon/stdafx.cpp
#	Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h
#	Code/Editor/Plugins/PerforcePlugin/PerforcePlugin_precompiled.h
#	Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.h
#	Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.h
#	Code/Tools/AssetProcessor/native/precompiled.h
#	Code/Tools/Standalone/StandaloneTools_precompiled.h
#	Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.h
#	Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.h
#	Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/Mac/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/iOS/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.h
#	Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake
#	Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.h
#	Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Android/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Linux/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Mac/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Windows/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.h
#	Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
#	Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake
#	Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h
#	Gems/Blast/Code/Source/StdAfx.cpp
#	Gems/Camera/Code/Source/Camera_precompiled.h
#	Gems/EMotionFX/Code/Source/EMotionFX_precompiled.h
#	Gems/FastNoise/Code/Source/FastNoise_precompiled.h
#	Gems/Gestures/Code/Source/Gestures_precompiled.h
#	Gems/GradientSignal/Code/Source/GradientSignal_precompiled.h
#	Gems/GraphCanvas/Code/precompiled.h
#	Gems/ImGui/Code/Source/ImGui_precompiled.h
#	Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.h
#	Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.h
#	Gems/LmbrCentral/Code/Tests/ShapeGeometryUtilTest.cpp
#	Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.h
#	Gems/LyShine/Code/Source/Animation/LyShine_precompiled.h
#	Gems/LyShine/Code/Source/LyShine_precompiled.h
#	Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.h
#	Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.h
#	Gems/Maestro/Code/Source/Maestro_precompiled.h
#	Gems/MessagePopup/Code/Source/MessagePopup_precompiled.h
#	Gems/Metastream/Code/Source/Metastream_precompiled.h
#	Gems/Microphone/Code/Source/Microphone_precompiled.h
#	Gems/Multiplayer/Code/Source/Multiplayer_precompiled.h
#	Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.h
#	Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.h
#	Gems/PhysX/Code/Source/PhysX_precompiled.h
#	Gems/PhysX/Code/physx_unsupported_files.cmake
#	Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.h
#	Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.h
#	Gems/ScriptCanvas/Code/Editor/precompiled.h
#	Gems/ScriptCanvas/Code/Source/precompiled.h
#	Gems/ScriptCanvasDeveloper/Code/Source/precompiled.h
#	Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.h
#	Gems/ScriptEvents/Code/Source/precompiled.h
#	Gems/ScriptEvents/Code/Tests/Editor/EditorTests.cpp
#	Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.h
#	Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.h
#	Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.h
#	Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.h
#	Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.h
#	Gems/SurfaceData/Code/Source/SurfaceData_precompiled.h
#	Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.h
#	Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.h
#	Gems/Twitch/Code/Source/Twitch_precompiled.h
#	Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBox_precompiled.h
2021-07-16 15:42:37 -07:00

368 lines
12 KiB
C++

/*
* 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 <AzCore/PlatformDef.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <Source/Previewer/ImagePreviewer.h>
#include <Source/Previewer/ui_ImagePreviewer.h>
#include <Editor/EditorCommon.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
#include <AzCore/IO/FileIO.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <ImageLoader/ImageLoaders.h>
#include <Processing/ImageConvert.h>
#include <Processing/ImagePreview.h>
#include <Processing/ImageToProcess.h>
#include <Processing/Utils.h>
#include <Processing/ImageFlags.h>
#include <QString>
#include <QStringList>
AZ_POP_DISABLE_WARNING
namespace ImageProcessingAtom
{
static constexpr const int IMAGE_PREVIEWER_CHAR_WIDTH = 6;
ImagePreviewer::ImagePreviewer(QWidget* parent)
: Previewer(parent)
, m_ui(new Ui::ImagePreviewerClass())
{
m_ui->setupUi(this);
Clear();
}
ImagePreviewer::~ImagePreviewer()
{
AZ::SystemTickBus::Handler::BusDisconnect();
if (m_createDisplayTextureResult.isRunning())
{
m_createDisplayTextureResult.waitForFinished();
}
}
void ImagePreviewer::Clear() const
{
m_ui->m_texturePreviewWidget->hide();
m_ui->m_fileInfoCtrl->hide();
}
void ImagePreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
using namespace AzToolsFramework::AssetBrowser;
m_previewImageObject = nullptr;
Clear();
switch (entry->GetEntryType())
{
case AssetBrowserEntry::AssetEntryType::Source:
DisplaySource(static_cast<const SourceAssetBrowserEntry*>(entry));
break;
case AssetBrowserEntry::AssetEntryType::Product:
DisplayProduct(static_cast<const ProductAssetBrowserEntry*>(entry));
break;
}
}
const QString& ImagePreviewer::GetName() const
{
return m_name;
}
void ImagePreviewer::resizeEvent(QResizeEvent* event)
{
AZ_UNUSED(event);
m_ui->m_fileInfoCtrl->setText(WordWrap(m_fileinfo, m_ui->m_fileInfoCtrl->width() / IMAGE_PREVIEWER_CHAR_WIDTH));
}
// Get the preview of a sub-image specified by mip
QImage GetSubImagePreview(IImageObjectPtr image, uint32_t mip)
{
AZ::u8* imageBuf;
AZ::u32 pitch;
image->GetImagePointer(mip, imageBuf, pitch);
const AZ::u32 width = image->GetWidth(mip);
const AZ::u32 height = image->GetHeight(mip);
return QImage(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
}
// From image info string from ImageObject
void GetImageInfoString(IImageObjectPtr image, AZStd::string& output)
{
if (!image)
{
return;
}
output += AZStd::string::format("Dimensions: %dx%d\r\n", image->GetWidth(0), image->GetHeight(0));
AZ::u32 mipCount = image->GetMipCount();
output += AZStd::string::format("Mips: %d\r\n", mipCount);
AZ::u32 memSize = image->GetTextureMemory();
AZStd::string memSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(memSize);
output += AZStd::string::format("Size: %s\r\n", memSizeString.c_str());
CPixelFormats& pixelFormats = CPixelFormats::GetInstance();
EPixelFormat format = image->GetPixelFormat();
const PixelFormatInfo* info = pixelFormats.GetPixelFormatInfo(format);
if (info)
{
output += AZStd::string::format("Format: %s\r\n", info->szName);
}
AZStd::string colorSpaceString;
if (image->HasImageFlags(EIF_SRGBRead))
{
colorSpaceString = "sRGB";
}
else
{
// If the flag isn't set, then we don't know whether it's linear, or it's sRGB and the file format doesn't support a color space flag.
colorSpaceString = "Unknown";
}
output += AZStd::string::format("Color Space: %s\r\n", colorSpaceString.c_str());
if (image->HasImageFlags(EIF_Cubemap))
{
output += AZStd::string::format("Cubemap\r\n");
}
}
// From image info string from StreamingImageAsset
void GetImageInfoString(const AZ::Data::Asset<AZ::RPI::StreamingImageAsset>& imageAsset, AZStd::string& output)
{
if (!imageAsset.IsReady())
{
return;
}
AZ::RHI::ImageDescriptor descriptor = imageAsset->GetImageDescriptor();
output += AZStd::string("\r\nOverall image data...\r\n");
output += AZStd::string::format("Dimensions: %dx%d\r\n", descriptor.m_size.m_width, descriptor.m_size.m_height);
AZStd::string memSizeString;
if (imageAsset->GetTotalImageDataSize() > 0)
{
memSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(imageAsset->GetTotalImageDataSize());
}
else
{
memSizeString = "Unknown";
}
output += AZStd::string::format("Size: %s\r\n", memSizeString.c_str());
uint32_t totalMipCount = descriptor.m_mipLevels;
output += AZStd::string::format("Mips: %d\r\n", totalMipCount);
output += AZStd::string::format("Format: %s\r\n", AZ::RHI::ToString(descriptor.m_format));
//[GFX TODO] Put this back in, pending in my other CL
//output += AZStd::string::format("Color Space: %s\r\n", AZ::RHI::ToString(descriptor.m_colorSpace));
if (descriptor.m_isCubemap)
{
output += AZStd::string::format("Cubemap: true\r\n");
}
output += AZStd::string("\r\nBuilt-in mip chain...\r\n");
uint32_t builtInMipCount = imageAsset->GetTailMipChain().GetMipLevelCount();
output += AZStd::string::format("Mips: %d\r\n", builtInMipCount);
memSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(imageAsset->GetTailMipChain().GetImageDataSize());
output += AZStd::string::format("Size: %s\r\n", memSizeString.c_str());
AZ::RHI::Size builtInMipSizeA = imageAsset->GetTailMipChain().GetSubImageLayout(0).m_size;
AZStd::string mipChainDimensionString;
if (builtInMipCount == 1)
{
mipChainDimensionString = AZStd::string::format("%dx%d", builtInMipSizeA.m_width, builtInMipSizeA.m_height);
}
else
{
AZ::RHI::Size builtInMipSizeB = imageAsset->GetTailMipChain().GetSubImageLayout(builtInMipCount - 1).m_size;
mipChainDimensionString = AZStd::string::format("%dx%d .. %dx%d", builtInMipSizeA.m_width, builtInMipSizeA.m_height, builtInMipSizeB.m_width, builtInMipSizeB.m_height);
}
output += AZStd::string::format("Dimensions: %s\r\n", mipChainDimensionString.c_str());
output += AZStd::string("\r\n");
size_t additionalMipChainCount = imageAsset->GetMipChainCount() - 1;
output += AZStd::string::format("Additional Mip Chains: %zu\r\n", additionalMipChainCount);
}
void ImagePreviewer::DisplayProduct(const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* product)
{
m_ui->m_fileInfoCtrl->show();
m_fileinfo = QString::fromUtf8(product->GetName().c_str());
m_fileinfo += GetFileSize(product->GetRelativePath().c_str());
CreateAndDisplayTextureItemAsync(
[assetId = product->GetAssetId()]
() -> CreateDisplayTextureResult
{
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> imageAsset = Utils::LoadImageAsset(assetId);
IImageObjectPtr image = Utils::LoadImageFromImageAsset(imageAsset);
if (image)
{
// Add product image info
AZStd::string productInfo;
GetImageInfoString(imageAsset, productInfo);
QString fileInfo = QStringLiteral("\r\n");
fileInfo += productInfo.c_str();
return { ConvertImageForPreview(image), fileInfo };
}
else
{
return { nullptr, "" };
}
});
DisplayTextureItem();
}
void ImagePreviewer::DisplaySource(const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* source)
{
m_ui->m_fileInfoCtrl->show();
m_fileinfo = QString::fromUtf8(source->GetName().c_str());
m_fileinfo += GetFileSize(source->GetFullPath().c_str());
CreateAndDisplayTextureItemAsync(
[fullPath = source->GetFullPath()]
() -> CreateDisplayTextureResult
{
IImageObjectPtr image = IImageObjectPtr(LoadImageFromFile(fullPath));
if (image)
{
// Add source image info
AZStd::string sourceInfo;
GetImageInfoString(image, sourceInfo);
QString fileInfo = QStringLiteral("\r\n");
fileInfo += sourceInfo.c_str();
return { ConvertImageForPreview(image), fileInfo };
}
else
{
return { nullptr, "" };
}
});
DisplayTextureItem();
}
QString ImagePreviewer::GetFileSize(const char* path)
{
QString fileSizeStr;
AZ::u64 fileSizeResult = 0;
if (AZ::IO::FileIOBase::GetInstance()->Size(path, fileSizeResult))
{
AZStd::string fileSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(fileSizeResult);
fileSizeStr += tr("\r\nFile Size: ");
fileSizeStr += fileSizeString.c_str();
}
return fileSizeStr;
}
void ImagePreviewer::DisplayTextureItem()
{
m_ui->m_texturePreviewWidget->show();
if (m_previewImageObject)
{
// Display mip 0 by default
PreviewSubImage(0);
}
else
{
m_ui->m_previewImageCtrl->setPixmap(QPixmap());
}
m_ui->m_fileInfoCtrl->setText(WordWrap(m_fileinfo, m_ui->m_fileInfoCtrl->width() / IMAGE_PREVIEWER_CHAR_WIDTH));
updateGeometry();
}
template<class CreateFn>
void ImagePreviewer::CreateAndDisplayTextureItemAsync(CreateFn create)
{
AZ::SystemTickBus::Handler::BusConnect();
m_createDisplayTextureResult = QtConcurrent::run(AZStd::move(create));
}
void ImagePreviewer::OnSystemTick()
{
if (m_createDisplayTextureResult.isFinished())
{
CreateDisplayTextureResult result = m_createDisplayTextureResult.result();
m_previewImageObject = AZStd::move(result.first);
m_fileinfo += result.second;
AZ::SystemTickBus::Handler::BusDisconnect();
DisplayTextureItem();
}
}
void ImagePreviewer::PreviewSubImage(uint32_t mip)
{
QImage previewImage = GetSubImagePreview(m_previewImageObject, mip);
QPixmap pix = QPixmap::fromImage(previewImage);
m_ui->m_previewImageCtrl->setPixmap(pix);
m_ui->m_previewImageCtrl->updateGeometry();
}
QString ImagePreviewer::WordWrap(const QString& string, int maxLength)
{
QString result;
int length = 0;
for (auto c : string)
{
if (c == '\n')
{
length = 0;
}
else if (length > maxLength)
{
result.append('\n');
length = 0;
}
else
{
length++;
}
result.append(c);
}
return result;
}
}//namespace ImageProcessingAtom
#include <Source/Previewer/moc_ImagePreviewer.cpp>