diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index f1c41576ef..90499be8b8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -31,6 +31,11 @@ #include #include +#include + +#if defined(OPEN_IMAGE_IO_ENABLED) +#include +#endif namespace AZ { @@ -38,6 +43,41 @@ namespace AZ { AZ_ENUM_DEFINE_REFLECT_UTILITIES(FrameCaptureResult); +#if defined(OPEN_IMAGE_IO_ENABLED) + AZ_CVAR(unsigned int, + r_pngCompressionLevel, + 3, // A compression level of 3 seems like the best default in terms of file size and saving speeds + nullptr, + ConsoleFunctorFlags::Null, + "Sets the compression level for saving png screenshots. Valid values are from 0 to 8" + ); + + FrameCaptureOutputResult PngFrameCaptureOutput( + const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) + { + using namespace OIIO; + AZStd::unique_ptr out = ImageOutput::create(outputFilePath.c_str()); + if (out) + { + ImageSpec spec( + readbackResult.m_imageDescriptor.m_size.m_width, + readbackResult.m_imageDescriptor.m_size.m_height, + AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format) + ); + spec.attribute("png:compressionLevel", r_pngCompressionLevel); + + if (out->open(outputFilePath.c_str(), spec)) + { + out->write_image(TypeDesc::UINT8, readbackResult.m_dataBuffer->data()); + out->close(); + return FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt}; + } + } + + return FrameCaptureOutputResult{FrameCaptureResult::InternalError, "Unable to save frame capture output to " + outputFilePath}; + } +#endif + FrameCaptureOutputResult DdsFrameCaptureOutput( const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) { @@ -377,7 +417,6 @@ namespace AZ if (readbackResult.m_attachmentType == AZ::RHI::AttachmentType::Buffer) { // write buffer data to the data file - AZ::IO::FileIOStream fileStream(m_outputFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath); if (fileStream.IsOpen()) { @@ -418,6 +457,18 @@ namespace AZ m_result = ddsFrameCapture.m_result; m_latestCaptureInfo = ddsFrameCapture.m_errorMessage.value_or(""); } +#if defined(OPEN_IMAGE_IO_ENABLED) + else if (extension == "png") + { + AZStd::string folderPath; + AzFramework::StringFunc::Path::GetFolderPath(m_outputFilePath.c_str(), folderPath); + AZ::IO::SystemFile::CreateDir(folderPath.c_str()); + + const auto frameCaptureResult = PngFrameCaptureOutput(m_outputFilePath, readbackResult); + m_result = frameCaptureResult.m_result; + m_latestCaptureInfo = frameCaptureResult.m_errorMessage.value_or(""); + } +#endif else { m_latestCaptureInfo = AZStd::string::format("Only supports saving image to ppm or dds files"); diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake index f5b9ea77a2..b12b5de9ce 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake @@ -9,3 +9,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +set(LY_BUILD_DEPENDENCIES + PRIVATE + 3rdParty::OpenImageIO + 3rdParty::ilmbase +) + +# [GFX-TODO] Add macro defintion in OpenImageIO 3rd party find cmake file +set(LY_COMPILE_DEFINITIONS + PRIVATE + OPEN_IMAGE_IO_ENABLED +)