Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <Atom/Utils/DdsFile.h>
|
||||
#include <Atom/Utils/PpmFile.h>
|
||||
#include <Atom/Utils/PngFile.h>
|
||||
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <AzCore/Jobs/JobFunction.h>
|
||||
@@ -34,21 +35,12 @@
|
||||
#include <AzCore/Preprocessor/EnumReflectUtils.h>
|
||||
#include <AzCore/Console/Console.h>
|
||||
|
||||
#if defined(OPEN_IMAGE_IO_ENABLED)
|
||||
// OpenImageIO/fmath.h(2271,5): error C4777: 'fprintf' : format string '%zd' requires an argument of type 'unsigned __int64', but variadic
|
||||
// argument 5 has type 'OpenImageIO_v2_1::span_strided<const float,-1>::index_type'
|
||||
AZ_PUSH_DISABLE_WARNING(4777, "-Wunknown-warning-option")
|
||||
#include <OpenImageIO/imageio.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
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
|
||||
@@ -97,28 +89,22 @@ namespace AZ
|
||||
jobCompletion.StartAndWaitForCompletion();
|
||||
}
|
||||
|
||||
using namespace OIIO;
|
||||
AZStd::unique_ptr<ImageOutput> out = ImageOutput::create(outputFilePath.c_str());
|
||||
if (out)
|
||||
{
|
||||
ImageSpec spec(
|
||||
readbackResult.m_imageDescriptor.m_size.m_width,
|
||||
readbackResult.m_imageDescriptor.m_size.m_height,
|
||||
numChannels
|
||||
);
|
||||
spec.attribute("png:compressionLevel", r_pngCompressionLevel);
|
||||
Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer);
|
||||
|
||||
if (out->open(outputFilePath.c_str(), spec))
|
||||
{
|
||||
out->write_image(TypeDesc::UINT8, buffer->data());
|
||||
out->close();
|
||||
return FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt};
|
||||
}
|
||||
Utils::PngFile::SaveSettings saveSettings;
|
||||
saveSettings.m_compressionLevel = r_pngCompressionLevel;
|
||||
// We should probably strip alpha to save space, especially for automated test screenshots. Alpha is left in to maintain
|
||||
// prior behavior, changing this is out of scope for the current task. Note, it would have bit of a cascade effect where
|
||||
// AtomSampleViewer's ScriptReporter assumes an RGBA image.
|
||||
saveSettings.m_stripAlpha = false;
|
||||
|
||||
if(image && image.Save(outputFilePath.c_str(), saveSettings))
|
||||
{
|
||||
return FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt};
|
||||
}
|
||||
|
||||
return FrameCaptureOutputResult{FrameCaptureResult::InternalError, "Unable to save frame capture output to " + outputFilePath};
|
||||
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)
|
||||
@@ -502,7 +488,6 @@ namespace AZ
|
||||
m_result = ddsFrameCapture.m_result;
|
||||
m_latestCaptureInfo = ddsFrameCapture.m_errorMessage.value_or("");
|
||||
}
|
||||
#if defined(OPEN_IMAGE_IO_ENABLED)
|
||||
else if (extension == "png")
|
||||
{
|
||||
if (readbackResult.m_imageDescriptor.m_format == RHI::Format::R8G8B8A8_UNORM ||
|
||||
@@ -523,7 +508,6 @@ namespace AZ
|
||||
m_result = FrameCaptureResult::UnsupportedFormat;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
m_latestCaptureInfo = AZStd::string::format("Only supports saving image to ppm or dds files");
|
||||
|
||||
@@ -12,12 +12,5 @@ endif()
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ ly_add_target(
|
||||
Gem::Atom_RHI.Public
|
||||
PUBLIC
|
||||
Gem::Atom_RHI.Reflect
|
||||
3rdParty::libpng
|
||||
)
|
||||
|
||||
################################################################################
|
||||
@@ -43,6 +44,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzFramework
|
||||
Gem::Atom_Utils.Static
|
||||
)
|
||||
ly_add_googletest(
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AtomCore/std/containers/array_view.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
#include <Atom/RHI.Reflect/Size.h>
|
||||
#include <Atom/RHI.Reflect/Format.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
//! This is a light wrapper class for libpng, to load and save .png files.
|
||||
//! Functionality is limited, feel free to add more features as needed.
|
||||
class PngFile
|
||||
{
|
||||
public:
|
||||
using ErrorHandler = AZStd::function<void(const char*)>;
|
||||
|
||||
struct LoadSettings
|
||||
{
|
||||
ErrorHandler m_errorHandler{}; //!< optional callback function describing any errors that are encountered
|
||||
bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB
|
||||
LoadSettings() {}; // clang errors out if this is not provided.
|
||||
};
|
||||
|
||||
struct SaveSettings
|
||||
{
|
||||
ErrorHandler m_errorHandler{}; //!< optional callback function describing any errors that are encountered
|
||||
bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB
|
||||
int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h
|
||||
SaveSettings() {}; // clang errors out if this is not provided.
|
||||
};
|
||||
|
||||
// To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel.
|
||||
enum class Format
|
||||
{
|
||||
Unknown,
|
||||
RGB,
|
||||
RGBA
|
||||
};
|
||||
|
||||
//! @return the loaded PngFile or an invalid PngFile if there was an error.
|
||||
static PngFile Load(const char* path, LoadSettings loadSettings = {});
|
||||
|
||||
//! Create a PngFile from an RHI data buffer.
|
||||
//! @param size the dimensions of the image (m_depth is not used, assumed to be 1)
|
||||
//! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation.
|
||||
//! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters.
|
||||
//! @param errorHandler optional callback function describing any errors that are encountered
|
||||
//! @return the created PngFile or an invalid PngFile if there was an error.
|
||||
static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::array_view<uint8_t> data, ErrorHandler errorHandler = {});
|
||||
static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::vector<uint8_t>&& data, ErrorHandler errorHandler = {});
|
||||
|
||||
PngFile() = default;
|
||||
AZ_DEFAULT_MOVE(PngFile)
|
||||
|
||||
//! @return true if the save operation was successful
|
||||
bool Save(const char* path, SaveSettings saveSettings = {});
|
||||
|
||||
bool IsValid() const;
|
||||
operator bool() const { return IsValid(); }
|
||||
|
||||
uint32_t GetWidth() const { return m_width; }
|
||||
uint32_t GetHeight() const { return m_height; }
|
||||
|
||||
Format GetBufferFormat() const { return m_bufferFormat; }
|
||||
const AZStd::vector<uint8_t>& GetBuffer() const { return m_buffer; }
|
||||
|
||||
//! Returns a r-value reference that can be moved. This will invalidate the PngFile.
|
||||
AZStd::vector<uint8_t>&& TakeBuffer();
|
||||
|
||||
private:
|
||||
AZ_DEFAULT_COPY(PngFile)
|
||||
|
||||
static const int HeaderSize = 8;
|
||||
|
||||
static void DefaultErrorHandler(const char* message);
|
||||
|
||||
uint32_t m_width = 0;
|
||||
uint32_t m_height = 0;
|
||||
int32_t m_bitDepth = 0;
|
||||
|
||||
Format m_bufferFormat = Format::Unknown;
|
||||
AZStd::vector<uint8_t> m_buffer;
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* 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 <Atom/Utils/PngFile.h>
|
||||
#include <png.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void PngImage_user_error_fn(png_structp png_ptr, png_const_charp error_msg)
|
||||
{
|
||||
PngFile::ErrorHandler* errorHandler = reinterpret_cast<PngFile::ErrorHandler*>(png_get_error_ptr(png_ptr));
|
||||
(*errorHandler)(error_msg);
|
||||
}
|
||||
|
||||
void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg)
|
||||
{
|
||||
AZ_Warning("PngFile", false, "%s", warning_msg);
|
||||
}
|
||||
}
|
||||
|
||||
PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view<uint8_t> data, ErrorHandler errorHandler)
|
||||
{
|
||||
return Create(size, format, AZStd::vector<uint8_t>{data.begin(), data.end()}, errorHandler);
|
||||
}
|
||||
|
||||
PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::vector<uint8_t>&& data, ErrorHandler errorHandler)
|
||||
{
|
||||
if (!errorHandler)
|
||||
{
|
||||
errorHandler = [](const char* message) { DefaultErrorHandler(message); };
|
||||
}
|
||||
|
||||
PngFile image;
|
||||
|
||||
if (RHI::Format::R8G8B8A8_UNORM == format)
|
||||
{
|
||||
if (size.m_width * size.m_height * 4 == data.size())
|
||||
{
|
||||
image.m_width = size.m_width;
|
||||
image.m_height = size.m_height;
|
||||
image.m_bitDepth = 8;
|
||||
image.m_bufferFormat = PngFile::Format::RGBA;
|
||||
image.m_buffer = AZStd::move(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
errorHandler("Invalid arguments. Buffer size does not match the image dimensions.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorHandler(AZStd::string::format("Cannot create PngFile with unsupported format %s", AZ::RHI::ToString(format)).c_str());
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
PngFile PngFile::Load(const char* path, LoadSettings loadSettings)
|
||||
{
|
||||
if (!loadSettings.m_errorHandler)
|
||||
{
|
||||
loadSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not load file '%s'. %s", path, message).c_str()); };
|
||||
}
|
||||
|
||||
// For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3
|
||||
|
||||
FILE* fp = NULL;
|
||||
azfopen(&fp, path, "rb"); // return type differs across platforms so can't do inside if
|
||||
if (!fp)
|
||||
{
|
||||
loadSettings.m_errorHandler("Cannot open file.");
|
||||
return {};
|
||||
}
|
||||
|
||||
png_byte header[HeaderSize] = {};
|
||||
|
||||
if (fread(header, 1, HeaderSize, fp) != HeaderSize)
|
||||
{
|
||||
fclose(fp);
|
||||
loadSettings.m_errorHandler("Invalid png header.");
|
||||
return {};
|
||||
}
|
||||
|
||||
bool isPng = !png_sig_cmp(header, 0, HeaderSize);
|
||||
if (!isPng)
|
||||
{
|
||||
fclose(fp);
|
||||
loadSettings.m_errorHandler("Invalid png header.");
|
||||
return {};
|
||||
}
|
||||
|
||||
png_voidp user_error_ptr = &loadSettings.m_errorHandler;
|
||||
png_error_ptr user_error_fn = PngImage_user_error_fn;
|
||||
png_error_ptr user_warning_fn = PngImage_user_warning_fn;
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn);
|
||||
if (!png_ptr)
|
||||
{
|
||||
fclose(fp);
|
||||
loadSettings.m_errorHandler("png_create_read_struct failed.");
|
||||
return {};
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
fclose(fp);
|
||||
loadSettings.m_errorHandler("png_create_info_struct failed.");
|
||||
return {};
|
||||
}
|
||||
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (!end_info)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
fclose(fp);
|
||||
loadSettings.m_errorHandler("png_create_info_struct failed.");
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4611, "-Wunknown-warning-option") // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
fclose(fp);
|
||||
// We don't report an error message here because the user_error_fn should have done that already.
|
||||
return {};
|
||||
}
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
png_set_sig_bytes(png_ptr, HeaderSize);
|
||||
|
||||
png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0);
|
||||
|
||||
// To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel
|
||||
int png_transforms = PNG_TRANSFORM_PACKING | // Expand 1, 2 and 4-bit samples to bytes
|
||||
PNG_TRANSFORM_STRIP_16 | // Reduce 16 bit samples to 8 bits
|
||||
PNG_TRANSFORM_GRAY_TO_RGB;
|
||||
|
||||
if (loadSettings.m_stripAlpha)
|
||||
{
|
||||
png_transforms |= PNG_TRANSFORM_STRIP_ALPHA;
|
||||
}
|
||||
|
||||
png_read_png(png_ptr, info_ptr, png_transforms, NULL);
|
||||
|
||||
// Note that libpng will allocate row_pointers for us. If we want to manage the memory ourselves, we need to call png_set_rows.
|
||||
// In that case we would have to use the low level interface: png_read_info, png_read_image, and png_read_end.
|
||||
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
|
||||
|
||||
PngFile pngFile;
|
||||
|
||||
int colorType = 0;
|
||||
|
||||
png_get_IHDR(png_ptr, info_ptr, &pngFile.m_width, &pngFile.m_height, &pngFile.m_bitDepth, &colorType, NULL, NULL, NULL);
|
||||
|
||||
uint32_t bytesPerPixel = 0;
|
||||
|
||||
switch (colorType)
|
||||
{
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
pngFile.m_bufferFormat = PngFile::Format::RGB;
|
||||
bytesPerPixel = 3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGBA:
|
||||
pngFile.m_bufferFormat = PngFile::Format::RGBA;
|
||||
bytesPerPixel = 4;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
// Handles cases where the image uses 1, 2, or 4 bit samples.
|
||||
// Note bytesPerPixel is 3 because we use PNG_TRANSFORM_PACKING
|
||||
pngFile.m_bufferFormat = PngFile::Format::RGB;
|
||||
bytesPerPixel = 3;
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel");
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
fclose(fp);
|
||||
loadSettings.m_errorHandler("Unsupported pixel format.");
|
||||
return {};
|
||||
}
|
||||
|
||||
// In the future we could use the low-level interface to avoid copying the image (and provide progress callbacks)
|
||||
pngFile.m_buffer.set_capacity(pngFile.m_width * pngFile.m_height * bytesPerPixel);
|
||||
for (uint32_t rowIndex = 0; rowIndex < pngFile.m_height; ++rowIndex)
|
||||
{
|
||||
png_bytep row = row_pointers[rowIndex];
|
||||
pngFile.m_buffer.insert(pngFile.m_buffer.end(), row, row + (pngFile.m_width * bytesPerPixel));
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
fclose(fp);
|
||||
return pngFile;
|
||||
}
|
||||
|
||||
bool PngFile::Save(const char* path, SaveSettings saveSettings)
|
||||
{
|
||||
if (!saveSettings.m_errorHandler)
|
||||
{
|
||||
saveSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not save file '%s'. %s", path, message).c_str()); };
|
||||
}
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
saveSettings.m_errorHandler("This PngFile is invalid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4
|
||||
|
||||
FILE* fp = NULL;
|
||||
azfopen(&fp, path, "wb"); // return type differs across platforms so can't do inside if
|
||||
if (!fp)
|
||||
{
|
||||
saveSettings.m_errorHandler("Cannot open file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_voidp user_error_ptr = &saveSettings.m_errorHandler;
|
||||
png_error_ptr user_error_fn = PngImage_user_error_fn;
|
||||
png_error_ptr user_warning_fn = PngImage_user_warning_fn;
|
||||
|
||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn);
|
||||
if (!png_ptr)
|
||||
{
|
||||
fclose(fp);
|
||||
saveSettings.m_errorHandler("png_create_write_struct failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
{
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
fclose(fp);
|
||||
saveSettings.m_errorHandler("png_destroy_write_struct failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4611, "-Wunknown-warning-option") // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(fp);
|
||||
// We don't report an error message here because the user_error_fn should have done that already.
|
||||
return false;
|
||||
}
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
int colorType = 0;
|
||||
if (saveSettings.m_stripAlpha || m_bufferFormat == PngFile::Format::RGB)
|
||||
{
|
||||
colorType = PNG_COLOR_TYPE_RGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
colorType = PNG_COLOR_TYPE_RGBA;
|
||||
}
|
||||
|
||||
int transforms = PNG_TRANSFORM_IDENTITY;
|
||||
if (saveSettings.m_stripAlpha && m_bufferFormat == PngFile::Format::RGBA)
|
||||
{
|
||||
transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER;
|
||||
}
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_set_compression_level(png_ptr, saveSettings.m_compressionLevel);
|
||||
|
||||
const uint32_t bytesPerPixel = (m_bufferFormat == PngFile::Format::RGB) ? 3 : 4;
|
||||
|
||||
AZStd::vector<uint8_t*> rows;
|
||||
rows.reserve(m_height);
|
||||
for (uint32_t i = 0; i < m_height; ++i)
|
||||
{
|
||||
rows.push_back(m_buffer.begin() + m_width * bytesPerPixel * i);
|
||||
}
|
||||
|
||||
png_set_rows(png_ptr, info_ptr, rows.begin());
|
||||
|
||||
png_write_png(png_ptr, info_ptr, transforms, NULL);
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PngFile::DefaultErrorHandler(const char* message)
|
||||
{
|
||||
AZ_Error("PngFile", false, "%s", message);
|
||||
}
|
||||
|
||||
bool PngFile::IsValid() const
|
||||
{
|
||||
return
|
||||
!m_buffer.empty() &&
|
||||
m_width > 0 &&
|
||||
m_height > 0 &&
|
||||
m_bitDepth > 0;
|
||||
}
|
||||
|
||||
AZStd::vector<uint8_t>&& PngFile::TakeBuffer()
|
||||
{
|
||||
return AZStd::move(m_buffer);
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
}// namespace AZ
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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 <Atom/Utils/PngFile.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/Math/Color.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace AZ::Utils;
|
||||
|
||||
class PngFileTests
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
protected:
|
||||
AZ::IO::Path m_testImageFolder;
|
||||
AZ::IO::Path m_tempPngFilePath;
|
||||
AZStd::vector<uint8_t> m_primaryColors3x1;
|
||||
AZStd::unique_ptr<AZ::IO::FileIOBase> m_localFileIO;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_testImageFolder = AZ::IO::Path(AZ::Test::GetEngineRootPath()) / AZ::IO::Path("Gems/Atom/Utils/Code/Tests/PngTestImages", '/');
|
||||
|
||||
m_tempPngFilePath = m_testImageFolder / "temp.png";
|
||||
|
||||
m_localFileIO.reset(aznew AZ::IO::LocalFileIO());
|
||||
AZ::IO::FileIOBase::SetInstance(m_localFileIO.get());
|
||||
|
||||
AZ::IO::FileIOBase::GetInstance()->Remove(m_tempPngFilePath.c_str());
|
||||
|
||||
m_primaryColors3x1 = {
|
||||
255u, 0u, 0u, 255u,
|
||||
0u, 255u, 0u, 255u,
|
||||
0u, 0u, 255u, 255u
|
||||
};
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_testImageFolder = AZ::IO::Path{};
|
||||
m_tempPngFilePath = AZ::IO::Path{};
|
||||
m_primaryColors3x1 = AZStd::vector<uint8_t>{};
|
||||
|
||||
AZ::IO::FileIOBase::SetInstance(nullptr);
|
||||
m_localFileIO.reset();
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
struct Color3 : public AZStd::array<uint8_t, 3>
|
||||
{
|
||||
using Base = AZStd::array<uint8_t, 3>;
|
||||
Color3(uint8_t r, uint8_t g, uint8_t b) : Base({r, g, b}) {}
|
||||
Color3(const uint8_t* raw) : Base({raw[0], raw[1], raw[2]}) {}
|
||||
};
|
||||
|
||||
struct Color4 : public AZStd::array<uint8_t, 4>
|
||||
{
|
||||
using Base = AZStd::array<uint8_t, 4>;
|
||||
Color4(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : Base({r, g, b, a}) {}
|
||||
Color4(const uint8_t* raw) : Base({raw[0], raw[1], raw[2], raw[3]}) {}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(PngFileTests, LoadRgb)
|
||||
{
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgb.png").c_str());
|
||||
EXPECT_TRUE(image.IsValid());
|
||||
EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB);
|
||||
EXPECT_EQ(image.GetWidth(), 3);
|
||||
EXPECT_EQ(image.GetHeight(), 2);
|
||||
EXPECT_EQ(image.GetBuffer().size(), 18);
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(255u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(0u, 255u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(0u, 0u, 255u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 9), Color3(255u, 255u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 12), Color3(0u, 255u, 255u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 15), Color3(255u, 0u, 255u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, LoadRgba)
|
||||
{
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgba.png").c_str());
|
||||
EXPECT_TRUE(image.IsValid());
|
||||
EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGBA);
|
||||
EXPECT_EQ(image.GetWidth(), 3);
|
||||
EXPECT_EQ(image.GetHeight(), 2);
|
||||
EXPECT_EQ(image.GetBuffer().size(), 24);
|
||||
EXPECT_EQ(Color4(image.GetBuffer().begin() + 0), Color4(255u, 0u, 0u, 200u));
|
||||
EXPECT_EQ(Color4(image.GetBuffer().begin() + 4), Color4(0u, 255u, 0u, 150u));
|
||||
EXPECT_EQ(Color4(image.GetBuffer().begin() + 8), Color4(0u, 0u, 255u, 100u));
|
||||
EXPECT_EQ(Color4(image.GetBuffer().begin() + 12), Color4(255u, 255u, 0u, 125u));
|
||||
EXPECT_EQ(Color4(image.GetBuffer().begin() + 16), Color4(0u, 255u, 255u, 175u));
|
||||
EXPECT_EQ(Color4(image.GetBuffer().begin() + 20), Color4(255u, 0u, 255u, 75u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, LoadRgbaStripAlpha)
|
||||
{
|
||||
PngFile::LoadSettings loadSettings;
|
||||
loadSettings.m_stripAlpha = true;
|
||||
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgba.png").c_str(), loadSettings);
|
||||
// Note these checks are identical to the LoadRgb test.
|
||||
EXPECT_TRUE(image.IsValid());
|
||||
EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB);
|
||||
EXPECT_EQ(image.GetWidth(), 3);
|
||||
EXPECT_EQ(image.GetHeight(), 2);
|
||||
EXPECT_EQ(image.GetBuffer().size(), 18);
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(255u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(0u, 255u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(0u, 0u, 255u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 9), Color3(255u, 255u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 12), Color3(0u, 255u, 255u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 15), Color3(255u, 0u, 255u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, LoadColorPaletteTwoBits)
|
||||
{
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "ColorPalette_2bit.png").c_str());
|
||||
EXPECT_TRUE(image.IsValid());
|
||||
EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB);
|
||||
EXPECT_EQ(image.GetWidth(), 1);
|
||||
EXPECT_EQ(image.GetHeight(), 3);
|
||||
EXPECT_EQ(image.GetBuffer().size(), 9);
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(255u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(0u, 255u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(0u, 0u, 255u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, LoadGrayscaleOneBit)
|
||||
{
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "GrayPalette_1bit.png").c_str());
|
||||
EXPECT_TRUE(image.IsValid());
|
||||
EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB);
|
||||
EXPECT_EQ(image.GetWidth(), 1);
|
||||
EXPECT_EQ(image.GetHeight(), 2);
|
||||
EXPECT_EQ(image.GetBuffer().size(), 6);
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(0u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(255u, 255u, 255u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, LoadRgba64Bits)
|
||||
{
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "Gradient_rgb_16bpc.png").c_str());
|
||||
EXPECT_TRUE(image.IsValid());
|
||||
EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB);
|
||||
EXPECT_EQ(image.GetWidth(), 5);
|
||||
EXPECT_EQ(image.GetHeight(), 1);
|
||||
EXPECT_EQ(image.GetBuffer().size(), 15);
|
||||
// The values in this file are 30.0f, 30.1f, 30.2f, 30.3f, 30.4f. But we use PNG_TRANSFORM_STRIP_16 to reduce them to 8 bits per channel for simplicity.
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(76u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(77u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(77u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 9), Color3(77u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(image.GetBuffer().begin() + 12), Color3(77u, 0u, 0u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, CreateCopy)
|
||||
{
|
||||
AZStd::vector<uint8_t> data = m_primaryColors3x1;
|
||||
|
||||
PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, data);
|
||||
EXPECT_TRUE(savedImage.IsValid());
|
||||
EXPECT_EQ(savedImage.GetWidth(), 3);
|
||||
EXPECT_EQ(savedImage.GetHeight(), 1);
|
||||
EXPECT_EQ(savedImage.GetBuffer(), data);
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, CreateMove)
|
||||
{
|
||||
AZStd::vector<uint8_t> data = m_primaryColors3x1;
|
||||
|
||||
PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, AZStd::move(data));
|
||||
EXPECT_TRUE(savedImage.IsValid());
|
||||
EXPECT_EQ(savedImage.GetWidth(), 3);
|
||||
EXPECT_EQ(savedImage.GetHeight(), 1);
|
||||
EXPECT_EQ(savedImage.GetBuffer(), m_primaryColors3x1);
|
||||
EXPECT_TRUE(data.empty()); // The data should have been moved
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, SaveRgba)
|
||||
{
|
||||
PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1);
|
||||
bool result = savedImage.Save(m_tempPngFilePath.c_str());
|
||||
EXPECT_TRUE(result);
|
||||
|
||||
PngFile loadedImage = PngFile::Load(m_tempPngFilePath.c_str());
|
||||
EXPECT_TRUE(loadedImage.IsValid());
|
||||
EXPECT_EQ(loadedImage.GetBufferFormat(), savedImage.GetBufferFormat());
|
||||
EXPECT_EQ(loadedImage.GetWidth(), savedImage.GetWidth());
|
||||
EXPECT_EQ(loadedImage.GetHeight(), savedImage.GetHeight());
|
||||
EXPECT_EQ(loadedImage.GetBuffer(), savedImage.GetBuffer());
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, SaveRgbaStripAlpha)
|
||||
{
|
||||
PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1);
|
||||
|
||||
PngFile::SaveSettings saveSettings;
|
||||
saveSettings.m_stripAlpha = true;
|
||||
|
||||
bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings);
|
||||
EXPECT_TRUE(result);
|
||||
|
||||
// The alpha was stripped when saving. Now we load the data without stripping anything and should find
|
||||
// that there is no alpha channel.
|
||||
|
||||
PngFile loadedImage = PngFile::Load(m_tempPngFilePath.c_str());
|
||||
|
||||
// The dimensions are the same...
|
||||
EXPECT_TRUE(loadedImage.IsValid());
|
||||
EXPECT_EQ(loadedImage.GetWidth(), savedImage.GetWidth());
|
||||
EXPECT_EQ(loadedImage.GetHeight(), savedImage.GetHeight());
|
||||
|
||||
// ... but the format is different
|
||||
EXPECT_NE(loadedImage.GetBufferFormat(), savedImage.GetBufferFormat());
|
||||
EXPECT_EQ(loadedImage.GetBufferFormat(), PngFile::Format::RGB);
|
||||
|
||||
// ... and the loaded data is smaller
|
||||
EXPECT_NE(loadedImage.GetBuffer(), savedImage.GetBuffer());
|
||||
EXPECT_EQ(Color3(loadedImage.GetBuffer().begin() + 0), Color3(255u, 0u, 0u));
|
||||
EXPECT_EQ(Color3(loadedImage.GetBuffer().begin() + 3), Color3(0u, 255u, 0u));
|
||||
EXPECT_EQ(Color3(loadedImage.GetBuffer().begin() + 6), Color3(0u, 0u, 255u));
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, Error_CreateUnsupportedFormat)
|
||||
{
|
||||
AZStd::vector<uint8_t> data = m_primaryColors3x1;
|
||||
|
||||
AZStd::string gotErrorMessage;
|
||||
|
||||
PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R32_UINT, data,
|
||||
[&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; });
|
||||
|
||||
EXPECT_FALSE(savedImage.IsValid());
|
||||
EXPECT_TRUE(gotErrorMessage.find("unsupported format R32_UINT") != AZStd::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, Error_CreateIncorrectBufferSize)
|
||||
{
|
||||
AZStd::vector<uint8_t> data = m_primaryColors3x1;
|
||||
|
||||
AZStd::string gotErrorMessage;
|
||||
|
||||
PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 2, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, data,
|
||||
[&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; });
|
||||
|
||||
EXPECT_FALSE(savedImage.IsValid());
|
||||
EXPECT_TRUE(gotErrorMessage.find("does not match") != AZStd::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, Error_LoadFileNotFound)
|
||||
{
|
||||
AZStd::string gotErrorMessage;
|
||||
|
||||
PngFile::LoadSettings loadSettings;
|
||||
loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; };
|
||||
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "DoesNotExist.png").c_str(), loadSettings);
|
||||
EXPECT_FALSE(image.IsValid());
|
||||
EXPECT_TRUE(gotErrorMessage.find("not open file") != AZStd::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, Error_LoadEmptyFile)
|
||||
{
|
||||
AZStd::string gotErrorMessage;
|
||||
|
||||
PngFile::LoadSettings loadSettings;
|
||||
loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; };
|
||||
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "EmptyFile.png").c_str(), loadSettings);
|
||||
EXPECT_FALSE(image.IsValid());
|
||||
EXPECT_TRUE(gotErrorMessage.find("Invalid png header") != AZStd::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, Error_LoadNotPngFile)
|
||||
{
|
||||
AZStd::string gotErrorMessage;
|
||||
|
||||
PngFile::LoadSettings loadSettings;
|
||||
loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; };
|
||||
|
||||
PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgba.jpg").c_str(), loadSettings);
|
||||
EXPECT_FALSE(image.IsValid());
|
||||
EXPECT_TRUE(gotErrorMessage.find("Invalid png header") != AZStd::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(PngFileTests, Error_SaveInvalidPngFile)
|
||||
{
|
||||
AZStd::string gotErrorMessage;
|
||||
|
||||
PngFile::SaveSettings saveSettings;
|
||||
saveSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; };
|
||||
|
||||
PngFile savedImage;
|
||||
bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings);
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_TRUE(gotErrorMessage.find("PngFile is invalid") != AZStd::string::npos);
|
||||
EXPECT_FALSE(AZ::IO::FileIOBase::GetInstance()->Exists(m_tempPngFilePath.c_str()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
temp.png
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:af0d0d079354495ff96aa266ecb4092d679e6c5a952e8b2d4ee743e538d54809
|
||||
size 126
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:01cad8dd75c9a26169e858960817424362c16cbf2a8df8bc55857f6172ce2526
|
||||
size 834
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6ddb5f70eaf72fe09add6cc7cdf7cbba2d327ab312bb9bde73d7f456f80b8d6e
|
||||
size 141
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b50e93bbbd320d69752df2c25b4118c0198226a0d230781a6ed93f89b7eea053
|
||||
size 142
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cb56e8bf15a4727bcebba579cb97a36e1f26e4a4870b2b4a38bdbd4b4bd076fd
|
||||
size 127
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:710fd5c80af49a42249a471ded6c9119be79d6748218073bb8297ffb4b4e62d1
|
||||
size 137
|
||||
@@ -23,6 +23,7 @@ set(FILES
|
||||
Include/Atom/Utils/ImGuiShaderMetrics.inl
|
||||
Include/Atom/Utils/ImGuiTransientAttachmentProfiler.h
|
||||
Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl
|
||||
Include/Atom/Utils/PngFile.h
|
||||
Include/Atom/Utils/PpmFile.h
|
||||
Include/Atom/Utils/StableDynamicArray.h
|
||||
Include/Atom/Utils/StableDynamicArray.inl
|
||||
@@ -31,6 +32,7 @@ set(FILES
|
||||
Include/Atom/Utils/AssetCollectionAsyncLoader.h
|
||||
Source/DdsFile.cpp
|
||||
Source/ImageComparison.cpp
|
||||
Source/PngFile.cpp
|
||||
Source/PpmFile.cpp
|
||||
Source/Utils.cpp
|
||||
Source/AssetCollectionAsyncLoader.cpp
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
|
||||
set(FILES
|
||||
Tests/ImageComparisonTests.cpp
|
||||
Tests/PngFileTests.cpp
|
||||
Tests/StableDynamicArrayTests.cpp
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS Phy
|
||||
ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705)
|
||||
ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-android TARGETS googletest PACKAGE_HASH 95671be75287a61c9533452835c3647e9c1b30f81b34b43bcb0ec1997cc23894)
|
||||
ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS GoogleBenchmark PACKAGE_HASH 20b46e572211a69d7d94ddad1c89ec37bb958711d6ad4025368ac89ea83078fb)
|
||||
ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-android TARGETS libpng PACKAGE_HASH 51d3ec1559c5595196c11e11674cf5745989d3073bf33dabc6697e3eee77a1cc)
|
||||
ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b)
|
||||
ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480)
|
||||
ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826)
|
||||
|
||||
@@ -36,6 +36,7 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux
|
||||
ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-linux TARGETS GoogleBenchmark PACKAGE_HASH 4038878f337fc7e0274f0230f71851b385b2e0327c495fc3dd3d1c18a807928d)
|
||||
ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux TARGETS unwind PACKAGE_HASH 3453265fb056e25432f611a61546a25f60388e315515ad39007b5925dd054a77)
|
||||
ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-linux TARGETS Qt PACKAGE_HASH 76b395897b941a173002845c7219a5f8a799e44b269ffefe8091acc048130f28)
|
||||
ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-linux TARGETS libpng PACKAGE_HASH 896451999f1de76375599aec4b34ae0573d8d34620d9ab29cc30b8739c265ba6)
|
||||
ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261)
|
||||
ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc)
|
||||
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099)
|
||||
|
||||
@@ -38,6 +38,7 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac
|
||||
ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-mac TARGETS GoogleBenchmark PACKAGE_HASH ad25de0146769c91e179953d845de2bec8ed4a691f973f47e3eb37639381f665)
|
||||
ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac TARGETS OpenSSL PACKAGE_HASH 28adc1c0616ac0482b2a9d7b4a3a3635a1020e87b163f8aba687c501cf35f96c)
|
||||
ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e)
|
||||
ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 1ad76cd038ccc1f288f83c5fe2859a0f35c5154e1fe7658e1230cc428d318a8b)
|
||||
ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe)
|
||||
ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-mac TARGETS zlib PACKAGE_HASH 21714e8a6de4f2523ee92a7f52d51fbee29c5f37ced334e00dc3c029115b472e)
|
||||
ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac TARGETS squish-ccr PACKAGE_HASH 155bfbfa17c19a9cd2ef025de14c5db598f4290045d5b0d83ab58cb345089a77)
|
||||
|
||||
@@ -41,6 +41,7 @@ ly_associate_package(PACKAGE_NAME d3dx12-headers-rev1-windows
|
||||
ly_associate_package(PACKAGE_NAME pyside2-qt-5.15.1-rev2-windows TARGETS pyside2 PACKAGE_HASH c90f3efcc7c10e79b22a33467855ad861f9dbd2e909df27a5cba9db9fa3edd0f)
|
||||
ly_associate_package(PACKAGE_NAME openimageio-2.1.16.0-rev2-windows TARGETS OpenImageIO PACKAGE_HASH 85a2a6cf35cbc4c967c56ca8074babf0955c5b490c90c6e6fd23c78db99fc282)
|
||||
ly_associate_package(PACKAGE_NAME qt-5.15.2-rev4-windows TARGETS Qt PACKAGE_HASH a4634caaf48192cad5c5f408504746e53d338856148285057274f6a0ccdc071d)
|
||||
ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-windows TARGETS libpng PACKAGE_HASH aa20c894fbd7cdaea585a54e37620b3454a7e414a58128acd68ccf6fe76c47d6)
|
||||
ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-windows TARGETS libsamplerate PACKAGE_HASH dcf3c11a96f212a52e2c9241abde5c364ee90b0f32fe6eeb6dcdca01d491829f)
|
||||
ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows TARGETS OpenMesh PACKAGE_HASH 1c1df639358526c368e790dfce40c45cbdfcfb1c9a041b9d7054a8949d88ee77)
|
||||
ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4)
|
||||
|
||||
@@ -25,6 +25,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-ios TARGETS PhysX
|
||||
ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-ios TARGETS mikkelsen PACKAGE_HASH 976aaa3ccd8582346132a10af253822ccc5d5bcc9ea5ba44d27848f65ee88a8a)
|
||||
ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-ios TARGETS googletest PACKAGE_HASH 2f121ad9784c0ab73dfaa58e1fee05440a82a07cc556bec162eeb407688111a7)
|
||||
ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-ios TARGETS GoogleBenchmark PACKAGE_HASH c2ffaed2b658892b1bcf81dee4b44cd1cb09fc78d55584ef5cb8ab87f2d8d1ae)
|
||||
ly_associate_package(PACKAGE_NAME libpng-1.6.37-ios TARGETS libpng PACKAGE_HASH 18a8217721083c4dc46514105be43ca764fa9c994a74aa0b57766ea6f8187e7b)
|
||||
ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-ios TARGETS libsamplerate PACKAGE_HASH 7656b961697f490d4f9c35d2e61559f6fc38c32102e542a33c212cd618fc2119)
|
||||
ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-ios TARGETS OpenSSL PACKAGE_HASH cd0dfce3086a7172777c63dadbaf0ac3695b676119ecb6d0614b5fb1da03462f)
|
||||
ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-ios TARGETS zlib PACKAGE_HASH a59fc0f83a02c616b679799310e9d86fde84514c6d2acefa12c6def0ae4a880c)
|
||||
|
||||
Reference in New Issue
Block a user