Merge branch 'main' into Atom/jromnoa/SPEC-6728-fix-material-editor-launcher
commit
a1b4844f6a
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"Amazon": {
|
|
||||||
"AssetProcessor": {
|
|
||||||
"Settings": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:1a1623477f4e2e5ef0440ecfc0c08e775d9b5f12d8ebc6b434e8212bf3445bcd
|
|
||||||
size 224
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:31b247223c1116d4fc014189a9d8d86d4458b792c1120442673631136fd89520
|
|
||||||
size 222
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
<RCC>
|
|
||||||
<qresource>
|
|
||||||
<file>refresh-active.png</file>
|
|
||||||
<file>warning.png</file>
|
|
||||||
<file>refresh.png</file>
|
|
||||||
<file>info.png</file>
|
|
||||||
<file>Backward.png</file>
|
|
||||||
<file>Forward.png</file>
|
|
||||||
<file>reset.png</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:3fec3caae92b9c9290c4157b3aeca29dcb366edd12719355e1d93dfb9d80cfed
|
|
||||||
size 825
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:d29af2b69b74815c88352f85a7131384482e4f2d26ecf36581b46dede542fccb
|
|
||||||
size 2973
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:36591b457ee3519b16405d281674fcdd18645e3570bfc960a22b8f142ee99a14
|
|
||||||
size 436
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:0362da38d3804e2911130d138be4fd73040d66c8ac7d1b5f9f60c70037e8ca93
|
|
||||||
size 1292
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:cf5e987ea92164dcaa6deb88989aaac962bc092f5745274017f71224f48dbf7a
|
|
||||||
size 651
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
#
|
|
||||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
# its licensors.
|
|
||||||
#
|
|
||||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
# distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
#
|
|
||||||
|
|
||||||
add_subdirectory(Code)
|
|
||||||
@ -1,147 +0,0 @@
|
|||||||
#
|
|
||||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
# its licensors.
|
|
||||||
#
|
|
||||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
# distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
#
|
|
||||||
|
|
||||||
ly_add_target(
|
|
||||||
NAME ImageProcessing.Headers HEADERONLY
|
|
||||||
NAMESPACE Gem
|
|
||||||
FILES_CMAKE
|
|
||||||
imageprocessing_headers_files.cmake
|
|
||||||
INCLUDE_DIRECTORIES
|
|
||||||
INTERFACE
|
|
||||||
Include
|
|
||||||
)
|
|
||||||
|
|
||||||
if (NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME})
|
|
||||||
|
|
||||||
set(platform_tools_files)
|
|
||||||
set(pal_tools_include_files)
|
|
||||||
set(pal_tools_dirs)
|
|
||||||
foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED})
|
|
||||||
string(TOLOWER ${enabled_platform} enabled_platform_lowercase)
|
|
||||||
ly_get_list_relative_pal_filename(pal_tools_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform})
|
|
||||||
list(APPEND platform_tools_files ${pal_tools_dir}/pal_tools_${enabled_platform_lowercase}.cmake)
|
|
||||||
list(APPEND pal_tools_include_files ${pal_tools_dir}/pal_tools_${enabled_platform_lowercase}_files.cmake)
|
|
||||||
list(APPEND pal_tools_dirs ${pal_tools_dir})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
ly_add_target(
|
|
||||||
NAME ImageProcessing.Static STATIC
|
|
||||||
NAMESPACE Gem
|
|
||||||
AUTOMOC
|
|
||||||
AUTOUIC
|
|
||||||
FILES_CMAKE
|
|
||||||
imageprocessing_static_files.cmake
|
|
||||||
${pal_tools_include_files}
|
|
||||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
|
||||||
PLATFORM_INCLUDE_FILES
|
|
||||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
|
|
||||||
${platform_tools_files}
|
|
||||||
INCLUDE_DIRECTORIES
|
|
||||||
PRIVATE
|
|
||||||
.
|
|
||||||
Source
|
|
||||||
../External
|
|
||||||
${pal_dir}
|
|
||||||
${pal_tools_dirs}
|
|
||||||
PUBLIC
|
|
||||||
Include
|
|
||||||
BUILD_DEPENDENCIES
|
|
||||||
PRIVATE
|
|
||||||
3rdParty::Qt::Core
|
|
||||||
3rdParty::Qt::Widgets
|
|
||||||
3rdParty::etc2comp
|
|
||||||
3rdParty::PVRTexTool
|
|
||||||
3rdParty::squish-ccr
|
|
||||||
3rdParty::zlib
|
|
||||||
3rdParty::tiff
|
|
||||||
Legacy::CryCommon
|
|
||||||
AZ::AzCore
|
|
||||||
AZ::AssetBuilderSDK
|
|
||||||
Gem::TextureAtlas
|
|
||||||
)
|
|
||||||
ly_add_source_properties(
|
|
||||||
SOURCES
|
|
||||||
Source/BuilderSettings/BuilderSettingManager.cpp
|
|
||||||
Source/Processing/ImageConvert.cpp
|
|
||||||
PROPERTY COMPILE_DEFINITIONS
|
|
||||||
VALUES ${LY_PAL_TOOLS_DEFINES}
|
|
||||||
)
|
|
||||||
|
|
||||||
ly_add_target(
|
|
||||||
NAME ImageProcessing.Editor GEM_MODULE
|
|
||||||
|
|
||||||
NAMESPACE Gem
|
|
||||||
AUTOMOC
|
|
||||||
AUTORCC
|
|
||||||
FILES_CMAKE
|
|
||||||
imageprocessing_files.cmake
|
|
||||||
PLATFORM_INCLUDE_FILES
|
|
||||||
${platform_tools_files}
|
|
||||||
INCLUDE_DIRECTORIES
|
|
||||||
PRIVATE
|
|
||||||
.
|
|
||||||
Source
|
|
||||||
${pal_dir}
|
|
||||||
PUBLIC
|
|
||||||
Include
|
|
||||||
BUILD_DEPENDENCIES
|
|
||||||
PRIVATE
|
|
||||||
3rdParty::Qt::Widgets
|
|
||||||
3rdParty::PVRTexTool
|
|
||||||
3rdParty::squish-ccr
|
|
||||||
Legacy::CryCommon
|
|
||||||
AZ::AzCore
|
|
||||||
AZ::AzToolsFramework
|
|
||||||
AZ::AssetBuilderSDK
|
|
||||||
Gem::ImageProcessing.Static
|
|
||||||
Gem::TextureAtlas
|
|
||||||
RUNTIME_DEPENDENCIES
|
|
||||||
3rdParty::ASTCEncoder
|
|
||||||
Gem::TextureAtlas
|
|
||||||
)
|
|
||||||
|
|
||||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
|
||||||
ly_add_target(
|
|
||||||
NAME ImageProcessing.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
|
||||||
NAMESPACE Gem
|
|
||||||
FILES_CMAKE
|
|
||||||
imageprocessing_tests_files.cmake
|
|
||||||
INCLUDE_DIRECTORIES
|
|
||||||
PRIVATE
|
|
||||||
Tests
|
|
||||||
.
|
|
||||||
Source
|
|
||||||
${pal_dir}
|
|
||||||
BUILD_DEPENDENCIES
|
|
||||||
PRIVATE
|
|
||||||
AZ::AzTest
|
|
||||||
3rdParty::Qt::Widgets
|
|
||||||
Legacy::CryCommon
|
|
||||||
AZ::AssetBuilderSDK
|
|
||||||
Gem::ImageProcessing.Static
|
|
||||||
Gem::ImageProcessing.Editor
|
|
||||||
Gem::TextureAtlas
|
|
||||||
)
|
|
||||||
ly_add_googletest(
|
|
||||||
NAME Gem::ImageProcessing.Tests
|
|
||||||
)
|
|
||||||
|
|
||||||
ly_add_source_properties(
|
|
||||||
SOURCES Tests/ImageProcessing_Test.cpp
|
|
||||||
PROPERTY COMPILE_DEFINITIONS
|
|
||||||
VALUES ${LY_PAL_TOOLS_DEFINES}
|
|
||||||
)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
|
||||||
#include <AzCore/std/string/string.h>
|
|
||||||
#include <AzCore/std/containers/vector.h>
|
|
||||||
#include <AzCore/Math/Vector4.h>
|
|
||||||
#include <AzCore/Math/Color.h>
|
|
||||||
|
|
||||||
namespace AZ
|
|
||||||
{
|
|
||||||
namespace IO
|
|
||||||
{
|
|
||||||
class SystemFileStream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class IImageObject;
|
|
||||||
class TextureSettings;
|
|
||||||
typedef AZStd::shared_ptr<IImageObject> IImageObjectPtr;
|
|
||||||
|
|
||||||
enum class EAlphaContent
|
|
||||||
{
|
|
||||||
eAlphaContent_Indeterminate, // the format may have alpha, but can't be calculated
|
|
||||||
eAlphaContent_Absent, // the format has no alpha
|
|
||||||
eAlphaContent_OnlyWhite, // alpha contains just white
|
|
||||||
eAlphaContent_OnlyBlack, // alpha contains just black
|
|
||||||
eAlphaContent_OnlyBlackAndWhite, // alpha contains just black and white
|
|
||||||
eAlphaContent_Greyscale // alpha contains grey tones
|
|
||||||
};
|
|
||||||
|
|
||||||
//interface for image object. The image object may have mipmaps.
|
|
||||||
class IImageObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//static functions
|
|
||||||
static IImageObject* CreateImage(AZ::u32 width, AZ::u32 height, AZ::u32 maxMipCount, EPixelFormat pixelFormat);
|
|
||||||
|
|
||||||
virtual ~IImageObject() {};
|
|
||||||
public:
|
|
||||||
//creating new image object outof this image object
|
|
||||||
virtual IImageObject* Clone() const = 0;
|
|
||||||
// allocate an empty image object with requested format and same properties with current image
|
|
||||||
virtual IImageObject* AllocateImage(EPixelFormat pixelFormat) const = 0;
|
|
||||||
virtual IImageObject* AllocateImage() const = 0;
|
|
||||||
|
|
||||||
//get pixel format
|
|
||||||
virtual EPixelFormat GetPixelFormat() const = 0;
|
|
||||||
|
|
||||||
virtual AZ::u32 GetPixelCount(AZ::u32 mip) const = 0;
|
|
||||||
virtual AZ::u32 GetWidth(AZ::u32 mip) const = 0;
|
|
||||||
virtual AZ::u32 GetHeight(AZ::u32 mip) const = 0;
|
|
||||||
virtual bool IsCubemap() const = 0;
|
|
||||||
virtual AZ::u32 GetMipCount() const = 0;
|
|
||||||
|
|
||||||
//get pixel data buffer
|
|
||||||
virtual void GetImagePointer(AZ::u32 mip, AZ::u8*& pMem, AZ::u32& pitch) const = 0;
|
|
||||||
virtual AZ::u32 GetMipBufSize(AZ::u32 mip) const = 0;
|
|
||||||
virtual void SetMipData(AZ::u32 mip, AZ::u8* mipBuf, AZ::u32 bufSize, AZ::u32 pitch) = 0;
|
|
||||||
|
|
||||||
//get/set image flags
|
|
||||||
virtual AZ::u32 GetImageFlags() const = 0;
|
|
||||||
virtual void SetImageFlags(AZ::u32 imageFlags) = 0;
|
|
||||||
virtual void AddImageFlags(AZ::u32 imageFlags) = 0;
|
|
||||||
virtual void RemoveImageFlags(AZ::u32 imageFlags) = 0;
|
|
||||||
virtual bool HasImageFlags(AZ::u32 imageFlags) const = 0;
|
|
||||||
|
|
||||||
// image data operations and calculation
|
|
||||||
// Calculates "(pixel.rgba * scale) + bias"
|
|
||||||
virtual void ScaleAndBiasChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& scale, const AZ::Vector4& bias) = 0;
|
|
||||||
// Calculates "clamp(pixel.rgba, min, max)"
|
|
||||||
virtual void ClampChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& min, const AZ::Vector4& max) = 0;
|
|
||||||
|
|
||||||
//transfer alpha coverage from source image
|
|
||||||
virtual void TransferAlphaCoverage(const TextureSettings* textureSetting, const IImageObjectPtr srcImg) = 0;
|
|
||||||
// Routines to measure and manipulate alpha coverage
|
|
||||||
virtual float ComputeAlphaCoverageScaleFactor(AZ::u32 mip, float fDesiredCoverage, float fAlphaRef) const = 0;
|
|
||||||
virtual float ComputeAlphaCoverage(AZ::u32 mip, float fAlphaRef) const = 0;
|
|
||||||
|
|
||||||
//helper functions
|
|
||||||
//compare whether two images are same. return true if they are same.
|
|
||||||
virtual bool CompareImage(const IImageObjectPtr otherImage) const = 0;
|
|
||||||
|
|
||||||
// Writes this image to file used for runtime, overwrites any existing file.
|
|
||||||
// It may write alpha image as attached image into the same file
|
|
||||||
// outFilePaths will save filenames finally saved to since the image might be split and saved to multiple files
|
|
||||||
virtual bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector<AZStd::string>& outFilePaths) const = 0;
|
|
||||||
virtual bool SaveImage(AZ::IO::SystemFileStream& out) const = 0;
|
|
||||||
virtual bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const = 0;
|
|
||||||
|
|
||||||
//get total image data size in memory of all mipmaps. Not includs header and flags.
|
|
||||||
virtual AZ::u32 GetTextureMemory() const = 0;
|
|
||||||
|
|
||||||
//identify content of the alpha channel
|
|
||||||
virtual EAlphaContent GetAlphaContent() const = 0;
|
|
||||||
|
|
||||||
//normalize rgb channel for specified mips
|
|
||||||
virtual void NormalizeVectors(AZ::u32 firstMip, AZ::u32 maxMipCount) = 0;
|
|
||||||
|
|
||||||
// use when you convert an image to another one
|
|
||||||
virtual void CopyPropertiesFrom(const IImageObjectPtr src) = 0;
|
|
||||||
|
|
||||||
//swizzle data for source channels to dest channels
|
|
||||||
virtual void Swizzle(const char channels[4]) = 0;
|
|
||||||
|
|
||||||
//get/set properties of the image object
|
|
||||||
virtual void GetColorRange(AZ::Color& minColor, AZ::Color& maxColor) const = 0;
|
|
||||||
virtual void SetColorRange(const AZ::Color& minColor, const AZ::Color& maxColor) = 0;
|
|
||||||
virtual AZ::u32 GetNumPersistentMips() const = 0;
|
|
||||||
virtual void SetNumPersistentMips(AZ::u32 nMips) = 0;
|
|
||||||
virtual float GetAverageBrightness() const = 0;
|
|
||||||
virtual void SetAverageBrightness(float avgBrightness) = 0;
|
|
||||||
|
|
||||||
// Derive new roughness from normal variance to preserve the bumpiness of normal map mips and to reduce specular aliasing.
|
|
||||||
// The derived roughness is combined with the artist authored roughness stored in the alpha channel of the normal map.
|
|
||||||
// The algorithm is based on the Frequency Domain Normal Mapping implementation presented by Neubelt and Pettineo at Siggraph 2013.
|
|
||||||
virtual void GlossFromNormals(bool hasAuthoredGloss) = 0;
|
|
||||||
|
|
||||||
//convert gloss map from legacy distribution to new one. New World is still using legacy gloss map.
|
|
||||||
virtual void ConvertLegacyGloss() = 0;
|
|
||||||
|
|
||||||
//clear image with color
|
|
||||||
virtual void ClearColor(float r, float g, float b, float a) = 0;
|
|
||||||
|
|
||||||
virtual bool HasPowerOfTwoSizes() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
//loading function to load output dds file to a IImageObject
|
|
||||||
IImageObject* LoadImageFromDdsFile(const AZStd::string& filename);
|
|
||||||
IImageObject* LoadImageFromDdsFile(AZ::IO::SystemFileStream& fileLoadStream);
|
|
||||||
IImageObject* LoadAttachedImageFromDdsFile(const AZStd::string& filename, IImageObjectPtr originImage);
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/EBus/EBus.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class ImageProcessingRequests
|
|
||||||
: public AZ::EBusTraits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// EBusTraits overrides
|
|
||||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
|
||||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Loads an image from a source file path
|
|
||||||
virtual IImageObjectPtr LoadImage(const AZStd::string& filePath) = 0;
|
|
||||||
|
|
||||||
// Loads an image from a source file path and converts it to a format suitable for previewing in tools
|
|
||||||
virtual IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) = 0;
|
|
||||||
};
|
|
||||||
using ImageProcessingRequestBus = AZ::EBus<ImageProcessingRequests>;
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/EBus/EBus.h>
|
|
||||||
|
|
||||||
class QString;
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class ImageProcessingEditorRequests
|
|
||||||
: public AZ::EBusTraits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// EBusTraits overrides
|
|
||||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
|
||||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//! Open single texture file
|
|
||||||
virtual void OpenSourceTextureFile(const AZ::Uuid& textureSourceID) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using ImageProcessingEditorRequestBus = AZ::EBus<ImageProcessingEditorRequests>;
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
enum EPixelFormat : int
|
|
||||||
{
|
|
||||||
//unsigned formats
|
|
||||||
ePixelFormat_R8G8B8A8 = 0,
|
|
||||||
ePixelFormat_R8G8B8X8,
|
|
||||||
ePixelFormat_R8G8,
|
|
||||||
ePixelFormat_R8,
|
|
||||||
ePixelFormat_A8,
|
|
||||||
ePixelFormat_R16G16B16A16,
|
|
||||||
ePixelFormat_R16G16,
|
|
||||||
ePixelFormat_R16,
|
|
||||||
|
|
||||||
//Custom FourCC Formats
|
|
||||||
// Data in these FourCC formats is custom compressed data and only decodable by certain hardware.
|
|
||||||
//ASTC formats supported by ios devices with A8 processor. Also supported by Android Extension Pack.
|
|
||||||
ePixelFormat_ASTC_4x4,
|
|
||||||
ePixelFormat_ASTC_5x4,
|
|
||||||
ePixelFormat_ASTC_5x5,
|
|
||||||
ePixelFormat_ASTC_6x5,
|
|
||||||
ePixelFormat_ASTC_6x6,
|
|
||||||
ePixelFormat_ASTC_8x5,
|
|
||||||
ePixelFormat_ASTC_8x6,
|
|
||||||
ePixelFormat_ASTC_8x8,
|
|
||||||
ePixelFormat_ASTC_10x5,
|
|
||||||
ePixelFormat_ASTC_10x6,
|
|
||||||
ePixelFormat_ASTC_10x8,
|
|
||||||
ePixelFormat_ASTC_10x10,
|
|
||||||
ePixelFormat_ASTC_12x10,
|
|
||||||
ePixelFormat_ASTC_12x12,
|
|
||||||
//Formats supported by PowerVR GPU. Mainly for ios devices.
|
|
||||||
ePixelFormat_PVRTC2, //2bpp
|
|
||||||
ePixelFormat_PVRTC4, //4bpp
|
|
||||||
//formats for opengl and opengles 3.0 (android devices)
|
|
||||||
ePixelFormat_EAC_R11, //one channel unsigned data
|
|
||||||
ePixelFormat_EAC_RG11, //two channel unsigned data
|
|
||||||
ePixelFormat_ETC2, //Compresses RGB888 data, it taks 4x4 groups of pixel data and compresses each into a 64-bit
|
|
||||||
ePixelFormat_ETC2a, //Compresses RGBA8888 data with full alpha support
|
|
||||||
|
|
||||||
// Standardized Compressed DXGI Formats (DX10+)
|
|
||||||
// Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API.
|
|
||||||
ePixelFormat_BC1, // RGB without alpha, 0.5 byte/px
|
|
||||||
ePixelFormat_BC1a, // RGB with 1 bit of alpha, 0.5 byte/px.
|
|
||||||
ePixelFormat_BC3, // RGBA 1 byte/px, color maps with full alpha.
|
|
||||||
ePixelFormat_BC3t, // BC3 with alpha weighted color
|
|
||||||
ePixelFormat_BC4, // One color channel, 0.5 byte/px, unsigned
|
|
||||||
ePixelFormat_BC4s, // BC4, signed
|
|
||||||
ePixelFormat_BC5, // Two color channels, 1 byte/px, unsigned. Usually use for tangent-space normal maps
|
|
||||||
ePixelFormat_BC5s, // BC5, signed
|
|
||||||
ePixelFormat_BC6UH, // RGB, floating-point. Used for HDR images. Decompress to RGB in half floating point
|
|
||||||
ePixelFormat_BC7, // RGB or RGBA. 1 byte/px. Three color channels (4 to 7 bits per channel) with 0 to 8 bits of alpha
|
|
||||||
ePixelFormat_BC7t, // BC& with alpha weighted color
|
|
||||||
|
|
||||||
// Float formats
|
|
||||||
// Data in a Float format is floating point data.
|
|
||||||
ePixelFormat_R9G9B9E5,
|
|
||||||
ePixelFormat_R32G32B32A32F,
|
|
||||||
ePixelFormat_R32G32F,
|
|
||||||
ePixelFormat_R32F,
|
|
||||||
ePixelFormat_R16G16B16A16F,
|
|
||||||
ePixelFormat_R16G16F,
|
|
||||||
ePixelFormat_R16F,
|
|
||||||
|
|
||||||
//legacy format. Only used to load old converted dds files.
|
|
||||||
ePixelFormat_B8G8R8A8, //32bits rgba format
|
|
||||||
|
|
||||||
ePixelFormat_R32,
|
|
||||||
|
|
||||||
ePixelFormat_Count,
|
|
||||||
ePixelFormat_Unknown = ePixelFormat_Count
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool IsASTCFormat(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
return fmt == ePixelFormat_ASTC_4x4 || fmt == ePixelFormat_ASTC_5x4 || fmt == ePixelFormat_ASTC_5x5 ||
|
|
||||||
fmt == ePixelFormat_ASTC_6x5 || fmt == ePixelFormat_ASTC_6x6 || fmt == ePixelFormat_ASTC_8x5 ||
|
|
||||||
fmt == ePixelFormat_ASTC_8x6 || fmt == ePixelFormat_ASTC_8x8 || fmt == ePixelFormat_ASTC_10x5 ||
|
|
||||||
fmt == ePixelFormat_ASTC_10x6 || fmt == ePixelFormat_ASTC_10x8 || fmt == ePixelFormat_ASTC_10x10 ||
|
|
||||||
fmt == ePixelFormat_ASTC_12x10 || fmt == ePixelFormat_ASTC_12x12;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsETCFormat(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
return fmt == ePixelFormat_ETC2 || fmt == ePixelFormat_ETC2a || fmt == ePixelFormat_EAC_R11 ||
|
|
||||||
fmt == ePixelFormat_EAC_RG11;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsPVRTCFormat(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
return fmt == ePixelFormat_PVRTC2 || fmt == ePixelFormat_PVRTC4;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#include "AtlasBuilderComponent.h"
|
|
||||||
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
|
|
||||||
namespace TextureAtlasBuilder
|
|
||||||
{
|
|
||||||
// AZ Components should only initialize their members to null and empty in constructor
|
|
||||||
// Allocation of data should occur in Init(), once we can guarantee reflection and registration of types
|
|
||||||
AtlasBuilderComponent::AtlasBuilderComponent()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle deallocation of your memory allocated in Init()
|
|
||||||
AtlasBuilderComponent::~AtlasBuilderComponent()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init is where you'll actually allocate memory or create objects
|
|
||||||
// This ensures that any dependency components will have been been created and serialized
|
|
||||||
void AtlasBuilderComponent::Init()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activate is where you'd perform registration with other objects and systems.
|
|
||||||
// All builder classes owned by this component should be registered here
|
|
||||||
// Any EBuses for the builder classes should also be connected at this point
|
|
||||||
void AtlasBuilderComponent::Activate()
|
|
||||||
{
|
|
||||||
AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
|
|
||||||
builderDescriptor.m_name = "Atlas Worker Builder";
|
|
||||||
builderDescriptor.m_version = 1;
|
|
||||||
builderDescriptor.m_patterns.emplace_back(AssetBuilderSDK::AssetBuilderPattern("*.texatlas", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
|
||||||
builderDescriptor.m_busId = azrtti_typeid<AtlasBuilderWorker>();
|
|
||||||
builderDescriptor.m_createJobFunction = AZStd::bind(&AtlasBuilderWorker::CreateJobs, &m_atlasBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
|
||||||
builderDescriptor.m_processJobFunction = AZStd::bind(&AtlasBuilderWorker::ProcessJob, &m_atlasBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
|
||||||
|
|
||||||
m_atlasBuilder.BusConnect(builderDescriptor.m_busId);
|
|
||||||
|
|
||||||
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnects from any EBuses we connected to in Activate()
|
|
||||||
// Unregisters from objects and systems we register with in Activate()
|
|
||||||
void AtlasBuilderComponent::Deactivate()
|
|
||||||
{
|
|
||||||
m_atlasBuilder.BusDisconnect();
|
|
||||||
|
|
||||||
// We don't need to unregister the builder - the AP will handle this for us, because it is managing the lifecycle of this component
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reflect the input and output formats for the serializer
|
|
||||||
void AtlasBuilderComponent::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<AtlasBuilderComponent, AZ::Component>()
|
|
||||||
->Version(0)
|
|
||||||
->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector<AZ::Crc32>({ AssetBuilderSDK::ComponentTags::AssetBuilder }))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtlasBuilderInput::Reflect(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AtlasBuilderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
|
||||||
{
|
|
||||||
provided.push_back(AZ_CRC("Atlas Builder Plugin Service", 0x35974d0d));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AtlasBuilderComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
|
||||||
{
|
|
||||||
incompatible.push_back(AZ_CRC("Atlas Builder Plugin Service", 0x35974d0d));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AtlasBuilderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
|
||||||
{
|
|
||||||
AZ_UNUSED(required);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AtlasBuilderComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
|
||||||
{
|
|
||||||
AZ_UNUSED(dependent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/Component/Component.h>
|
|
||||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
|
||||||
#include "AtlasBuilderWorker.h"
|
|
||||||
|
|
||||||
namespace TextureAtlasBuilder
|
|
||||||
{
|
|
||||||
class AtlasBuilderComponent : public AZ::Component
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_COMPONENT(AtlasBuilderComponent, "{F49987FB-3375-4417-AB83-97B44C78B335}");
|
|
||||||
|
|
||||||
AtlasBuilderComponent();
|
|
||||||
~AtlasBuilderComponent() override;
|
|
||||||
|
|
||||||
void Init() override;
|
|
||||||
void Activate() override;
|
|
||||||
void Deactivate() override;
|
|
||||||
|
|
||||||
//! Reflect formats for input and output
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
|
||||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
|
||||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
|
||||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
|
||||||
|
|
||||||
private:
|
|
||||||
AtlasBuilderWorker m_atlasBuilder;
|
|
||||||
};
|
|
||||||
} // namespace TextureAtlasBuilder
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
*or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/RTTI/RTTI.h>
|
|
||||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
|
||||||
#include <AssetBuilderSDK/AssetBuilderBusses.h>
|
|
||||||
#include <qimage.h>
|
|
||||||
#include <TextureAtlas/TextureAtlasBus.h>
|
|
||||||
|
|
||||||
namespace TextureAtlasBuilder
|
|
||||||
{
|
|
||||||
//! Struct that is used to communicate input commands
|
|
||||||
struct AtlasBuilderInput
|
|
||||||
{
|
|
||||||
AZ_CLASS_ALLOCATOR(AtlasBuilderInput, AZ::SystemAllocator, 0);
|
|
||||||
AZ_TYPE_INFO(AtlasBuilderInput, "{F54477F9-1BDE-4274-8CC0-8320A3EF4A42}");
|
|
||||||
|
|
||||||
bool m_forceSquare;
|
|
||||||
bool m_forcePowerOf2;
|
|
||||||
// Includes a white default texture for the UI to use under certain circumstances
|
|
||||||
bool m_includeWhiteTexture;
|
|
||||||
int m_maxDimension;
|
|
||||||
// At least this much padding will surround each texture except on the edges of the atlas
|
|
||||||
int m_padding;
|
|
||||||
// Color used in wasted space
|
|
||||||
AZ::Color m_unusedColor;
|
|
||||||
// A preset to use for the texture atlas image processing
|
|
||||||
AZStd::string m_presetName;
|
|
||||||
|
|
||||||
AZStd::vector<AZStd::string> m_filePaths;
|
|
||||||
AtlasBuilderInput():
|
|
||||||
m_forceSquare(false),
|
|
||||||
m_forcePowerOf2(false),
|
|
||||||
m_includeWhiteTexture(true),
|
|
||||||
m_maxDimension(4096),
|
|
||||||
m_padding(1),
|
|
||||||
// Default color should be a non-transparent color that isn't used often in uis
|
|
||||||
m_unusedColor(.235f, .702f, .443f, 1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
//! Attempts to read the input from a .texatlas file. "valid" is for reporting exceptions and telling the asset
|
|
||||||
//! proccesor to fail the job. Supports parsing through a human readable custom parser.
|
|
||||||
static AtlasBuilderInput ReadFromFile(const AZStd::string& path, const AZStd::string& directory, bool& valid);
|
|
||||||
|
|
||||||
//! Resolves any wild cards in paths
|
|
||||||
static void AddFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert);
|
|
||||||
|
|
||||||
//! Removes anything that matches the wildcard
|
|
||||||
static void RemoveFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
|
|
||||||
|
|
||||||
//! Resolves any folder paths into image file paths
|
|
||||||
static void AddFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert, bool& valid);
|
|
||||||
|
|
||||||
//! Resolves remove commands for folders
|
|
||||||
static void RemoveFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Struct that is used to represent an object with a width and height in pixels
|
|
||||||
struct ImageDimension
|
|
||||||
{
|
|
||||||
int m_width;
|
|
||||||
int m_height;
|
|
||||||
|
|
||||||
ImageDimension(int width, int height)
|
|
||||||
{
|
|
||||||
m_width = width;
|
|
||||||
m_height = height;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Typedef for an ImageDimension paired with an integer
|
|
||||||
using IndexImageDimension = AZStd::pair<int, ImageDimension>;
|
|
||||||
|
|
||||||
//! Typedef for a list of ImageDimensions paired with integers
|
|
||||||
using ImageDimensionData = AZStd::vector<IndexImageDimension>;
|
|
||||||
|
|
||||||
//! Typedef to simplify references to TextureAtlas::AtlasCoordinates
|
|
||||||
using AtlasCoordinates = TextureAtlasNamespace::AtlasCoordinates;
|
|
||||||
|
|
||||||
//! Number of bytes in a pixel
|
|
||||||
const int bytesPerPixel = 4;
|
|
||||||
|
|
||||||
//! The size of the padded sorting units (important for compression)
|
|
||||||
const int cellSize = 4;
|
|
||||||
|
|
||||||
//! Indexes of the products
|
|
||||||
enum class Product
|
|
||||||
{
|
|
||||||
TexatlasidxProduct = 0,
|
|
||||||
DdsProduct = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
//! An asset builder for texture atlases
|
|
||||||
class AtlasBuilderWorker : public AssetBuilderSDK::AssetBuilderCommandBus::Handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_RTTI(AtlasBuilderWorker, "{79036188-E017-4575-9EC0-8D39CB560EA6}");
|
|
||||||
|
|
||||||
AtlasBuilderWorker() = default;
|
|
||||||
~AtlasBuilderWorker() = default;
|
|
||||||
|
|
||||||
//! Asset Builder Callback Functions
|
|
||||||
|
|
||||||
//! Called by asset processor to gather information on a job for a ".texatlas" file
|
|
||||||
void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request,
|
|
||||||
AssetBuilderSDK::CreateJobsResponse& response);
|
|
||||||
//! Called by asset proccessor when it wants us to execute a job
|
|
||||||
void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request,
|
|
||||||
AssetBuilderSDK::ProcessJobResponse& response);
|
|
||||||
|
|
||||||
//! Returns the job related information used by the builder
|
|
||||||
static AssetBuilderSDK::JobDescriptor GetJobDescriptor(const AZStd::string& sourceFile, const AtlasBuilderInput& input);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//! AssetBuilderSDK::AssetBuilderCommandBus interface
|
|
||||||
void ShutDown() override; // if you get this you must fail all existing jobs and return.
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_isShuttingDown = false;
|
|
||||||
|
|
||||||
//! This is the main function that takes a set of inputs and attempts to pack them into an atlas of a given
|
|
||||||
//! size. Returns true if succesful, does not update out on failure.
|
|
||||||
static bool TryPack(const ImageDimensionData& images,
|
|
||||||
int targetWidth,
|
|
||||||
int targetHeight,
|
|
||||||
int padding,
|
|
||||||
size_t& amountFit,
|
|
||||||
AZStd::vector<AtlasCoordinates>& out);
|
|
||||||
|
|
||||||
//! Removes any overlap between slotList and the given item
|
|
||||||
static void TrimOverlap(AZStd::vector<AtlasCoordinates>& slotList, AtlasCoordinates item);
|
|
||||||
|
|
||||||
//! Uses the proper tightening method based on the input and returns the maximum number of items that were able to be fit
|
|
||||||
bool TryTightening(AtlasBuilderInput input,
|
|
||||||
const ImageDimensionData& images,
|
|
||||||
int smallestWidth,
|
|
||||||
int smallestHeight,
|
|
||||||
int targetArea,
|
|
||||||
int padding,
|
|
||||||
int& resultWidth,
|
|
||||||
int& resultHeight,
|
|
||||||
size_t& amountFit,
|
|
||||||
AZStd::vector<AtlasCoordinates>& out);
|
|
||||||
|
|
||||||
//! Finds the tightest square fit achievable by expanding a square area until a valid fit is found
|
|
||||||
bool TryTighteningSquare(const ImageDimensionData& images,
|
|
||||||
int lowerBound,
|
|
||||||
int maxDimension,
|
|
||||||
int targetArea,
|
|
||||||
bool powerOfTwo,
|
|
||||||
int padding,
|
|
||||||
int& resultWidth,
|
|
||||||
int& resultHeight,
|
|
||||||
size_t& amountFit,
|
|
||||||
AZStd::vector<AtlasCoordinates>& out);
|
|
||||||
|
|
||||||
//! Finds the tightest fit achievable by starting with the optimal thin solution and attempting to resize to be
|
|
||||||
//! a better shape
|
|
||||||
bool TryTighteningOptimal(const ImageDimensionData& images,
|
|
||||||
int smallestWidth,
|
|
||||||
int smallestHeight,
|
|
||||||
int maxDimension,
|
|
||||||
int targetArea,
|
|
||||||
bool powerOfTwo,
|
|
||||||
int padding,
|
|
||||||
int& resultWidth,
|
|
||||||
int& resultHeight,
|
|
||||||
size_t& amountFit,
|
|
||||||
AZStd::vector<AtlasCoordinates>& out);
|
|
||||||
|
|
||||||
//! Sorting logic for adding a slot to a sorted list in order to maintain increasing order
|
|
||||||
static void InsertInOrder(AZStd::vector<AtlasCoordinates>& slotList, AtlasCoordinates item);
|
|
||||||
|
|
||||||
//! Misc Logic For Estimating Target Shape
|
|
||||||
|
|
||||||
//! Returns the width of the widest element
|
|
||||||
static int GetWidest(const ImageDimensionData& imageList);
|
|
||||||
|
|
||||||
//! Returns the height of the tallest area
|
|
||||||
static int GetTallest(const ImageDimensionData& imageList);
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Used for sorting ImageDimensions
|
|
||||||
static bool operator<(ImageDimension a, ImageDimension b);
|
|
||||||
|
|
||||||
//! Used to expose the ImageDimension in a pair to AZStd::Sort
|
|
||||||
static bool operator<(IndexImageDimension a, IndexImageDimension b);
|
|
||||||
|
|
||||||
//! Returns true if two coordinate sets overlap
|
|
||||||
static bool Collides(AtlasCoordinates a, AtlasCoordinates b);
|
|
||||||
|
|
||||||
//! Returns true if item collides with any object in list
|
|
||||||
static bool Collides(AtlasCoordinates item, AZStd::vector<AtlasCoordinates> list);
|
|
||||||
|
|
||||||
//! Returns the portion of the second item that overlaps with the first
|
|
||||||
static AtlasCoordinates GetOverlap(AtlasCoordinates a, AtlasCoordinates b);
|
|
||||||
|
|
||||||
//! Performs an operation that copies a pixel to the output
|
|
||||||
static void SetPixels(AZ::u8* dest, const AZ::u8* source, int destBytes);
|
|
||||||
|
|
||||||
//! Checks if we can insert an image into a slot
|
|
||||||
static bool CanInsert(AtlasCoordinates slot, ImageDimension image, int padding, int farRight, int farBot);
|
|
||||||
|
|
||||||
//! Adds the necessary padding to an Atlas Coordinate
|
|
||||||
static void AddPadding(AtlasCoordinates& slot, int padding, int farRight, int farBot);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
*or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BuilderSettings/ImageProcessingDefines.h>
|
|
||||||
#include <BuilderSettings/BuilderSettings.h>
|
|
||||||
#include <AzCore/std/containers/set.h>
|
|
||||||
#include <AzCore/base.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
|
|
||||||
class QSettings;
|
|
||||||
class QString;
|
|
||||||
|
|
||||||
namespace AZ
|
|
||||||
{
|
|
||||||
template<class T> class EnvironmentVariable;
|
|
||||||
class SerializeContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class BuilderSettingManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_TYPE_INFO(CBuilderSettingManager, "{DAA55241-64FA-4A9B-A37F-C0A36B36D536}");
|
|
||||||
AZ_CLASS_ALLOCATOR(BuilderSettingManager, AZ::SystemAllocator, 0);
|
|
||||||
//load builder settings for all platform
|
|
||||||
//contain builder setting for all platforms
|
|
||||||
//this manager should be able to get texture setting for a platform
|
|
||||||
|
|
||||||
|
|
||||||
static BuilderSettingManager* Instance();
|
|
||||||
// life cycle management:
|
|
||||||
static void CreateInstance();
|
|
||||||
static void DestroyInstance();
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
const PresetSettings* GetPreset(const AZ::Uuid presetId, const PlatformName& platform = "");
|
|
||||||
|
|
||||||
const BuilderSettings* GetBuilderSetting(const PlatformName& platform);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to translate a legacy preset name into Open 3D Engine preset name.
|
|
||||||
* @param legacy preset name string
|
|
||||||
* @return A translated preset name. If no translation is available, returns the same value as input argument.
|
|
||||||
*/
|
|
||||||
const PresetName TranslateLegacyPresetName(const PresetName& legacyName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A list of platform supported
|
|
||||||
*/
|
|
||||||
const PlatformNameList GetPlatformList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A map of preset settings based on their filemasks.
|
|
||||||
* @key filemask string, empty string means no filemask
|
|
||||||
* @value set of preset setting names supporting the specified filemask
|
|
||||||
*/
|
|
||||||
const AZStd::map<FileMask, AZStd::set<PresetName>>& GetPresetFilterMap();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find preset id list based on the preset name.
|
|
||||||
* @param preset name string
|
|
||||||
* @return a map of preset ids whose name are specified by the input on different platforms
|
|
||||||
* @key platform name string
|
|
||||||
* @value uuid of the preset setting
|
|
||||||
*/
|
|
||||||
const AZ::Uuid GetPresetIdFromName(const PresetName& presetName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find preset name based on the preset id.
|
|
||||||
* @param uuid of the preset setting
|
|
||||||
* @return preset name string
|
|
||||||
*/
|
|
||||||
const PresetName GetPresetNameFromId(const AZ::Uuid& presetId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes preset data to file using AZ::Serialization format.
|
|
||||||
* @param filepath string to the build settings xml
|
|
||||||
*/
|
|
||||||
StringOutcome WriteBuilderSettings(AZStd::string filepath, AZ::SerializeContext* context = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads preset data from file using AZ::Serialization format.
|
|
||||||
* @param filepath string to the build settings xml
|
|
||||||
*/
|
|
||||||
StringOutcome LoadBuilderSettings(AZStd::string filepath, AZ::SerializeContext* context = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overload function. Loads preset data from project setting file if any
|
|
||||||
* Otherwise, the function will load default setting file inside the gem
|
|
||||||
*/
|
|
||||||
StringOutcome LoadBuilderSettings();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads preset data from legacy format found in RC.ini.
|
|
||||||
* @param filepath string to RC.ini
|
|
||||||
*/
|
|
||||||
StringOutcome LoadBuilderSettingsFromRC(AZStd::string& filePath);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first u32 generated from a hash of the builder settings
|
|
||||||
* file that can be used as a version to detect changes to the file.
|
|
||||||
*/
|
|
||||||
AZ::u32 BuilderSettingsVersion() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a full path to the adjacent metafile of a given texture/image file.
|
|
||||||
* @param Filepath string to the texture/image file.
|
|
||||||
* @param Output filepath string to the adjacent texture/image metafile.
|
|
||||||
* Will output whichever metafile is present, whether it is legacy or modern format.
|
|
||||||
* If both are present, modern format is returned.
|
|
||||||
* If none are present, an empty string is returned.
|
|
||||||
*/
|
|
||||||
void MetafilePathFromImagePath(const AZStd::string& imagePath, AZStd::string& metafilePath);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a suitable preset a given image file.
|
|
||||||
* @param imageFilePath: Filepath string of the image file. The function may load the image from the path for better detection
|
|
||||||
* @param image: an optional image object which can be used for preset selection if there is no match based file mask.
|
|
||||||
* @return suggested preset uuid.
|
|
||||||
*/
|
|
||||||
AZ::Uuid GetSuggestedPreset(const AZStd::string& imageFilePath, IImageObjectPtr image = nullptr);
|
|
||||||
|
|
||||||
bool DoesSupportPlatform(const AZStd::string& platformId);
|
|
||||||
|
|
||||||
static const char* s_environmentVariableName;
|
|
||||||
static AZ::EnvironmentVariable<BuilderSettingManager*> s_globalInstance;
|
|
||||||
static AZStd::mutex s_instanceMutex;
|
|
||||||
static const PlatformName s_defaultPlatform;
|
|
||||||
|
|
||||||
BuilderSettingManager(){}
|
|
||||||
|
|
||||||
private: // functions
|
|
||||||
AZ_DISABLE_COPY_MOVE(BuilderSettingManager);
|
|
||||||
|
|
||||||
StringOutcome ProcessPreset(QString& preset, QSettings& rcINI, PlatformNameVector& all_platforms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear Builder Settings and any cached maps/lists
|
|
||||||
*/
|
|
||||||
void ClearSettings();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Regenerate Builder Settings and any cached maps/lists
|
|
||||||
*/
|
|
||||||
void RegenerateMappings();
|
|
||||||
|
|
||||||
private: // variables
|
|
||||||
|
|
||||||
//builder settings for each platform
|
|
||||||
AZStd::map <PlatformName, BuilderSettings> m_builderSettings;
|
|
||||||
AZStd::map <PresetName, PresetName> m_presetAliases;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cached list of presets mapped by their file masks.
|
|
||||||
* @Key file mask, use empty string to indicate all presets without filtering
|
|
||||||
* @Value set of preset names that matches the file mask
|
|
||||||
*/
|
|
||||||
AZStd::map <FileMask, AZStd::set<PresetName> > m_presetFilterMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mutex to protect when modifying any map in this manager
|
|
||||||
*/
|
|
||||||
AZStd::mutex m_presetMapLock;
|
|
||||||
|
|
||||||
//default presets for certian file masks
|
|
||||||
AZStd::map <FileMask, AZ::Uuid > m_defaultPresetByFileMask;
|
|
||||||
|
|
||||||
//default preset for none power of two image
|
|
||||||
AZ::Uuid m_defaultPresetNonePOT;
|
|
||||||
|
|
||||||
//default preset for power of two
|
|
||||||
AZ::Uuid m_defaultPreset;
|
|
||||||
|
|
||||||
//default preset for power of two with alpha
|
|
||||||
AZ::Uuid m_defaultPresetAlpha;
|
|
||||||
|
|
||||||
//generated from hashing the builder settings file
|
|
||||||
AZ::u32 m_builderSettingsFileVersion;
|
|
||||||
};
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#include <BuilderSettings/BuilderSettings.h>
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
void BuilderSettings::Reflect(AZ::ReflectContext* context)
|
|
||||||
{
|
|
||||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
||||||
if (serialize)
|
|
||||||
{
|
|
||||||
serialize->Class<BuilderSettings>()
|
|
||||||
->Version(1)
|
|
||||||
->Field("GlossScale", &BuilderSettings::m_brdfGlossScale)
|
|
||||||
->Field("GlossBias", &BuilderSettings::m_brdfGlossBias)
|
|
||||||
->Field("Streaming", &BuilderSettings::m_enableStreaming)
|
|
||||||
->Field("Enable", &BuilderSettings::m_enablePlatform)
|
|
||||||
->Field("Presets", &BuilderSettings::m_presets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BuilderSettings/PresetSettings.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//builder setting for a platform
|
|
||||||
struct BuilderSettings
|
|
||||||
{
|
|
||||||
AZ_TYPE_INFO(BuilderSettings, "{4085AB56-934C-43A6-AF25-4443E1EEB71D}");
|
|
||||||
AZ_CLASS_ALLOCATOR(BuilderSettings, AZ::SystemAllocator, 0);
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
//global settings
|
|
||||||
float m_brdfGlossScale = 16.0f;
|
|
||||||
float m_brdfGlossBias = 0.0f;
|
|
||||||
bool m_enableStreaming = true;
|
|
||||||
bool m_enablePlatform = true;
|
|
||||||
AZStd::map<AZ::Uuid, PresetSettings> m_presets;
|
|
||||||
};
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#include <BuilderSettings/CubemapSettings.h>
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
|
|
||||||
bool CubemapSettings::operator!=(const CubemapSettings& other)
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CubemapSettings::operator==(const CubemapSettings& other)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
m_angle == other.m_angle &&
|
|
||||||
m_mipAngle == other.m_mipAngle &&
|
|
||||||
m_mipSlope == other.m_mipSlope &&
|
|
||||||
m_edgeFixup == other.m_edgeFixup &&
|
|
||||||
m_generateDiff == other.m_generateDiff &&
|
|
||||||
m_diffuseGenPreset == other.m_diffuseGenPreset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapSettings::Reflect(AZ::ReflectContext* context)
|
|
||||||
{
|
|
||||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
||||||
if (serialize)
|
|
||||||
{
|
|
||||||
serialize->Class<CubemapSettings>()
|
|
||||||
->Version(1)
|
|
||||||
->Field("Filter", &CubemapSettings::m_filter)
|
|
||||||
->Field("Angle", &CubemapSettings::m_angle)
|
|
||||||
->Field("MipAngle", &CubemapSettings::m_mipAngle)
|
|
||||||
->Field("MipSlope", &CubemapSettings::m_mipSlope)
|
|
||||||
->Field("EdgeFixup", &CubemapSettings::m_edgeFixup)
|
|
||||||
->Field("GenerateDiff", &CubemapSettings::m_generateDiff)
|
|
||||||
->Field("DiffuseProbePreset", &CubemapSettings::m_diffuseGenPreset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/RTTI/TypeInfo.h>
|
|
||||||
#include <AzCore/RTTI/ReflectContext.h>
|
|
||||||
#include <AzCore/Memory/Memory.h>
|
|
||||||
#include <BuilderSettings/ImageProcessingDefines.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//! settings related to cubemap. Part of texture preset setting. only useful when cubemap enabled
|
|
||||||
struct CubemapSettings
|
|
||||||
{
|
|
||||||
AZ_TYPE_INFO(CubemapSettings, "{C6BDEB7B-8E05-4B2D-8F39-8F6275BC84E8}");
|
|
||||||
AZ_CLASS_ALLOCATOR(CubemapSettings, AZ::SystemAllocator, 0);
|
|
||||||
bool operator!=(const CubemapSettings& other);
|
|
||||||
bool operator==(const CubemapSettings& other);
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
// "cm_ftype", cubemap angular filter type: gaussian, cone, disc, cosine, cosine_power, ggx
|
|
||||||
CubemapFilterType m_filter;
|
|
||||||
|
|
||||||
// "cm_fangle", base filter angle for cubemap filtering(degrees), 0 - disabled
|
|
||||||
float m_angle;
|
|
||||||
|
|
||||||
// "cm_fmipangle", initial mip filter angle for cubemap filtering(degrees), 0 - disabled
|
|
||||||
float m_mipAngle;
|
|
||||||
|
|
||||||
// "cm_fmipslope", mip filter angle multiplier for cubemap filtering, 1 - default"
|
|
||||||
float m_mipSlope;
|
|
||||||
|
|
||||||
// "cm_edgefixup", cubemap edge fix-up width, 0 - disabled
|
|
||||||
float m_edgeFixup;
|
|
||||||
|
|
||||||
// "cm_diff", generate a diffuse illumination light-probe in addition
|
|
||||||
bool m_generateDiff;
|
|
||||||
|
|
||||||
// "cm_diffpreset", the name of the preset to be used for the diffuse probe
|
|
||||||
AZ::Uuid m_diffuseGenPreset;
|
|
||||||
};
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/std/containers/map.h>
|
|
||||||
#include <AzCore/std/containers/vector.h>
|
|
||||||
#include <AzCore/std/containers/list.h>
|
|
||||||
#include <AzCore/std/string/string.h>
|
|
||||||
#include <AzCore/Outcome/Outcome.h>
|
|
||||||
#include <AzCore/base.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand for checking a condition, and failing if false.
|
|
||||||
* Works with any function that returns AZ::Outcome<..., AZStd::string>.
|
|
||||||
* Unlike assert, it is not removed in release builds.
|
|
||||||
* Ensure all strings are passed with c_str(), as they are passed to AZStd::string::format().
|
|
||||||
*/
|
|
||||||
#define AZ_ENSURE_STRING_OUTCOME_CONDITION(cond, ...) if (!(cond)) { return AZ::Failure(AZStd::string::format(__VA_ARGS__)); }
|
|
||||||
|
|
||||||
// Similar to above macro, but ensures on an AZ::Outcome. Not removed in release builds.
|
|
||||||
#define AZ_ENSURE_STRING_OUTCOME(outcome) if (!(outcome.IsSuccess())) { return AZ::Failure(outcome.GetError()); }
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//! Common return type for operations that can fail.
|
|
||||||
// Empty success string == Success.
|
|
||||||
// Populated success string == Warning.
|
|
||||||
// Populated error string == Failure.
|
|
||||||
using StringOutcome = AZ::Outcome<AZStd::string, AZStd::string>;
|
|
||||||
#define STRING_OUTCOME_SUCCESS AZ::Success(AZStd::string())
|
|
||||||
#define STRING_OUTCOME_WARNING(warning) AZ::Success(AZStd::string(warning))
|
|
||||||
#define STRING_OUTCOME_ERROR(error) AZ::Failure(AZStd::string(error))
|
|
||||||
|
|
||||||
// Common typedefs (with dependent forward-declarations)
|
|
||||||
typedef AZStd::string PlatformName, PresetName, FileMask;
|
|
||||||
typedef AZStd::vector<PlatformName> PlatformNameVector;
|
|
||||||
typedef AZStd::list<PlatformName> PlatformNameList;
|
|
||||||
|
|
||||||
//! min and max reduce level
|
|
||||||
static const unsigned int s_MinReduceLevel = 0;
|
|
||||||
static const unsigned int s_MaxReduceLevel = 5;
|
|
||||||
|
|
||||||
static const int s_TotalSupportedImageExtensions = 8;
|
|
||||||
static const char* s_SupportedImageExtensions[s_TotalSupportedImageExtensions] = {
|
|
||||||
"*.tif",
|
|
||||||
"*.tiff",
|
|
||||||
"*.png",
|
|
||||||
"*.bmp",
|
|
||||||
"*.jpg",
|
|
||||||
"*.jpeg",
|
|
||||||
"*.tga",
|
|
||||||
"*.gif"
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class RGBWeight : AZ::u32
|
|
||||||
{
|
|
||||||
uniform, // uniform weights (1.0, 1.0, 1.0) (default)
|
|
||||||
luminance, // luminance-based weights (0.3086, 0.6094, 0.0820)
|
|
||||||
ciexyz // ciexyz-based weights (0.2126, 0.7152, 0.0722)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ColorSpace : AZ::u32
|
|
||||||
{
|
|
||||||
linear,
|
|
||||||
sRGB,
|
|
||||||
autoSelect,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MipGenType : AZ::u32
|
|
||||||
{
|
|
||||||
point, //Also called nearest neighbor
|
|
||||||
box, //Also called 'average'. When shrinking images it will average, and merge the pixels together.
|
|
||||||
triangle, //Also called linear or Bartlett window
|
|
||||||
quadratic, //Also called bilinear or Welch window
|
|
||||||
gaussian, //It remove high frequency noise in a highly controllable way.
|
|
||||||
blackmanHarris,
|
|
||||||
kaiserSinc //Good for foliage and tree assets exported from Speedtree.
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MipGenEvalType : AZ::u32
|
|
||||||
{
|
|
||||||
sum,
|
|
||||||
max,
|
|
||||||
min
|
|
||||||
};
|
|
||||||
|
|
||||||
//cubemap angular filter type. Only two filter types were used in rc.ini
|
|
||||||
enum class CubemapFilterType : AZ::u32
|
|
||||||
{
|
|
||||||
disc = 0, // same as CP_FILTER_TYPE_DISC in CubemapGen
|
|
||||||
cone = 1, // same as CP_FILTER_TYPE_CONE
|
|
||||||
cosine = 2, // same as CP_FILTER_TYPE_COSINE. only used for [EnvironmentProbeHDR_Irradiance]
|
|
||||||
gaussian = 3, // same as CP_FILTER_TYPE_ANGULAR_GAUSSIAN
|
|
||||||
cosine_power = 4, // same as CP_FILTER_TYPE_COSINE_POWER
|
|
||||||
ggx = 5 // same as CP_FILTER_TYPE_GGX. only used for [EnvironmentProbeHDR]
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#include <BuilderSettings/MipmapSettings.h>
|
|
||||||
#include <AzCore/Serialization/EditContext.h>
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
bool MipmapSettings::operator!=(const MipmapSettings& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MipmapSettings::operator==(const MipmapSettings& other) const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
m_type == other.m_type &&
|
|
||||||
m_borderColor == other.m_borderColor &&
|
|
||||||
m_normalize == other.m_normalize &&
|
|
||||||
m_streamableMips == other.m_streamableMips;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MipmapSettings::Reflect(AZ::ReflectContext* context)
|
|
||||||
{
|
|
||||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
||||||
if (serialize)
|
|
||||||
{
|
|
||||||
serialize->Class<MipmapSettings>()
|
|
||||||
->Version(1)
|
|
||||||
->Field("MipGenType", &MipmapSettings::m_type)
|
|
||||||
->Field("BorderColor", &MipmapSettings::m_borderColor)
|
|
||||||
->Field("Normalize", &MipmapSettings::m_normalize)
|
|
||||||
->Field("StreamableMips", &MipmapSettings::m_streamableMips);
|
|
||||||
|
|
||||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
|
||||||
if (editContext)
|
|
||||||
{
|
|
||||||
editContext->Class<MipmapSettings>("Mipmap Setting", "")
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &MipmapSettings::m_type, "Type", "")
|
|
||||||
->EnumAttribute(MipGenType::point, "Point")
|
|
||||||
->EnumAttribute(MipGenType::box, "Average")
|
|
||||||
->EnumAttribute(MipGenType::triangle, "Linear")
|
|
||||||
->EnumAttribute(MipGenType::quadratic, "Bilinear")
|
|
||||||
->EnumAttribute(MipGenType::gaussian, "Gaussian")
|
|
||||||
->EnumAttribute(MipGenType::blackmanHarris, "BlackmanHarris")
|
|
||||||
->EnumAttribute(MipGenType::kaiserSinc, "KaiserSinc")
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::Color, &MipmapSettings::m_borderColor, "Color", "")
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &MipmapSettings::m_normalize, "Normalized", "")
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::SpinBox, &MipmapSettings::m_streamableMips, "Streamable Mips", "")
|
|
||||||
->Attribute(AZ::Edit::Attributes::Min, 0)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BuilderSettings/ImageProcessingDefines.h>
|
|
||||||
#include <AzCore/RTTI/TypeInfo.h>
|
|
||||||
#include <AzCore/RTTI/ReflectContext.h>
|
|
||||||
#include <AzCore/Memory/Memory.h>
|
|
||||||
#include <AzCore/Math/Color.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
struct MipmapSettings
|
|
||||||
{
|
|
||||||
AZ_TYPE_INFO(MipmapSettings, "{9239618E-23A6-43C8-9B87-50528CBFA6FF}");
|
|
||||||
AZ_CLASS_ALLOCATOR(MipmapSettings, AZ::SystemAllocator, 0);
|
|
||||||
bool operator!=(const MipmapSettings& other) const;
|
|
||||||
bool operator==(const MipmapSettings& other) const;
|
|
||||||
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
MipGenType m_type = MipGenType::blackmanHarris;
|
|
||||||
|
|
||||||
//Unused or duplicated properties. We may want to move same properties from perset setting to here.
|
|
||||||
AZ::Color m_borderColor;
|
|
||||||
bool m_normalize;
|
|
||||||
AZ::u32 m_streamableMips;
|
|
||||||
};
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/RTTI/TypeInfo.h>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <BuilderSettings/ImageProcessingDefines.h>
|
|
||||||
#include <BuilderSettings/PixelFormats.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//! default settings for platform
|
|
||||||
struct PlatformSetting
|
|
||||||
{
|
|
||||||
AZ_TYPE_INFO(PlatformSetting, "{19EF828B-DDFF-4591-AD5A-946801FCC98E}");
|
|
||||||
AZ_CLASS_ALLOCATOR(PlatformSetting, AZ::SystemAllocator, 0);
|
|
||||||
|
|
||||||
//! Platform's name
|
|
||||||
PlatformName m_name;
|
|
||||||
|
|
||||||
//! pixel formats supported for the platform
|
|
||||||
AZStd::list<EPixelFormat> m_availableFormat;
|
|
||||||
};
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,213 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#include <BuilderSettings/PresetSettings.h>
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
PresetSettings::PresetSettings()
|
|
||||||
: m_uuid(0)
|
|
||||||
, m_rgbWeight(RGBWeight::uniform)
|
|
||||||
, m_srcColorSpace(ColorSpace::sRGB)
|
|
||||||
, m_destColorSpace(ColorSpace::autoSelect)
|
|
||||||
, m_suppressEngineReduce(false)
|
|
||||||
, m_pixelFormat(ePixelFormat_R8G8B8A8)
|
|
||||||
, m_pixelFormatName("R8G8B8A8")
|
|
||||||
, m_pixelFormatAlpha(ePixelFormat_Unknown)
|
|
||||||
, m_pixelFormatAlphaName("")
|
|
||||||
, m_discardAlpha(false)
|
|
||||||
, m_maxTextureSize(0)
|
|
||||||
, m_minTextureSize(0)
|
|
||||||
, m_isPowerOf2(false)
|
|
||||||
, m_sizeReduceLevel(0)
|
|
||||||
, m_isColorChart(0)
|
|
||||||
, m_highPassMip(0)
|
|
||||||
, m_glossFromNormals(false)
|
|
||||||
, m_isMipRenormalize(false)
|
|
||||||
, m_numStreamableMips(100)
|
|
||||||
, m_isLegacyGloss(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PresetSettings::PresetSettings(const PresetSettings& other)
|
|
||||||
{
|
|
||||||
DeepCopyMembers(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PresetSettings::Reflect(AZ::ReflectContext* context)
|
|
||||||
{
|
|
||||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
||||||
if (serialize)
|
|
||||||
{
|
|
||||||
serialize->Class<PresetSettings>()
|
|
||||||
->Version(1)
|
|
||||||
->Field("UUID", &PresetSettings::m_uuid)
|
|
||||||
->Field("Name", &PresetSettings::m_name)
|
|
||||||
->Field("Description", &PresetSettings::m_description)
|
|
||||||
->Field("RGB_Weight", &PresetSettings::m_rgbWeight)
|
|
||||||
->Field("SourceColor", &PresetSettings::m_srcColorSpace)
|
|
||||||
->Field("DestColor", &PresetSettings::m_destColorSpace)
|
|
||||||
->Field("FileMasks", &PresetSettings::m_fileMasks)
|
|
||||||
->Field("SuppressEngineReduce", &PresetSettings::m_suppressEngineReduce)
|
|
||||||
->Field("PixelFormat", &PresetSettings::m_pixelFormatName)
|
|
||||||
->Field("PixelFormatAlpha", &PresetSettings::m_pixelFormatAlphaName)
|
|
||||||
->Field("DiscardAlpha", &PresetSettings::m_discardAlpha)
|
|
||||||
->Field("MaxTextureSize", &PresetSettings::m_maxTextureSize)
|
|
||||||
->Field("MinTextureSize", &PresetSettings::m_minTextureSize)
|
|
||||||
->Field("IsPowerOf2", &PresetSettings::m_isPowerOf2)
|
|
||||||
->Field("SizeReduceLevel", &PresetSettings::m_sizeReduceLevel)
|
|
||||||
->Field("IsColorChart", &PresetSettings::m_isColorChart)
|
|
||||||
->Field("HighPassMip", &PresetSettings::m_highPassMip)
|
|
||||||
->Field("GlossFromNormal", &PresetSettings::m_glossFromNormals)
|
|
||||||
->Field("UseLegacyGloss", &PresetSettings::m_isLegacyGloss)
|
|
||||||
->Field("MipRenormalize", &PresetSettings::m_isMipRenormalize)
|
|
||||||
->Field("NumberStreamableMips", &PresetSettings::m_numStreamableMips)
|
|
||||||
->Field("Swizzle", &PresetSettings::m_swizzle)
|
|
||||||
->Field("CubemapSettings", &PresetSettings::m_cubemapSetting)
|
|
||||||
->Field("MipMapSetting", &PresetSettings::m_mipmapSetting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PresetSettings& PresetSettings::operator= (const PresetSettings& other)
|
|
||||||
{
|
|
||||||
DeepCopyMembers(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PresetSettings::operator==(const PresetSettings& other) const
|
|
||||||
{
|
|
||||||
bool arePointersEqual = true;
|
|
||||||
|
|
||||||
///////
|
|
||||||
// MipMap Settings
|
|
||||||
//////
|
|
||||||
// If both pointers are allocated...
|
|
||||||
if (m_mipmapSetting && other.m_mipmapSetting)
|
|
||||||
{
|
|
||||||
// If the allocated values are different...
|
|
||||||
if (*m_mipmapSetting != *other.m_mipmapSetting)
|
|
||||||
{
|
|
||||||
arePointersEqual = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, one or both pointers are un-allocated.
|
|
||||||
// If only one pointer is allocated (via unequivalency)...
|
|
||||||
else if (m_mipmapSetting != other.m_mipmapSetting)
|
|
||||||
{
|
|
||||||
arePointersEqual = false;
|
|
||||||
}
|
|
||||||
///////
|
|
||||||
// CubeMap Settings
|
|
||||||
//////
|
|
||||||
// If both pointers are allocated...
|
|
||||||
if (m_cubemapSetting && other.m_cubemapSetting)
|
|
||||||
{
|
|
||||||
// If the allocated values are different...
|
|
||||||
if (*m_cubemapSetting != *other.m_cubemapSetting)
|
|
||||||
{
|
|
||||||
arePointersEqual = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, one or both pointers are un-allocated.
|
|
||||||
// If only one pointer is allocated (via unequivalency)...
|
|
||||||
else if (m_cubemapSetting != other.m_cubemapSetting)
|
|
||||||
{
|
|
||||||
arePointersEqual = false;
|
|
||||||
}
|
|
||||||
return
|
|
||||||
arePointersEqual &&
|
|
||||||
m_uuid == other.m_uuid &&
|
|
||||||
m_name == other.m_name &&
|
|
||||||
m_description == other.m_description &&
|
|
||||||
m_rgbWeight == other.m_rgbWeight &&
|
|
||||||
m_srcColorSpace == other.m_srcColorSpace &&
|
|
||||||
m_destColorSpace == other.m_destColorSpace &&
|
|
||||||
m_fileMasks == other.m_fileMasks &&
|
|
||||||
m_suppressEngineReduce == other.m_suppressEngineReduce &&
|
|
||||||
m_pixelFormat == other.m_pixelFormat &&
|
|
||||||
m_pixelFormatName == other.m_pixelFormatName &&
|
|
||||||
m_pixelFormatAlpha == other.m_pixelFormatAlpha &&
|
|
||||||
m_pixelFormatAlphaName == other.m_pixelFormatAlphaName &&
|
|
||||||
m_discardAlpha == other.m_discardAlpha &&
|
|
||||||
m_minTextureSize == other.m_minTextureSize &&
|
|
||||||
m_maxTextureSize == other.m_maxTextureSize &&
|
|
||||||
m_isPowerOf2 == other.m_isPowerOf2 &&
|
|
||||||
m_sizeReduceLevel == other.m_sizeReduceLevel &&
|
|
||||||
m_isColorChart == other.m_isColorChart &&
|
|
||||||
m_highPassMip == other.m_highPassMip &&
|
|
||||||
m_glossFromNormals == other.m_glossFromNormals &&
|
|
||||||
m_isLegacyGloss == other.m_isLegacyGloss &&
|
|
||||||
m_swizzle == other.m_swizzle &&
|
|
||||||
m_isMipRenormalize == other.m_isMipRenormalize &&
|
|
||||||
m_numStreamableMips == other.m_numStreamableMips;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PresetSettings::DeepCopyMembers(const PresetSettings & other)
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
{
|
|
||||||
if(other.m_mipmapSetting)
|
|
||||||
{
|
|
||||||
m_mipmapSetting = AZStd::make_unique<MipmapSettings>(*other.m_mipmapSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(other.m_cubemapSetting)
|
|
||||||
{
|
|
||||||
m_cubemapSetting = AZStd::make_unique<CubemapSettings>(*other.m_cubemapSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_uuid = other.m_uuid;
|
|
||||||
m_name = other.m_name;
|
|
||||||
m_description = other.m_description;
|
|
||||||
m_rgbWeight = other.m_rgbWeight;
|
|
||||||
m_srcColorSpace = other.m_srcColorSpace;
|
|
||||||
m_destColorSpace = other.m_destColorSpace;
|
|
||||||
m_fileMasks = other.m_fileMasks;
|
|
||||||
m_suppressEngineReduce = other.m_suppressEngineReduce;
|
|
||||||
m_pixelFormat = other.m_pixelFormat;
|
|
||||||
m_pixelFormatAlpha = other.m_pixelFormatAlpha;
|
|
||||||
m_pixelFormatName = other.m_pixelFormatName;
|
|
||||||
m_pixelFormatAlphaName = other.m_pixelFormatAlphaName;
|
|
||||||
m_discardAlpha = other.m_discardAlpha;
|
|
||||||
m_minTextureSize = other.m_minTextureSize;
|
|
||||||
m_maxTextureSize = other.m_maxTextureSize;
|
|
||||||
m_isPowerOf2 = other.m_isPowerOf2;
|
|
||||||
m_sizeReduceLevel = other.m_sizeReduceLevel;
|
|
||||||
m_isColorChart = other.m_isColorChart;
|
|
||||||
m_highPassMip = other.m_highPassMip;
|
|
||||||
m_glossFromNormals = other.m_glossFromNormals;
|
|
||||||
m_isLegacyGloss = other.m_isLegacyGloss;
|
|
||||||
m_swizzle = other.m_swizzle;
|
|
||||||
m_isMipRenormalize = other.m_isMipRenormalize;
|
|
||||||
m_numStreamableMips = other.m_numStreamableMips;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::Vector3 PresetSettings::GetColorWeight()
|
|
||||||
{
|
|
||||||
switch (m_rgbWeight)
|
|
||||||
{
|
|
||||||
case RGBWeight::uniform:
|
|
||||||
return AZ::Vector3(0.3333f, 0.3334f, 0.3333f);
|
|
||||||
case RGBWeight::ciexyz:
|
|
||||||
return AZ::Vector3(0.2126f, 0.7152f, 0.0722f);
|
|
||||||
case RGBWeight::luminance:
|
|
||||||
return AZ::Vector3(0.3086f, 0.6094f, 0.0820f);
|
|
||||||
default:
|
|
||||||
AZ_Assert(false, "color weight value need to be added to new rgbWeight enum");
|
|
||||||
return AZ::Vector3(0.3333f, 0.3334f, 0.3333f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/RTTI/TypeInfo.h>
|
|
||||||
#include <BuilderSettings/ImageProcessingDefines.h>
|
|
||||||
#include <BuilderSettings/CubemapSettings.h>
|
|
||||||
#include <BuilderSettings/MipmapSettings.h>
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//settings for texture process preset
|
|
||||||
class PresetSettings
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_TYPE_INFO(PresetSettings, "{935BCE3F-9E76-494E-9408-47C5937D7288}");
|
|
||||||
AZ_CLASS_ALLOCATOR(PresetSettings, AZ::SystemAllocator, 0);
|
|
||||||
|
|
||||||
PresetSettings();
|
|
||||||
PresetSettings(const PresetSettings& other);
|
|
||||||
PresetSettings& operator= (const PresetSettings& other);
|
|
||||||
bool operator== (const PresetSettings& other) const;
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
//unique id for the preset
|
|
||||||
AZ::Uuid m_uuid;
|
|
||||||
|
|
||||||
PresetName m_name;
|
|
||||||
|
|
||||||
//a brief description for the usage of this Preset
|
|
||||||
AZStd::string m_description;
|
|
||||||
|
|
||||||
//misc options
|
|
||||||
// "rgbweights". specify preset for weighting of R,G,B channels (used by compressor)
|
|
||||||
RGBWeight m_rgbWeight;
|
|
||||||
ColorSpace m_srcColorSpace;
|
|
||||||
ColorSpace m_destColorSpace;
|
|
||||||
|
|
||||||
// file masks used for helping select default preset and option preset list in texture property dialog
|
|
||||||
AZStd::vector<FileMask> m_fileMasks;
|
|
||||||
|
|
||||||
// "ser". Whether to enable supress reduce resolution (m_sizeReduceLevel) during loading, 0(default)
|
|
||||||
bool m_suppressEngineReduce;
|
|
||||||
|
|
||||||
//pixel format
|
|
||||||
EPixelFormat m_pixelFormat;
|
|
||||||
AZStd::string m_pixelFormatName;
|
|
||||||
//pixel format for image which only contains alpha channel. this is for if we need to save alpha channel into a seperate image
|
|
||||||
EPixelFormat m_pixelFormatAlpha;
|
|
||||||
AZStd::string m_pixelFormatAlphaName;
|
|
||||||
bool m_discardAlpha;
|
|
||||||
|
|
||||||
// Resolution related settings
|
|
||||||
|
|
||||||
// "maxtexturesize", upper limit of the resolution of generated textures. It should be a power-of-2 number larger than 1
|
|
||||||
// resulting texture will be downscaled if its width or height larger than this value
|
|
||||||
// 0 - no upper resolution limit (default)
|
|
||||||
unsigned int m_maxTextureSize;
|
|
||||||
|
|
||||||
// "mintexturesize", lower limit of the resolution of generated textures.It should be a power-of-2 number larger than 1
|
|
||||||
// resulting texture will be upscaled if its width or height smaller than this value
|
|
||||||
// 0 - no lower resolution limit (default)
|
|
||||||
unsigned int m_minTextureSize;
|
|
||||||
|
|
||||||
bool m_isPowerOf2;
|
|
||||||
|
|
||||||
//"reduce", 0=no size reduce /1=half resolution /2=quarter resolution, etc"
|
|
||||||
unsigned int m_sizeReduceLevel;
|
|
||||||
|
|
||||||
//settings for cubemap generation. it's null if this preset is not for cubemap.
|
|
||||||
//"cm" equals 1 to enable cubemap in rc.ini
|
|
||||||
AZStd::unique_ptr<CubemapSettings> m_cubemapSetting;
|
|
||||||
|
|
||||||
//settings for mipmap generation. it's null if this preset disable mipmap.
|
|
||||||
AZStd::unique_ptr<MipmapSettings> m_mipmapSetting;
|
|
||||||
|
|
||||||
//some specific settings
|
|
||||||
// "colorchart". This is to indicate if need to extract color chart from the image and output the color chart data.
|
|
||||||
// This is very specific usage for cryEngine. Check ColorChart.cpp for better explaination.
|
|
||||||
bool m_isColorChart;
|
|
||||||
|
|
||||||
//"highpass". Defines which mip level is subtracted when applying the high pass filter
|
|
||||||
//this is only used for terrain asset. we might remove it later since it can be done with source image directly
|
|
||||||
AZ::u32 m_highPassMip;
|
|
||||||
|
|
||||||
//"glossfromnormals". Bake normal variance into smoothness stored in alpha channel
|
|
||||||
AZ::u32 m_glossFromNormals;
|
|
||||||
|
|
||||||
//"mipnormalize". need normalize the rgb
|
|
||||||
bool m_isMipRenormalize;
|
|
||||||
|
|
||||||
//function to get color's rgb weight in vec3 based on m_rgbWeight enum
|
|
||||||
//this is useful for squisher compression
|
|
||||||
AZ::Vector3 GetColorWeight();
|
|
||||||
|
|
||||||
//numstreamablemips
|
|
||||||
AZ::u32 m_numStreamableMips;
|
|
||||||
|
|
||||||
//legacy options might be removed later
|
|
||||||
//"glosslegacydist". If the gloss map use legacy distribution. NW is still using legacy dist
|
|
||||||
bool m_isLegacyGloss;
|
|
||||||
|
|
||||||
//"swizzle". need to be 4 character and each character need to be one of "rgba01"
|
|
||||||
AZStd::string m_swizzle;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void DeepCopyMembers(const PresetSettings& other);
|
|
||||||
};
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,589 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#include <BuilderSettings/TextureSettings.h>
|
|
||||||
#include <AzCore/RTTI/ReflectContext.h>
|
|
||||||
#include <AzCore/Serialization/EditContext.h>
|
|
||||||
#include <AzFramework/StringFunc/StringFunc.h>
|
|
||||||
#include <AzCore/IO/FileIO.h>
|
|
||||||
#include <AzCore/IO/SystemFile.h>
|
|
||||||
#include <AzCore/Serialization/Utils.h>
|
|
||||||
|
|
||||||
#include <BuilderSettings/BuilderSettingManager.h>
|
|
||||||
#include <ImageLoader/ImageLoaders.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
const char* TextureSettings::legacyExtensionName = ".exportsettings";
|
|
||||||
const char* TextureSettings::modernExtensionName = ".imagesettings";
|
|
||||||
|
|
||||||
StringOutcome ParseLegacyTextureSettingString(AZStd::string& key, AZStd::string& value, TextureSettings& textureSettingOut)
|
|
||||||
{
|
|
||||||
// Parse only the settings we support for TextureSetting
|
|
||||||
if ("reduce" == key) // Example: reduce=0
|
|
||||||
{
|
|
||||||
int reduce = AzFramework::StringFunc::ToInt(value.c_str());
|
|
||||||
if (reduce >= 0)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_sizeReduceLevel = reduce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("M" == key) // Example: M=50,50,0,50,50,50
|
|
||||||
{
|
|
||||||
textureSettingOut.m_enableMipmap = true;
|
|
||||||
|
|
||||||
AZStd::vector<AZStd::string> mipStringValues;
|
|
||||||
AzFramework::StringFunc::Tokenize(value.c_str(), mipStringValues, ',');
|
|
||||||
|
|
||||||
for (size_t mipIndex = 0; mipIndex < mipStringValues.size(); ++mipIndex)
|
|
||||||
{
|
|
||||||
AZ::u32 mipValue = AzFramework::StringFunc::ToInt(mipStringValues[mipIndex].c_str());
|
|
||||||
textureSettingOut.m_mipAlphaAdjust[mipIndex] = mipValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("ser" == key) // Example: ser=1
|
|
||||||
{
|
|
||||||
textureSettingOut.m_suppressEngineReduce = (value == "1");
|
|
||||||
}
|
|
||||||
else if ("preset" == key) // Example: preset=NormalsWithSmoothness
|
|
||||||
{
|
|
||||||
AZ::Uuid presetUuid = BuilderSettingManager::Instance()->GetPresetIdFromName(value);
|
|
||||||
|
|
||||||
// There's a chance the preset name still adheres to legacy preset naming convention (from CryEngine).
|
|
||||||
const PresetName translation = BuilderSettingManager::Instance()->TranslateLegacyPresetName(value);
|
|
||||||
AZ::Uuid translatedPresetUuid = BuilderSettingManager::Instance()->GetPresetIdFromName(translation);
|
|
||||||
|
|
||||||
if (!presetUuid.IsNull())
|
|
||||||
{
|
|
||||||
textureSettingOut.m_preset = presetUuid;
|
|
||||||
}
|
|
||||||
else if (!translatedPresetUuid.IsNull())
|
|
||||||
{
|
|
||||||
textureSettingOut.m_preset = translatedPresetUuid;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Image processing", false, "Can't find preset %s", value.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("mipgentype" == key) // Example: mipgentype=box
|
|
||||||
{
|
|
||||||
if ("box" == value || "average" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::box;
|
|
||||||
}
|
|
||||||
else if ("gauss" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::gaussian;
|
|
||||||
}
|
|
||||||
else if ("blackman-harris" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::blackmanHarris;
|
|
||||||
}
|
|
||||||
else if ("kaiser" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::kaiserSinc;
|
|
||||||
}
|
|
||||||
else if ("point" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::point;
|
|
||||||
}
|
|
||||||
else if ("quadric" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::quadratic;
|
|
||||||
}
|
|
||||||
else if ("triangle" == value)
|
|
||||||
{
|
|
||||||
textureSettingOut.m_mipGenType = MipGenType::triangle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return STRING_OUTCOME_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureSettings::TextureSettings()
|
|
||||||
: m_preset(0)
|
|
||||||
, m_sizeReduceLevel(0)
|
|
||||||
, m_suppressEngineReduce(false)
|
|
||||||
, m_enableMipmap(true)
|
|
||||||
, m_maintainAlphaCoverage(false)
|
|
||||||
, m_mipGenEval(MipGenEvalType::sum)
|
|
||||||
, m_mipGenType(MipGenType::blackmanHarris)
|
|
||||||
{
|
|
||||||
const int defaultMipMapValue = 50;
|
|
||||||
|
|
||||||
for (int i = 0; i < s_MaxMipMaps; ++i)
|
|
||||||
{
|
|
||||||
m_mipAlphaAdjust.push_back(defaultMipMapValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureSettings::Reflect(AZ::ReflectContext* context)
|
|
||||||
{
|
|
||||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
||||||
if (serialize)
|
|
||||||
{
|
|
||||||
serialize->Class<TextureSettings>()
|
|
||||||
->Version(1)
|
|
||||||
->Field("PresetID", &TextureSettings::m_preset)
|
|
||||||
->Field("SizeReduceLevel", &TextureSettings::m_sizeReduceLevel)
|
|
||||||
->Field("EngineReduce", &TextureSettings::m_suppressEngineReduce)
|
|
||||||
->Field("EnableMipmap", &TextureSettings::m_enableMipmap)
|
|
||||||
->Field("MaintainAlphaCoverage", &TextureSettings::m_maintainAlphaCoverage)
|
|
||||||
->Field("MipMapAlphaAdjustments", &TextureSettings::m_mipAlphaAdjust)
|
|
||||||
->Field("MipMapGenEval", &TextureSettings::m_mipGenEval)
|
|
||||||
->Field("MipMapGenType", &TextureSettings::m_mipGenType)
|
|
||||||
->Field("PlatformSpecificOverrides", &TextureSettings::m_platfromOverrides)
|
|
||||||
->Field("OverridingPlatform", &TextureSettings::m_overridingPlatform);
|
|
||||||
|
|
||||||
AZ::EditContext* edit = serialize->GetEditContext();
|
|
||||||
if (edit)
|
|
||||||
{
|
|
||||||
edit->Class<TextureSettings>("Texture Setting", "")
|
|
||||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
|
||||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
|
||||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::Default, &TextureSettings::m_mipAlphaAdjust, "Alpha Test Bias", "Multiplies the mipmap's alpha with a scale value that is based on alpha coverage. \
|
|
||||||
Set the mip 0 to mip 5 values to offset the alpha test values and ensure the mipmap's alpha coverage matches the original image. Specify a value from 0 to 100.")
|
|
||||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
|
||||||
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
|
|
||||||
->ElementAttribute(AZ::Edit::UIHandlers::Handler, AZ::Edit::UIHandlers::Slider)
|
|
||||||
->ElementAttribute(AZ::Edit::Attributes::Min, 0)
|
|
||||||
->ElementAttribute(AZ::Edit::Attributes::Max, 100)
|
|
||||||
->ElementAttribute(AZ::Edit::Attributes::Step, 1)
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &TextureSettings::m_mipGenType, "Filter Method", "")
|
|
||||||
->EnumAttribute(MipGenType::point, "Point")
|
|
||||||
->EnumAttribute(MipGenType::box, "Average")
|
|
||||||
->EnumAttribute(MipGenType::triangle, "Linear")
|
|
||||||
->EnumAttribute(MipGenType::quadratic, "Bilinear")
|
|
||||||
->EnumAttribute(MipGenType::gaussian, "Gaussian")
|
|
||||||
->EnumAttribute(MipGenType::blackmanHarris, "BlackmanHarris")
|
|
||||||
->EnumAttribute(MipGenType::kaiserSinc, "KaiserSinc")
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &TextureSettings::m_mipGenEval, "Pixel Sampling Type", "")
|
|
||||||
->EnumAttribute(MipGenEvalType::max, "Max")
|
|
||||||
->EnumAttribute(MipGenEvalType::min, "Min")
|
|
||||||
->EnumAttribute(MipGenEvalType::sum, "Sum")
|
|
||||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &TextureSettings::m_maintainAlphaCoverage, "Maintain Alpha Coverage", "Select this option to manually adjust Alpha channel mipmaps.")
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextureSettings::operator!=(const TextureSettings& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextureSettings::operator==(const TextureSettings& other) const
|
|
||||||
{
|
|
||||||
/////////////////////////////
|
|
||||||
// Compare Alpha Adjust
|
|
||||||
/////////////////////////////
|
|
||||||
bool matchingAlphaTestAdjust = true;
|
|
||||||
for (AZ::u8 curIndex = 0; curIndex < s_MaxMipMaps; ++curIndex)
|
|
||||||
{
|
|
||||||
if (m_mipAlphaAdjust[curIndex] != other.m_mipAlphaAdjust[curIndex])
|
|
||||||
{
|
|
||||||
matchingAlphaTestAdjust = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
matchingAlphaTestAdjust &&
|
|
||||||
m_preset == other.m_preset &&
|
|
||||||
m_sizeReduceLevel == other.m_sizeReduceLevel &&
|
|
||||||
m_suppressEngineReduce == other.m_suppressEngineReduce &&
|
|
||||||
m_maintainAlphaCoverage == other.m_maintainAlphaCoverage &&
|
|
||||||
m_mipGenEval == other.m_mipGenEval &&
|
|
||||||
m_mipGenType == other.m_mipGenType;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextureSettings::Equals(const TextureSettings& other, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
/////////////////////////////
|
|
||||||
// Compare Common Settings
|
|
||||||
/////////////////////////////
|
|
||||||
if (*this != other)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////
|
|
||||||
// Compare Overrides
|
|
||||||
/////////////////////////////
|
|
||||||
const MultiplatformTextureSettings selfOverrides = GetMultiplatformTextureSetting(*this, serializeContext);
|
|
||||||
const MultiplatformTextureSettings otherOverrides = GetMultiplatformTextureSetting(other, serializeContext);
|
|
||||||
auto selfOverridesIter = selfOverrides.begin();
|
|
||||||
auto otherOverridesIter = otherOverrides.begin();
|
|
||||||
|
|
||||||
while (selfOverridesIter != selfOverrides.end() && otherOverridesIter != otherOverrides.end())
|
|
||||||
{
|
|
||||||
if (selfOverridesIter->second != otherOverridesIter->second)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
otherOverridesIter++;
|
|
||||||
selfOverridesIter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ_Assert(selfOverridesIter == selfOverrides.end() && otherOverridesIter == otherOverrides.end(), "Both iterators must be at the end by now.")
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float TextureSettings::ComputeMIPAlphaOffset(AZ::u32 mip) const
|
|
||||||
{
|
|
||||||
if (mip / 2 + 1 >= s_MaxMipMaps)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float fVal = static_cast<float>(m_mipAlphaAdjust[s_MaxMipMaps - 1]);
|
|
||||||
if (mip / 2 + 1 < s_MaxMipMaps)
|
|
||||||
{
|
|
||||||
float fInterpolationSlider1 = static_cast<float>(m_mipAlphaAdjust[mip / 2]);
|
|
||||||
float fInterpolationSlider2 = static_cast<float>(m_mipAlphaAdjust[mip / 2 + 1]);
|
|
||||||
fVal = fInterpolationSlider1 + (fInterpolationSlider2 - fInterpolationSlider1) * (mip & 1) * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.5f - fVal / 100.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureSettings::ApplyPreset(AZ::Uuid presetId)
|
|
||||||
{
|
|
||||||
const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(presetId);
|
|
||||||
if (presetSetting != nullptr)
|
|
||||||
{
|
|
||||||
m_sizeReduceLevel = presetSetting->m_sizeReduceLevel;
|
|
||||||
m_suppressEngineReduce = presetSetting->m_suppressEngineReduce;
|
|
||||||
if (presetSetting->m_mipmapSetting)
|
|
||||||
{
|
|
||||||
m_mipGenType = presetSetting->m_mipmapSetting->m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_preset = presetId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Cannot set an invalid preset %s!", presetId.ToString<AZStd::string>().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StringOutcome TextureSettings::LoadTextureSetting(const AZStd::string& filepath, TextureSettings& textureSettingPtrOut, AZ::SerializeContext* serializeContext /*= nullptr*/)
|
|
||||||
{
|
|
||||||
auto loadedTextureSettingPtr = AZStd::unique_ptr<TextureSettings>(AZ::Utils::LoadObjectFromFile<TextureSettings>(filepath, serializeContext));
|
|
||||||
|
|
||||||
if (!loadedTextureSettingPtr)
|
|
||||||
{
|
|
||||||
return AZ::Failure(AZStd::string());
|
|
||||||
}
|
|
||||||
|
|
||||||
textureSettingPtrOut = *loadedTextureSettingPtr;
|
|
||||||
return AZ::Success(AZStd::string());
|
|
||||||
}
|
|
||||||
|
|
||||||
StringOutcome TextureSettings::WriteTextureSetting(const AZStd::string& filepath, TextureSettings& textureSetting, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
if(false == AZ::Utils::SaveObjectToFile<TextureSettings>(filepath, AZ::DataStream::StreamType::ST_XML, &textureSetting, serializeContext))
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR("Failed to write to file: " + filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return STRING_OUTCOME_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringOutcome TextureSettings::LoadLegacyTextureSetting(const AZStd::string& imagePath, const AZStd::string& contentString, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
AZStd::string trimmedContent = contentString;
|
|
||||||
AzFramework::StringFunc::TrimWhiteSpace(trimmedContent, true /* leading */, true /* trailing */);
|
|
||||||
if (trimmedContent.empty())
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR("Empty legacy texture setting!");
|
|
||||||
}
|
|
||||||
|
|
||||||
AZStd::vector<AZStd::string> settings;
|
|
||||||
AZStd::vector<AZStd::string*> overrideSettings;
|
|
||||||
|
|
||||||
// Each setting begins with a forward-slash.
|
|
||||||
AzFramework::StringFunc::Tokenize(trimmedContent.c_str(), settings, " /"); // requires space character.
|
|
||||||
|
|
||||||
// For each setting pair (field & value)...
|
|
||||||
for (AZStd::string& settingPair : settings)
|
|
||||||
{
|
|
||||||
// Split setting pair into key & value.
|
|
||||||
AZStd::string key, value;
|
|
||||||
{
|
|
||||||
AZStd::vector<AZStd::string> key_value;
|
|
||||||
AzFramework::StringFunc::Tokenize(settingPair.c_str(), key_value, '=');
|
|
||||||
if (key_value.size() == 2)
|
|
||||||
{
|
|
||||||
key = key_value[0];
|
|
||||||
value = key_value[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR("Invalid format found in legacy texture setting: " + settingPair);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool containsPlatformOverrides = !value.empty() && (value[0] == '"' && value[value.length() - 1] == '"');
|
|
||||||
if (containsPlatformOverrides)
|
|
||||||
{
|
|
||||||
// Process platform-specific overrides on the next loop.
|
|
||||||
overrideSettings.push_back(&settingPair);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the common settings.
|
|
||||||
ParseLegacyTextureSettingString(key, value, textureSettingOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some setting file won't assign a proper preset for the image, need to assign a suggested one here
|
|
||||||
if (textureSettingOut.m_preset.IsNull())
|
|
||||||
{
|
|
||||||
textureSettingOut.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imagePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store a temporary settings of all platforms intended to have overrides within this preset.
|
|
||||||
// We will collate all overrides per-platform to generate PatchData at the end.
|
|
||||||
MultiplatformTextureSettings overrideCache;
|
|
||||||
|
|
||||||
// For each platform-specific override setting pair
|
|
||||||
for (AZStd::string* overrideSettingPair : overrideSettings)
|
|
||||||
{
|
|
||||||
// Split setting pair into key & value.
|
|
||||||
AZStd::string key, value;
|
|
||||||
{
|
|
||||||
AZStd::vector<AZStd::string> key_value;
|
|
||||||
AzFramework::StringFunc::Tokenize(overrideSettingPair->c_str(), key_value, '=');
|
|
||||||
|
|
||||||
if (key_value.size() == 2)
|
|
||||||
{
|
|
||||||
key = key_value[0];
|
|
||||||
value = key_value[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR("Invalid format found in legacy texture setting: " + *overrideSettingPair);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chop the surrounding quotation marks.
|
|
||||||
AzFramework::StringFunc::LChop(value, 1);
|
|
||||||
AzFramework::StringFunc::RChop(value, 1);
|
|
||||||
|
|
||||||
// Split the collection of platforms overrides into entries in a vector.
|
|
||||||
// Layout: { [platform0],[value0],[platform1],[value1],[platform2],[value2] }
|
|
||||||
AZStd::vector<AZStd::string> override_platform_value;
|
|
||||||
AzFramework::StringFunc::Tokenize(value.c_str(), override_platform_value, ",:");
|
|
||||||
|
|
||||||
if (override_platform_value.size() % 2 != 0)
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR("Invalid format found in legacy texture setting: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int platformIdx = 0, valueIdx = 1;
|
|
||||||
valueIdx < override_platform_value.size();
|
|
||||||
platformIdx += 2, valueIdx = platformIdx + 1)
|
|
||||||
{
|
|
||||||
PlatformName& overridePlatform = override_platform_value[platformIdx];
|
|
||||||
AZStd::string& overrideValue = override_platform_value[valueIdx];
|
|
||||||
|
|
||||||
// Insert a copy of the base settings we've parsed from the legacy metafile.
|
|
||||||
overrideCache.insert(AZStd::pair<PlatformName, TextureSettings>(overridePlatform, textureSettingOut));
|
|
||||||
|
|
||||||
ParseLegacyTextureSettingString(key, overrideValue, overrideCache[overridePlatform]);
|
|
||||||
overrideCache[overridePlatform].m_overridingPlatform = overridePlatform;
|
|
||||||
overrideCache[overridePlatform].m_platfromOverrides.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the final result in a temp variable to do a whole-sale copy at the end.
|
|
||||||
TextureSettings finalResult = textureSettingOut;
|
|
||||||
|
|
||||||
// Use the override cache to generate a DataPatch per-platform.
|
|
||||||
for (auto& overridePair : overrideCache)
|
|
||||||
{
|
|
||||||
// Every DataPatch is only a diff between a vanilla common-settings (with no platform-specific overrides) and the specified platform's override.
|
|
||||||
AZ::DataPatch platformOverridePatch;
|
|
||||||
platformOverridePatch.Create<TextureSettings, TextureSettings>(&textureSettingOut, &overridePair.second,AZ::DataPatch::FlagsMap(), AZ::DataPatch::FlagsMap(), serializeContext);
|
|
||||||
finalResult.m_platfromOverrides.insert(AZStd::pair<PlatformName, AZ::DataPatch>(overridePair.first, platformOverridePatch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fully overwrite output variable. The only difference should be properly filled-out overrides.
|
|
||||||
textureSettingOut = finalResult;
|
|
||||||
|
|
||||||
return STRING_OUTCOME_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringOutcome TextureSettings::LoadLegacyTextureSettingFromFile(const AZStd::string& imagePath, const AZStd::string& filepath, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
AZStd::string fileContents;
|
|
||||||
|
|
||||||
// Perform file I/O to read the contents of the metafile into the string above.
|
|
||||||
auto fileIoPtr = AZ::IO::FileIOBase::GetInstance();
|
|
||||||
AZ::IO::HandleType fileHandle;
|
|
||||||
fileIoPtr->Open(filepath.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle);
|
|
||||||
AZ::u64 fileSize = 0;
|
|
||||||
AZ::u64 bytesRead = 0;
|
|
||||||
fileIoPtr->Size(fileHandle, fileSize);
|
|
||||||
char* fileString = new char[fileSize + 1];
|
|
||||||
fileIoPtr->Read(fileHandle, fileString, fileSize, false, &bytesRead);
|
|
||||||
fileIoPtr->Close(fileHandle);
|
|
||||||
fileString[bytesRead] = 0;
|
|
||||||
fileContents = fileString;
|
|
||||||
delete[] fileString;
|
|
||||||
|
|
||||||
|
|
||||||
return LoadLegacyTextureSetting(imagePath, fileContents, textureSettingOut, serializeContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplatformTextureSettings TextureSettings::GenerateDefaultMultiplatformTextureSettings(const AZStd::string& imageFilepath)
|
|
||||||
{
|
|
||||||
MultiplatformTextureSettings settings;
|
|
||||||
PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList();
|
|
||||||
AZ::Uuid suggestedPreset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilepath);
|
|
||||||
if (!suggestedPreset.IsNull())
|
|
||||||
{
|
|
||||||
for (PlatformName& platform : platformsList)
|
|
||||||
{
|
|
||||||
TextureSettings textureSettings;
|
|
||||||
textureSettings.ApplyPreset(suggestedPreset);
|
|
||||||
settings.insert(AZStd::pair<PlatformName, TextureSettings>(platform, textureSettings));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringOutcome TextureSettings::GetPlatformSpecificTextureSetting(const PlatformName& platformName, const TextureSettings& baseTextureSettings,
|
|
||||||
TextureSettings& textureSettingsOut, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
// Obtain the DataPatch (if platform exists)
|
|
||||||
auto overrideIter = baseTextureSettings.m_platfromOverrides.find(platformName);
|
|
||||||
if (overrideIter == baseTextureSettings.m_platfromOverrides.end())
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR(AZStd::string::format("TextureSettings preset [%s] does not have override for platform [%s]",
|
|
||||||
baseTextureSettings.m_preset.ToString<AZStd::string>().c_str(), platformName.c_str()));
|
|
||||||
}
|
|
||||||
AZ::DataPatch& platformOverride = const_cast<AZ::DataPatch&>(overrideIter->second);
|
|
||||||
|
|
||||||
// Update settings instance with override values.
|
|
||||||
if (platformOverride.IsData())
|
|
||||||
{
|
|
||||||
// Apply the AZ::DataPatch to obtain a platform-overridden version of the TextureSettings.
|
|
||||||
AZStd::unique_ptr<TextureSettings> platformSpecificTextureSettings(platformOverride.Apply(&baseTextureSettings, serializeContext));
|
|
||||||
AZ_Assert(platformSpecificTextureSettings->m_mipAlphaAdjust.size() == s_MaxMipMaps, "Unexpected m_mipAlphaAdjust size.");
|
|
||||||
|
|
||||||
// Adjust overrides data to imply 'platformSpecificTextureSettings' *IS* the override.
|
|
||||||
platformSpecificTextureSettings->m_platfromOverrides.clear();
|
|
||||||
platformSpecificTextureSettings->m_overridingPlatform = platformName;
|
|
||||||
textureSettingsOut = *platformSpecificTextureSettings;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
textureSettingsOut = baseTextureSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STRING_OUTCOME_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MultiplatformTextureSettings TextureSettings::GetMultiplatformTextureSetting(const TextureSettings& textureSettings, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
MultiplatformTextureSettings loadedSettingsReturn;
|
|
||||||
PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList();
|
|
||||||
// Generate MultiplatformTextureSettings based on existing available overrides.
|
|
||||||
for (const PlatformName& curPlatformName : platformsList)
|
|
||||||
{
|
|
||||||
// Start with a copy of the base settings
|
|
||||||
TextureSettings curPlatformOverride = textureSettings;
|
|
||||||
if (!GetPlatformSpecificTextureSetting(curPlatformName, textureSettings, curPlatformOverride, serializeContext).IsSuccess())
|
|
||||||
{
|
|
||||||
// We have failed to obtain an override. Maintain base settings to indicate zero overrides.
|
|
||||||
// We still want to designate these TextureSettings as an (empty) override.
|
|
||||||
curPlatformOverride.m_platfromOverrides.clear();
|
|
||||||
curPlatformOverride.m_overridingPlatform = curPlatformName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add as an entry to the multiplatform texture settings
|
|
||||||
loadedSettingsReturn.insert(AZStd::pair<PlatformName, TextureSettings>(curPlatformName, curPlatformOverride));
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a copy of the results
|
|
||||||
return loadedSettingsReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MultiplatformTextureSettings TextureSettings::GetMultiplatformTextureSetting(const AZStd::string& imageFilepath, bool& canOverridePreset, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
TextureSettings loadedTextureSetting;
|
|
||||||
|
|
||||||
// Attempt to get metadata filepath from image path.
|
|
||||||
AZStd::string legacyMetadataFilepath = imageFilepath + legacyExtensionName;
|
|
||||||
AZStd::string modernMetadataFilepath = imageFilepath + modernExtensionName;
|
|
||||||
bool hasLegacyMetafile = AZ::IO::SystemFile::Exists(legacyMetadataFilepath.c_str());
|
|
||||||
bool hasModernMetafile = AZ::IO::SystemFile::Exists(modernMetadataFilepath.c_str());
|
|
||||||
|
|
||||||
// If the image has an accompanying metadata...
|
|
||||||
if(hasModernMetafile)
|
|
||||||
{
|
|
||||||
// Parse the metadata file.
|
|
||||||
if (!LoadTextureSetting(modernMetadataFilepath, loadedTextureSetting, serializeContext).IsSuccess())
|
|
||||||
{
|
|
||||||
canOverridePreset = true;
|
|
||||||
return GenerateDefaultMultiplatformTextureSettings(imageFilepath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (hasLegacyMetafile)
|
|
||||||
{
|
|
||||||
if (!LoadLegacyTextureSettingFromFile(imageFilepath, legacyMetadataFilepath, loadedTextureSetting, serializeContext).IsSuccess())
|
|
||||||
{
|
|
||||||
canOverridePreset = true;
|
|
||||||
return GenerateDefaultMultiplatformTextureSettings(imageFilepath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
canOverridePreset = true; // RC could override settings if it was loaded from the image so this is set to
|
|
||||||
// true regardless of whether settings existed in the texture for compatibility.
|
|
||||||
// Try to load from image file if it has embedded setting file
|
|
||||||
AZStd::string embeddedString = LoadEmbeddedSettingFromFile(imageFilepath);
|
|
||||||
if (!LoadLegacyTextureSetting(imageFilepath, embeddedString, loadedTextureSetting, serializeContext).IsSuccess())
|
|
||||||
{
|
|
||||||
// If the texture has neither of legacy/modern meta file nor embedded setting, generate data for a new metadata file.
|
|
||||||
return GenerateDefaultMultiplatformTextureSettings(imageFilepath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate MultiplatformTextureSettings based on the loaded texture setting.
|
|
||||||
return GetMultiplatformTextureSetting(loadedTextureSetting, serializeContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringOutcome TextureSettings::ApplySettings(const TextureSettings& settings, const PlatformName& overridePlatform, AZ::SerializeContext* serializeContext)
|
|
||||||
{
|
|
||||||
if (overridePlatform.empty())
|
|
||||||
{
|
|
||||||
*this = settings;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ::DataPatch newOverride;
|
|
||||||
if (false == newOverride.Create<TextureSettings, TextureSettings>(this, &settings, AZ::DataPatch::FlagsMap(), AZ::DataPatch::FlagsMap(), serializeContext))
|
|
||||||
{
|
|
||||||
return STRING_OUTCOME_ERROR("Failed to create TextureSettings platform override data. See AZ_Error log for details.");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_platfromOverrides[overridePlatform] = newOverride;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STRING_OUTCOME_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BuilderSettings/ImageProcessingDefines.h>
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
#include <AzCore/RTTI/ReflectContext.h>
|
|
||||||
#include <AzCore/Serialization/DataPatch.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class TextureSettings;
|
|
||||||
typedef AZStd::map<PlatformName, TextureSettings> MultiplatformTextureSettings;
|
|
||||||
|
|
||||||
class TextureSettings
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_TYPE_INFO(TextureSettings, "{CC3ED018-7FF7-4233-AAD8-6D3115FD844A}");
|
|
||||||
AZ_CLASS_ALLOCATOR(TextureSettings, AZ::SystemAllocator, 0);
|
|
||||||
|
|
||||||
TextureSettings();
|
|
||||||
float ComputeMIPAlphaOffset(AZ::u32 mip) const;
|
|
||||||
void ApplyPreset(AZ::Uuid presetId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a comprehensive comparison between two TextureSettings instances.
|
|
||||||
* @param Reference to the settings which will be compared.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return True, is both instances are equivalent.
|
|
||||||
*/
|
|
||||||
bool Equals(const TextureSettings& other, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies texture settings to the instance (including overrides). Common settings are applied, unless specific platform is specified.
|
|
||||||
* @param Reference to the settings which will be applied.
|
|
||||||
* @param Optional. Applies settings as a platform override if a platform is specified.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return Status outcome result.
|
|
||||||
*/
|
|
||||||
StringOutcome ApplySettings(const TextureSettings& settings, const PlatformName& overridePlatform = PlatformName(), AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets platform-specific texture settings obtained from the base settings version of a pre-loaded TextureSettings instance.
|
|
||||||
* @param Name of platform to get the settings from.
|
|
||||||
* @param Base TextureSettings which we will get overrides from.
|
|
||||||
* @param Output TextureSettings which will contain the result of the function.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return Status outcome result.
|
|
||||||
*/
|
|
||||||
static StringOutcome GetPlatformSpecificTextureSetting(const PlatformName& platformName, const TextureSettings& baseTextureSettings, TextureSettings& textureSettingsOut, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads base texture settings obtained from ".exportsettings" file (legacy setting)
|
|
||||||
* @param ImagePath absolute/relative path of the image file.
|
|
||||||
* @param FilePath absolute/relative path of the ".exportsettings" file.
|
|
||||||
* @param Output TextureSettings which contain the result of the function, it may contains platform-specific overrides.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return Status outcome result.
|
|
||||||
*/
|
|
||||||
static StringOutcome LoadLegacyTextureSettingFromFile(const AZStd::string& imagePath, const AZStd::string& filepath, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads base texture settings obtained from a legacy setting string
|
|
||||||
* @param ImagePath absolute/relative path of the image file.
|
|
||||||
* @param Content string of the legacy setting to be read.
|
|
||||||
* @param Output TextureSettings which contain the result of the function, it may contains platform-specific overrides.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return Status outcome result.
|
|
||||||
*/
|
|
||||||
static StringOutcome LoadLegacyTextureSetting(const AZStd::string& imagePath, const AZStd::string& contentString, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads base texture settings obtained from ".imagesettings" file (modern setting)
|
|
||||||
* @param FilePath absolute/relative path of the ".imagesettings" file.
|
|
||||||
* @param Output TextureSettings which contain the result of the function, it may contains platform-specific overrides.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return Status outcome result.
|
|
||||||
*/
|
|
||||||
static StringOutcome LoadTextureSetting(const AZStd::string& filepath, TextureSettings& textureSettingPtrOut, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes base texture settings to a ".imagesettings" file (modern setting)
|
|
||||||
* @param FilePath absolute/relative path of the ".imagesettings" file.
|
|
||||||
* @param TextureSetting to be written on the disk, it may contains platform-specific overrides.
|
|
||||||
* @param Optional. Serialize context. Will use global context if none is provided.
|
|
||||||
* @return Status outcome result.
|
|
||||||
*/
|
|
||||||
static StringOutcome WriteTextureSetting(const AZStd::string& filepath, TextureSettings& textureSetting, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
// Generates a MultiplatformTextureSettings collection with default texture settings for all
|
|
||||||
static MultiplatformTextureSettings GenerateDefaultMultiplatformTextureSettings(const AZStd::string& imageFilepath);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a TextureSetting instance of a particular image file for each supported platform.
|
|
||||||
* @param filepath - A path to the texture file.
|
|
||||||
* @param canOverridePreset - Returns whether the preset can be overriden. Will return false if the preset was selecting from a settings file created by the user.
|
|
||||||
* @param serializeContext - Optional. Serialize context used for reflection/serialization
|
|
||||||
* @return - The collection of TextureSetting instances. If error occurs, a default MultiplatformTextureSettings is returned (see GenerateDefaultMultiplatformTextureSettings()).
|
|
||||||
*/
|
|
||||||
static const MultiplatformTextureSettings GetMultiplatformTextureSetting(const AZStd::string& filepath, bool& canOverridePreset, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a TextureSetting instance of a particular image file for each supported platform.
|
|
||||||
* @param textureSettings - A reference to an already-loaded texture settings.
|
|
||||||
* @param serializeContext - Optional. Serialize context used for reflection/serialization
|
|
||||||
* @return - The collection of TextureSetting instances. If error occurs, a default MultiplatformTextureSettings is returned (see GenerateDefaultMultiplatformTextureSettings()).
|
|
||||||
*/
|
|
||||||
static const MultiplatformTextureSettings GetMultiplatformTextureSetting(const TextureSettings& textureSettings, AZ::SerializeContext* serializeContext = nullptr);
|
|
||||||
|
|
||||||
static const char* legacyExtensionName;
|
|
||||||
static const char* modernExtensionName;
|
|
||||||
static const size_t s_MaxMipMaps = 6;
|
|
||||||
|
|
||||||
// uuid of selected preset for this texture
|
|
||||||
AZ::Uuid m_preset;
|
|
||||||
|
|
||||||
// texture size reduce level. the value of this variable will override the same variable in PresetSettings
|
|
||||||
unsigned int m_sizeReduceLevel;
|
|
||||||
|
|
||||||
// "ser". Whether to enable supress reduce resolution (m_sizeReduceLevel) during loading, 0(default)
|
|
||||||
// the value of this variable will override the same variable in PresetSettings
|
|
||||||
bool m_suppressEngineReduce;
|
|
||||||
|
|
||||||
//enable generate mipmap or not
|
|
||||||
bool m_enableMipmap;
|
|
||||||
|
|
||||||
//"mc". not used in rc.ini. experiemental
|
|
||||||
//maybe relate to http://the-witness.net/news/2010/09/computing-alpha-mipmaps/
|
|
||||||
bool m_maintainAlphaCoverage;
|
|
||||||
|
|
||||||
// "M", adjust mipalpha, 0..50=normal..100. associate with ComputeMIPAlphaOffset function
|
|
||||||
// only useful if m_maintainAlphaCoverage set to true.
|
|
||||||
// This data type MUST be an AZStd::vector, even though we treat is as a fixed array. This is due to a limitation
|
|
||||||
// during AZ::DataPatch serialization, where an element is allocated one by one while extending the container..
|
|
||||||
AZStd::vector<AZ::u32> m_mipAlphaAdjust;
|
|
||||||
|
|
||||||
MipGenEvalType m_mipGenEval;
|
|
||||||
|
|
||||||
MipGenType m_mipGenType;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Platform overrides in form of DataPatch. Each entry is a patch for a specified platform.
|
|
||||||
// This map is used to generate TextureSettings with overridden values. The map is empty if
|
|
||||||
// the instance is for platform-specific settings.
|
|
||||||
AZStd::map<PlatformName, AZ::DataPatch> m_platfromOverrides;
|
|
||||||
|
|
||||||
// The platform which these settings override.
|
|
||||||
// Blank if the instance is for common settings.
|
|
||||||
PlatformName m_overridingPlatform;
|
|
||||||
|
|
||||||
// Comparison operators only compare the base settings, they do not compare overrides.
|
|
||||||
// For a comprehensive equality comparison, use Equals() function.
|
|
||||||
bool operator==(const TextureSettings& other) const;
|
|
||||||
bool operator!=(const TextureSettings& other) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,387 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
|
|
||||||
#include <Compressors/CTSquisher.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
struct CrySquisherCallbackUserData
|
|
||||||
{
|
|
||||||
IImageObjectPtr m_pImageObject;
|
|
||||||
AZ::u8* m_dstMem;
|
|
||||||
AZ::u32 m_dstOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
// callbacks for the CryTextureSquisher
|
|
||||||
void CrySquisherOutputCallback(const CryTextureSquisher::CompressorParameters& compress, const void* data, AZ::u32 size, AZ::u32 oy, AZ::u32 ox)
|
|
||||||
{
|
|
||||||
CrySquisherCallbackUserData* const pUserData = (CrySquisherCallbackUserData*)compress.userPtr;
|
|
||||||
|
|
||||||
AZ::u32 stride = (compress.width + 3) >> 2;
|
|
||||||
AZ::u32 blocks = (compress.height + 3) >> 2;
|
|
||||||
memcpy(pUserData->m_dstMem + size * (stride * oy + ox), data, size);
|
|
||||||
pUserData->m_dstOffset = size * (stride * blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CrySquisherInputCallback(const CryTextureSquisher::DecompressorParameters& decompress, void* data, AZ::u32 size, AZ::u32 oy, AZ::u32 ox)
|
|
||||||
{
|
|
||||||
CrySquisherCallbackUserData* const pUserData = (CrySquisherCallbackUserData*)decompress.userPtr;
|
|
||||||
AZ::u32 stride = (decompress.width + 3) >> 2;
|
|
||||||
AZ::u32 blocks = (decompress.height + 3) >> 2;
|
|
||||||
|
|
||||||
//assert(CPixelFormats::GetPixelFormatInfo(pUserData->m_pImageObject->GetPixelFormat())->bCompressed);
|
|
||||||
|
|
||||||
memcpy(data, pUserData->m_dstMem + size * (stride * oy + ox), size);
|
|
||||||
|
|
||||||
pUserData->m_dstOffset = size * (stride * blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CryTextureSquisher::ECodingPreset CTSquisher::GetCompressPreset(EPixelFormat compressFmt, EPixelFormat uncompressFmt)
|
|
||||||
{
|
|
||||||
CryTextureSquisher::ECodingPreset preset = CryTextureSquisher::eCompressorPreset_Num;
|
|
||||||
switch (compressFmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_BC1:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC1U;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC1a:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC1Ua;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC3:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC3U;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC3t:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC3Ut;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC4:
|
|
||||||
preset = (CPixelFormats::GetInstance().IsFormatSingleChannel(uncompressFmt)
|
|
||||||
? CryTextureSquisher::eCompressorPreset_BC4Ua // a-channel
|
|
||||||
: CryTextureSquisher::eCompressorPreset_BC4U); // r-channel
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC4s:
|
|
||||||
preset = (CPixelFormats::GetInstance().IsFormatSingleChannel(uncompressFmt)
|
|
||||||
? CryTextureSquisher::eCompressorPreset_BC4Sa // a-channel
|
|
||||||
: CryTextureSquisher::eCompressorPreset_BC4S); // r-channel
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC5:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC5Un;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC5s:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC5Sn;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC6UH:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC6UH;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC7:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC7U;
|
|
||||||
break;
|
|
||||||
case ePixelFormat_BC7t:
|
|
||||||
preset = CryTextureSquisher::eCompressorPreset_BC7Ut;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
AZ_Assert(false, "%s: Unexpected pixel format (in compressing an image). Inform an RC programmer.", __FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
return preset;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CTSquisher::IsCompressedPixelFormatSupported(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_BC1:
|
|
||||||
case ePixelFormat_BC1a:
|
|
||||||
case ePixelFormat_BC3:
|
|
||||||
case ePixelFormat_BC3t:
|
|
||||||
case ePixelFormat_BC4:
|
|
||||||
case ePixelFormat_BC4s:
|
|
||||||
case ePixelFormat_BC5:
|
|
||||||
case ePixelFormat_BC5s:
|
|
||||||
case ePixelFormat_BC6UH:
|
|
||||||
case ePixelFormat_BC7:
|
|
||||||
case ePixelFormat_BC7t:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CTSquisher::IsUncompressedPixelFormatSupported(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_R8:
|
|
||||||
case ePixelFormat_A8:
|
|
||||||
case ePixelFormat_R8G8B8A8:
|
|
||||||
case ePixelFormat_R8G8B8X8:
|
|
||||||
case ePixelFormat_R32F:
|
|
||||||
case ePixelFormat_R32G32B32A32F:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CTSquisher::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EPixelFormat CTSquisher::GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt)
|
|
||||||
{
|
|
||||||
//special cases
|
|
||||||
if (compressedfmt == ePixelFormat_BC6UH || compressedfmt == ePixelFormat_BC5 || compressedfmt == ePixelFormat_BC5s)
|
|
||||||
{
|
|
||||||
return ePixelFormat_R32G32B32A32F;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsUncompressedPixelFormatSupported(uncompressedfmt))
|
|
||||||
{
|
|
||||||
return uncompressedfmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
//for fmt dont support, convert to supported uncompressed formats: ePixelFormat_A8, ePixelFormat_R8, ePixelFormat_A8R8G8B8,
|
|
||||||
// ePixelFormat_X8R8G8B8, ePixelFormat_R32F, ePixelFormat_A32B32G32R32F
|
|
||||||
|
|
||||||
switch (uncompressedfmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_R8G8:
|
|
||||||
case ePixelFormat_R16G16:
|
|
||||||
return ePixelFormat_R8G8B8X8;
|
|
||||||
case ePixelFormat_R16:
|
|
||||||
return ePixelFormat_R8;
|
|
||||||
case ePixelFormat_R16G16B16A16:
|
|
||||||
case ePixelFormat_B8G8R8A8:
|
|
||||||
return ePixelFormat_R8G8B8A8;
|
|
||||||
case ePixelFormat_R9G9B9E5:
|
|
||||||
case ePixelFormat_R32G32F:
|
|
||||||
case ePixelFormat_R16G16B16A16F:
|
|
||||||
case ePixelFormat_R16G16F:
|
|
||||||
return ePixelFormat_R32G32B32A32F;
|
|
||||||
case ePixelFormat_R16F:
|
|
||||||
return ePixelFormat_R32F;
|
|
||||||
default:
|
|
||||||
//this shouldn't happen. but we could handle it with uncompressed data anyway
|
|
||||||
if (CPixelFormats::GetInstance().IsPixelFormatWithoutAlpha(uncompressedfmt))
|
|
||||||
{
|
|
||||||
return ePixelFormat_R8G8B8X8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ePixelFormat_R8G8B8A8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr CTSquisher::DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
// Decompressing
|
|
||||||
// the output pixel format could only have one channel or four channels. need to find out more
|
|
||||||
EPixelFormat fmtSrc = srcImage->GetPixelFormat();
|
|
||||||
|
|
||||||
//src format need to be compressed and dst format need to uncompressed.
|
|
||||||
if (!IsCompressedPixelFormatSupported(fmtSrc) || !IsUncompressedPixelFormatSupported(fmtDst))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst));
|
|
||||||
|
|
||||||
//clear the dstImage to (0, 0, 0, 1) since some compression format only write to certain channels
|
|
||||||
dstImage->ClearColor(0, 0, 0, 1);
|
|
||||||
|
|
||||||
//for each mipmap
|
|
||||||
const AZ::u32 mipCount = srcImage->GetMipCount();
|
|
||||||
for (AZ::u32 dwMip = 0; dwMip < mipCount; ++dwMip)
|
|
||||||
{
|
|
||||||
const AZ::u32 dwLocalWidth = srcImage->GetWidth(dwMip);
|
|
||||||
const AZ::u32 dwLocalHeight = srcImage->GetHeight(dwMip);
|
|
||||||
|
|
||||||
AZ::u8* pSrcMem;
|
|
||||||
AZ::u32 dwSrcPitch;
|
|
||||||
srcImage->GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
|
|
||||||
|
|
||||||
AZ::u8* pDstMem;
|
|
||||||
AZ::u32 dwDstPitch;
|
|
||||||
dstImage->GetImagePointer(dwMip, pDstMem, dwDstPitch);
|
|
||||||
|
|
||||||
CrySquisherCallbackUserData userData;
|
|
||||||
userData.m_pImageObject = srcImage;
|
|
||||||
userData.m_dstOffset = 0;
|
|
||||||
userData.m_dstMem = pSrcMem;
|
|
||||||
|
|
||||||
CryTextureSquisher::DecompressorParameters decompress;
|
|
||||||
|
|
||||||
decompress.dstBuffer = pDstMem;
|
|
||||||
decompress.width = dwLocalWidth;
|
|
||||||
decompress.height = dwLocalHeight;
|
|
||||||
decompress.pitch = dwDstPitch;
|
|
||||||
|
|
||||||
decompress.dstType = (CPixelFormats::GetInstance().IsFormatFloatingPoint(fmtDst, true) ?
|
|
||||||
CryTextureSquisher::eBufferType_ufloat : CryTextureSquisher::eBufferType_uint8);
|
|
||||||
|
|
||||||
if (CPixelFormats::GetInstance().IsFormatSigned(fmtSrc))
|
|
||||||
{
|
|
||||||
decompress.dstType = (decompress.dstType == CryTextureSquisher::eBufferType_ufloat ?
|
|
||||||
CryTextureSquisher::eBufferType_sfloat : CryTextureSquisher::eBufferType_sint8);
|
|
||||||
}
|
|
||||||
|
|
||||||
decompress.userPtr = &userData;
|
|
||||||
decompress.userInputFunction = CrySquisherInputCallback;
|
|
||||||
decompress.preset = GetCompressPreset(fmtSrc, fmtDst);
|
|
||||||
|
|
||||||
CryTextureSquisher::Decompress(decompress);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CTsquish operates on native normal vectors when floating-point
|
|
||||||
// buffers are used. Apply bias and scale when returning a normal-map.
|
|
||||||
if (fmtSrc == ePixelFormat_BC5 || fmtSrc == ePixelFormat_BC5s)
|
|
||||||
{
|
|
||||||
if (fmtDst == ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
//conver from [-1, 1] to [0, 1]. And set alpha to 1.
|
|
||||||
dstImage->ScaleAndBiasChannels(0, 100,
|
|
||||||
AZ::Vector4(0.5f, 0.5f, 0.5f, 0.0f),
|
|
||||||
AZ::Vector4(0.5f, 0.5f, 0.5f, 1.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dstImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
IImageObjectPtr CTSquisher::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst,
|
|
||||||
const CompressOption *compressOption)
|
|
||||||
{
|
|
||||||
// Compressing
|
|
||||||
EPixelFormat fmtSrc = srcImage->GetPixelFormat();
|
|
||||||
|
|
||||||
//src format need to be uncompressed and dst format need to compressed.
|
|
||||||
if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst));
|
|
||||||
|
|
||||||
//passing compress option
|
|
||||||
ICompressor::EQuality quality = ICompressor::eQuality_Normal;
|
|
||||||
AZ::Vector3 weights = AZ::Vector3(0.3333f, 0.3334f, 0.3333f);
|
|
||||||
if (compressOption)
|
|
||||||
{
|
|
||||||
quality = compressOption->compressQuality;
|
|
||||||
weights = compressOption->rgbWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
//do some clamp for float
|
|
||||||
if (fmtSrc == ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
const uint32 nMips = srcImage->GetMipCount();
|
|
||||||
|
|
||||||
// NOTES:
|
|
||||||
// - all incoming images are unsigned, even normal maps
|
|
||||||
// - all mipmaps of incoming images can contain out-of-range values from mipmap filtering
|
|
||||||
// - 3Dc/BC5 is synonymous with "is a normal map" because they are not tagged explicitly as such
|
|
||||||
if (fmtDst == ePixelFormat_BC5 || fmtDst == ePixelFormat_BC5s)
|
|
||||||
{
|
|
||||||
srcImage->ScaleAndBiasChannels(0, nMips,
|
|
||||||
AZ::Vector4(2.0f, 2.0f, 2.0f, 1.0f),
|
|
||||||
AZ::Vector4(-1.0f, -1.0f, -1.0f, 0.0f));
|
|
||||||
srcImage->ClampChannels(0, nMips,
|
|
||||||
AZ::Vector4(-1.0f, -1.0f, -1.0f, -1.0f),
|
|
||||||
AZ::Vector4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
}
|
|
||||||
else if (fmtDst == ePixelFormat_BC6UH)
|
|
||||||
{
|
|
||||||
srcImage->ClampChannels(0, nMips,
|
|
||||||
AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f),
|
|
||||||
AZ::Vector4(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcImage->ClampChannels(0, nMips,
|
|
||||||
AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f),
|
|
||||||
AZ::Vector4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 mipCount = dstImage->GetMipCount();
|
|
||||||
for (uint32 dwMip = 0; dwMip < mipCount; ++dwMip)
|
|
||||||
{
|
|
||||||
uint32 dwLocalWidth = srcImage->GetWidth(dwMip);
|
|
||||||
uint32 dwLocalHeight = srcImage->GetHeight(dwMip);
|
|
||||||
|
|
||||||
uint8* pSrcMem;
|
|
||||||
uint32 dwSrcPitch;
|
|
||||||
srcImage->GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
|
|
||||||
|
|
||||||
uint8* pDstMem;
|
|
||||||
uint32 dwDstPitch;
|
|
||||||
dstImage->GetImagePointer(dwMip, pDstMem, dwDstPitch);
|
|
||||||
|
|
||||||
{
|
|
||||||
CrySquisherCallbackUserData userData;
|
|
||||||
userData.m_pImageObject = dstImage;
|
|
||||||
userData.m_dstOffset = 0;
|
|
||||||
userData.m_dstMem = pDstMem;
|
|
||||||
|
|
||||||
CryTextureSquisher::CompressorParameters compress;
|
|
||||||
|
|
||||||
compress.srcBuffer = pSrcMem;
|
|
||||||
compress.width = dwLocalWidth;
|
|
||||||
compress.height = dwLocalHeight;
|
|
||||||
compress.pitch = dwSrcPitch;
|
|
||||||
|
|
||||||
compress.srcType = (CPixelFormats::GetInstance().IsFormatFloatingPoint(fmtSrc, true) ?
|
|
||||||
CryTextureSquisher::eBufferType_ufloat : CryTextureSquisher::eBufferType_uint8);
|
|
||||||
if (CPixelFormats::GetInstance().IsFormatSigned(fmtDst))
|
|
||||||
{
|
|
||||||
compress.srcType = (compress.srcType == CryTextureSquisher::eBufferType_ufloat ?
|
|
||||||
CryTextureSquisher::eBufferType_sfloat : CryTextureSquisher::eBufferType_sint8);
|
|
||||||
}
|
|
||||||
|
|
||||||
const AZ::Vector3 uniform = AZ::Vector3(0.3333f, 0.3334f, 0.3333f);
|
|
||||||
|
|
||||||
compress.weights[0] = weights.GetX();
|
|
||||||
compress.weights[1] = weights.GetY();
|
|
||||||
compress.weights[2] = weights.GetZ();
|
|
||||||
|
|
||||||
compress.perceptual =
|
|
||||||
(compress.weights[0] != uniform.GetX()) ||
|
|
||||||
(compress.weights[1] != uniform.GetY()) ||
|
|
||||||
(compress.weights[2] != uniform.GetZ());
|
|
||||||
|
|
||||||
compress.quality =
|
|
||||||
(quality == eQuality_Preview ? CryTextureSquisher::eQualityProfile_Low :
|
|
||||||
(quality == eQuality_Fast ? CryTextureSquisher::eQualityProfile_Low :
|
|
||||||
(quality == eQuality_Slow ? CryTextureSquisher::eQualityProfile_High :
|
|
||||||
CryTextureSquisher::eQualityProfile_Medium)));
|
|
||||||
|
|
||||||
compress.userPtr = &userData;
|
|
||||||
compress.userOutputFunction = CrySquisherOutputCallback;
|
|
||||||
compress.preset = GetCompressPreset(fmtDst, fmtSrc);
|
|
||||||
|
|
||||||
CryTextureSquisher::Compress(compress);
|
|
||||||
}
|
|
||||||
} // for: all mips
|
|
||||||
|
|
||||||
return dstImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace ImageProcessing
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Compressors/CryTextureSquisher/CryTextureSquisher.h>
|
|
||||||
#include <Compressors/Compressor.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//Cry Texture Squisher for all the BC compressions
|
|
||||||
class CTSquisher : public ICompressor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bool IsCompressedPixelFormatSupported(EPixelFormat fmt);
|
|
||||||
static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt);
|
|
||||||
static bool DoesSupportDecompress(EPixelFormat fmtDst);
|
|
||||||
|
|
||||||
IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) override;
|
|
||||||
IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) override;
|
|
||||||
|
|
||||||
EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) override;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
static CryTextureSquisher::ECodingPreset GetCompressPreset(EPixelFormat compressFmt, EPixelFormat uncompressFmt);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Compressors/CTSquisher.h>
|
|
||||||
#include <Compressors/PVRTC.h>
|
|
||||||
#include <Compressors/ETC2.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
ICompressorPtr ICompressor::FindCompressor(EPixelFormat fmt, bool isCompressing)
|
|
||||||
{
|
|
||||||
if (CTSquisher::IsCompressedPixelFormatSupported(fmt))
|
|
||||||
{
|
|
||||||
if (isCompressing || (!isCompressing && CTSquisher::DoesSupportDecompress(fmt)))
|
|
||||||
{
|
|
||||||
return ICompressorPtr(new CTSquisher());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both ETC2Compressor and PVRTCCompressor can process ETC formats
|
|
||||||
// According to Mobile team, Etc2Com is faster than PVRTexLib, so we check with ETC2Compressor before PVRTCCompressor
|
|
||||||
// Note: with the test I have done, I found out it cost similar time for both Etc2Com and PVRTexLib to compress
|
|
||||||
// a 2048x2048 test texture to EAC_R11 and EAC_RG11. It was around 7 minutes for EAC_R11 and 14 minutes for EAC_RG11
|
|
||||||
if (ETC2Compressor::IsCompressedPixelFormatSupported(fmt))
|
|
||||||
{
|
|
||||||
if (isCompressing || (!isCompressing && ETC2Compressor::DoesSupportDecompress(fmt)))
|
|
||||||
{
|
|
||||||
return ICompressorPtr(new ETC2Compressor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PVRTCCompressor::IsCompressedPixelFormatSupported(fmt))
|
|
||||||
{
|
|
||||||
if (isCompressing || (!isCompressing && PVRTCCompressor::DoesSupportDecompress(fmt)))
|
|
||||||
{
|
|
||||||
return ICompressorPtr(new PVRTCCompressor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ICompressor::~ICompressor()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class ICompressor;
|
|
||||||
typedef AZStd::shared_ptr<ICompressor> ICompressorPtr;
|
|
||||||
|
|
||||||
//the interface base class for any compressors which can decompress/compress image with compressed pixel format
|
|
||||||
class ICompressor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum EQuality
|
|
||||||
{
|
|
||||||
eQuality_Preview, // for the 256x256 preview only
|
|
||||||
eQuality_Fast,
|
|
||||||
eQuality_Normal,
|
|
||||||
eQuality_Slow,
|
|
||||||
};
|
|
||||||
|
|
||||||
//some extra information required for different compressors.
|
|
||||||
//keep is a simple structure for now.
|
|
||||||
struct CompressOption
|
|
||||||
{
|
|
||||||
EQuality compressQuality = eQuality_Normal;
|
|
||||||
//required for CTSquisher
|
|
||||||
AZ::Vector3 rgbWeight = AZ::Vector3(0.3333f, 0.3334f, 0.3333f);
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
//compress the source image to desired compressed pixel format
|
|
||||||
virtual IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) = 0;
|
|
||||||
virtual IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) = 0;
|
|
||||||
virtual EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) = 0;
|
|
||||||
|
|
||||||
//find compressor for specified compressed pixel format. isCompressing to indicate if it's for compressing or decompressing
|
|
||||||
static ICompressorPtr FindCompressor(EPixelFormat fmt, bool isCompressing);
|
|
||||||
|
|
||||||
virtual ~ICompressor() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,297 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <AzCore/Math/MathUtils.h>
|
|
||||||
|
|
||||||
#include "ColorBlockRGBA4x4c.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
static_assert(sizeof(int) == 4, "Expected size of int to be 4 bytes!");
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4c::setRGBA8(const void* imgBGRA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgBGRA8, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(ColorRGBA8), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA8* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const uint8* const pSrc = ((const uint8*)imgBGRA8) + (pitch * (y + row)) + (x * sizeof(ColorRGBA8));
|
|
||||||
|
|
||||||
ColorRGBA8* const pDst = &m_color[row << 2];
|
|
||||||
|
|
||||||
pDst[0].setRGBA(&pSrc[0 * sizeof(ColorRGBA8) / sizeof(*pSrc)]);
|
|
||||||
pDst[1].setRGBA(&pSrc[1 * sizeof(ColorRGBA8) / sizeof(*pSrc)]);
|
|
||||||
pDst[2].setRGBA(&pSrc[2 * sizeof(ColorRGBA8) / sizeof(*pSrc)]);
|
|
||||||
pDst[3].setRGBA(&pSrc[3 * sizeof(ColorRGBA8) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
const uint8* const pSrc = ((const uint8*)imgBGRA8) + pitch * (y + by);
|
|
||||||
|
|
||||||
ColorRGBA8* pDst = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pDst[col].setRGBA(&pSrc[(x + bx) * sizeof(ColorRGBA8) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4c::getRGBA8(void* imgRGBA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgRGBA8, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(ColorRGBA8), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA8* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
uint8* const pDst = ((uint8*)imgRGBA8) + (pitch * (y + row)) + (x * sizeof(ColorRGBA8));
|
|
||||||
|
|
||||||
const ColorRGBA8* const pSrc = &m_color[row << 2];
|
|
||||||
|
|
||||||
pSrc[0].getRGBA(&pDst[0 * sizeof(ColorRGBA8) / sizeof(*pDst)]);
|
|
||||||
pSrc[1].getRGBA(&pDst[1 * sizeof(ColorRGBA8) / sizeof(*pDst)]);
|
|
||||||
pSrc[2].getRGBA(&pDst[2 * sizeof(ColorRGBA8) / sizeof(*pDst)]);
|
|
||||||
pSrc[3].getRGBA(&pDst[3 * sizeof(ColorRGBA8) / sizeof(*pDst)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
uint8* const pDst = ((uint8*)imgRGBA8) + pitch * (y + by);
|
|
||||||
|
|
||||||
const ColorRGBA8* const pSrc = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pSrc[col].getRGBA(&pDst[(x + bx) * sizeof(ColorRGBA8) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4c::setA8(const void* imgA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgA8, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA8* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const uint8* const pSrc = ((const uint8*)imgA8) + (pitch * (y + row)) + (x * sizeof(uint8));
|
|
||||||
|
|
||||||
ColorRGBA8* const pDst = &m_color[row << 2];
|
|
||||||
|
|
||||||
pDst[0].setRGBA(0, 0, 0, pSrc[0]);
|
|
||||||
pDst[1].setRGBA(0, 0, 0, pSrc[1]);
|
|
||||||
pDst[2].setRGBA(0, 0, 0, pSrc[2]);
|
|
||||||
pDst[3].setRGBA(0, 0, 0, pSrc[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
const uint8* const pSrc = ((const uint8*)imgA8) + pitch * (y + by);
|
|
||||||
|
|
||||||
ColorRGBA8* pDst = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pDst[col].setRGBA(0, 0, 0, pSrc[x + bx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4c::getA8(void* imgA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgA8, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA8* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
uint8* const pDst = ((uint8*)imgA8) + (pitch * (y + row)) + (x * sizeof(uint8));
|
|
||||||
uint8 r, g, b;
|
|
||||||
|
|
||||||
const ColorRGBA8* const pSrc = &m_color[row << 2];
|
|
||||||
|
|
||||||
pSrc[0].getRGBA(r, g, b, pDst[0]);
|
|
||||||
pSrc[1].getRGBA(r, g, b, pDst[1]);
|
|
||||||
pSrc[2].getRGBA(r, g, b, pDst[2]);
|
|
||||||
pSrc[3].getRGBA(r, g, b, pDst[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
uint8* const pDst = ((uint8*)imgA8) + pitch * (y + by);
|
|
||||||
uint8 r, g, b;
|
|
||||||
|
|
||||||
const ColorRGBA8* const pSrc = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pSrc[col].getRGBA(r, g, b, pDst[x + bx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ColorBlockRGBA4x4c::isSingleColorIgnoringAlpha() const
|
|
||||||
{
|
|
||||||
for (unsigned int i = 1; i < COLOR_COUNT; ++i)
|
|
||||||
{
|
|
||||||
if ((m_color[0].b != m_color[i].b) ||
|
|
||||||
(m_color[0].g != m_color[i].g) ||
|
|
||||||
(m_color[0].r != m_color[i].r))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include "ColorTypes.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
// Uncompressed 4x4 color block of 8bit integers.
|
|
||||||
struct ColorBlockRGBA4x4c
|
|
||||||
{
|
|
||||||
ColorBlockRGBA4x4c()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA8(const void* imgBGRA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
void getRGBA8(void* imgBGRA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
void setA8(const void* imgA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
void getA8(void* imgA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
bool isSingleColorIgnoringAlpha() const;
|
|
||||||
|
|
||||||
const ColorRGBA8* colors() const
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA8* colors()
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA8 color(unsigned int i) const
|
|
||||||
{
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA8& color(unsigned int i)
|
|
||||||
{
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const unsigned int COLOR_COUNT = 4 * 4;
|
|
||||||
|
|
||||||
ColorRGBA8 m_color[COLOR_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,282 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <AzCore/Math/MathUtils.h>
|
|
||||||
|
|
||||||
#include "ColorBlockRGBA4x4f.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
static_assert(sizeof(int) == 4, "Expected size of int to be 4 bytes!");
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4f::setRGBAf(const void* imgRGBAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgRGBAf, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(ColorRGBAf), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorRGBAf* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const float* const pSrc = (const float*)(((const uint8*)imgRGBAf) + (pitch * (y + row)) + (x * sizeof(ColorRGBAf)));
|
|
||||||
|
|
||||||
ColorRGBAf* const pDst = &m_color[row << 2];
|
|
||||||
|
|
||||||
pDst[0].setRGBA(&pSrc[0 * sizeof(ColorRGBAf) / sizeof(*pSrc)]);
|
|
||||||
pDst[1].setRGBA(&pSrc[1 * sizeof(ColorRGBAf) / sizeof(*pSrc)]);
|
|
||||||
pDst[2].setRGBA(&pSrc[2 * sizeof(ColorRGBAf) / sizeof(*pSrc)]);
|
|
||||||
pDst[3].setRGBA(&pSrc[3 * sizeof(ColorRGBAf) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
const float* const pSrc = (const float*)(((const uint8*)imgRGBAf) + pitch * (y + by));
|
|
||||||
|
|
||||||
ColorRGBAf* pDst = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pDst[col].setRGBA(&pSrc[(x + bx) * sizeof(ColorRGBAf) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4f::getRGBAf(void* imgRGBAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgRGBAf, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(ColorRGBAf), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorRGBAf* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
float* const pDst = (float*)(((uint8*)imgRGBAf) + (pitch * (y + row)) + (x * sizeof(ColorRGBAf)));
|
|
||||||
|
|
||||||
const ColorRGBAf* const pSrc = &m_color[row << 2];
|
|
||||||
|
|
||||||
pSrc[0].getRGBA(&pDst[0 * sizeof(ColorRGBAf) / sizeof(*pDst)]);
|
|
||||||
pSrc[1].getRGBA(&pDst[1 * sizeof(ColorRGBAf) / sizeof(*pDst)]);
|
|
||||||
pSrc[2].getRGBA(&pDst[2 * sizeof(ColorRGBAf) / sizeof(*pDst)]);
|
|
||||||
pSrc[3].getRGBA(&pDst[3 * sizeof(ColorRGBAf) / sizeof(*pDst)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
float* const pDst = (float*)(((uint8*)imgRGBAf) + pitch * (y + by));
|
|
||||||
|
|
||||||
const ColorRGBAf* const pSrc = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pSrc[col].getRGBA(&pDst[(x + bx) * sizeof(ColorRGBAf) / sizeof(*pDst)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4f::setAf(const void* imgAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgAf, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(float), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorRGBAf* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const float* const pSrc = (const float*)(((const uint8*)imgAf) + (pitch * (y + row)) + (x * sizeof(float)));
|
|
||||||
|
|
||||||
ColorRGBAf* const pDst = &m_color[row << 2];
|
|
||||||
|
|
||||||
pDst[0].setRGBA(0, 0, 0, pSrc[0]);
|
|
||||||
pDst[1].setRGBA(0, 0, 0, pSrc[1]);
|
|
||||||
pDst[2].setRGBA(0, 0, 0, pSrc[2]);
|
|
||||||
pDst[3].setRGBA(0, 0, 0, pSrc[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
const float* const pSrc = (const float*)(((const uint8*)imgAf) + (pitch * (y + by)));
|
|
||||||
|
|
||||||
ColorRGBAf* pDst = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pDst[col].setRGBA(0, 0, 0, pSrc[x + bx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4f::getAf(void* imgAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgAf, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(float), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorRGBAf* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
float* const pDst = (float*)(((uint8*)imgAf) + (pitch * (y + row)) + (x * sizeof(float)));
|
|
||||||
float r, g, b;
|
|
||||||
|
|
||||||
const ColorRGBAf* const pSrc = &m_color[row << 2];
|
|
||||||
|
|
||||||
pSrc[0].getRGBA(r, g, b, pDst[0]);
|
|
||||||
pSrc[1].getRGBA(r, g, b, pDst[1]);
|
|
||||||
pSrc[2].getRGBA(r, g, b, pDst[2]);
|
|
||||||
pSrc[3].getRGBA(r, g, b, pDst[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
float* const pDst = (float*)(((uint8*)imgAf) + pitch * (y + by));
|
|
||||||
float r, g, b;
|
|
||||||
|
|
||||||
const ColorRGBAf* const pSrc = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pSrc[col].getRGBA(r, g, b, pDst[x + bx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ColorTypes.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
// Uncompressed 4x4 color block of single precision floating points.
|
|
||||||
struct ColorBlockRGBA4x4f
|
|
||||||
{
|
|
||||||
ColorBlockRGBA4x4f()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBAf(const void* imgARGBf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
void getRGBAf(void* imgARGBf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
void setAf(const void* imgAf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
void getAf(void* imgAf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
const ColorRGBAf* colors() const
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBAf* colors()
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBAf color(unsigned int i) const
|
|
||||||
{
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBAf& color(unsigned int i)
|
|
||||||
{
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const unsigned int COLOR_COUNT = 4 * 4;
|
|
||||||
|
|
||||||
ColorRGBAf m_color[COLOR_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,297 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <AzCore/Math/MathUtils.h>
|
|
||||||
|
|
||||||
#include "ColorBlockRGBA4x4s.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
static_assert(sizeof(int) == 4, "Expected size of int to be 4 bytes!");
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4s::setRGBA16(const void* imgBGRA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgBGRA16, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(ColorRGBA16), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA16* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const uint16* const pSrc = (const uint16*)(((const uint8*)imgBGRA16) + (pitch * (y + row)) + (x * sizeof(ColorRGBA16)));
|
|
||||||
|
|
||||||
ColorRGBA16* const pDst = &m_color[row << 2];
|
|
||||||
|
|
||||||
pDst[0].setRGBA(&pSrc[0 * sizeof(ColorRGBA16) / sizeof(*pSrc)]);
|
|
||||||
pDst[1].setRGBA(&pSrc[1 * sizeof(ColorRGBA16) / sizeof(*pSrc)]);
|
|
||||||
pDst[2].setRGBA(&pSrc[2 * sizeof(ColorRGBA16) / sizeof(*pSrc)]);
|
|
||||||
pDst[3].setRGBA(&pSrc[3 * sizeof(ColorRGBA16) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
const uint16* const pSrc = (const uint16*)(((const uint8*)imgBGRA16) + pitch * (y + by));
|
|
||||||
|
|
||||||
ColorRGBA16* pDst = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pDst[col].setRGBA(&pSrc[(x + bx) * sizeof(ColorRGBA16) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4s::getRGBA16(void* imgBGRA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgBGRA16, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(ColorRGBA16), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA16* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
uint16* const pDst = (uint16*)(((uint8*)imgBGRA16) + (pitch * (y + row)) + (x * sizeof(ColorRGBA16)));
|
|
||||||
|
|
||||||
const ColorRGBA16* const pSrc = &m_color[row << 2];
|
|
||||||
|
|
||||||
pSrc[0].getRGBA(&pDst[0 * sizeof(ColorRGBA16) / sizeof(*pDst)]);
|
|
||||||
pSrc[1].getRGBA(&pDst[1 * sizeof(ColorRGBA16) / sizeof(*pDst)]);
|
|
||||||
pSrc[2].getRGBA(&pDst[2 * sizeof(ColorRGBA16) / sizeof(*pDst)]);
|
|
||||||
pSrc[3].getRGBA(&pDst[3 * sizeof(ColorRGBA16) / sizeof(*pDst)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
uint16* const pDst = (uint16*)(((uint8*)imgBGRA16) + pitch * (y + by));
|
|
||||||
|
|
||||||
const ColorRGBA16* const pSrc = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pSrc[col].getRGBA(&pDst[(x + bx) * sizeof(ColorRGBA16) / sizeof(*pSrc)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4s::setA16(const void* imgA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgA16, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA16* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const uint16* const pSrc = (const uint16*)(((const uint8*)imgA16) + (pitch * (y + row)) + (x * sizeof(uint16)));
|
|
||||||
|
|
||||||
ColorRGBA16* const pDst = &m_color[row << 2];
|
|
||||||
|
|
||||||
pDst[0].setRGBA(0, 0, 0, pSrc[0]);
|
|
||||||
pDst[1].setRGBA(0, 0, 0, pSrc[1]);
|
|
||||||
pDst[2].setRGBA(0, 0, 0, pSrc[2]);
|
|
||||||
pDst[3].setRGBA(0, 0, 0, pSrc[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
const uint16* const pSrc = (const uint16*)(((const uint8*)imgA16) + pitch * (y + by));
|
|
||||||
|
|
||||||
ColorRGBA16* pDst = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pDst[col].setRGBA(0, 0, 0, pSrc[x + bx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBlockRGBA4x4s::getA16(void* imgA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
AZ_Assert(imgA16, "%s: Unexpected image pointer", __FUNCTION__);
|
|
||||||
AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__);
|
|
||||||
AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__);
|
|
||||||
AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__);
|
|
||||||
AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__);
|
|
||||||
AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__);
|
|
||||||
|
|
||||||
const unsigned int bw = AZ::GetMin(width - x, 4U);
|
|
||||||
const unsigned int bh = AZ::GetMin(height - y, 4U);
|
|
||||||
|
|
||||||
// note: it's allowed for source data to be not aligned to 4 byte boundary
|
|
||||||
// (so, we cannot cast source data pointer to ColorBGRA16* in code below)
|
|
||||||
|
|
||||||
if ((bw == 4) && (bh == 4))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
uint16* const pDst = (uint16*)(((uint8*)imgA16) + (pitch * (y + row)) + (x * sizeof(uint16)));
|
|
||||||
uint16 r, g, b;
|
|
||||||
|
|
||||||
const ColorRGBA16* const pSrc = &m_color[row << 2];
|
|
||||||
|
|
||||||
pSrc[0].getRGBA(r, g, b, pDst[0]);
|
|
||||||
pSrc[1].getRGBA(r, g, b, pDst[1]);
|
|
||||||
pSrc[2].getRGBA(r, g, b, pDst[2]);
|
|
||||||
pSrc[3].getRGBA(r, g, b, pDst[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Rare case: block is smaller than 4x4.
|
|
||||||
// Let's repeat pixels in this case.
|
|
||||||
// It will keep frequency of colors, except the case
|
|
||||||
// when width and/or height equals 3. But, this case
|
|
||||||
// is very rare because images usually are "power of 2" sized, and even
|
|
||||||
// if they are not, nobody will notice that the resulting encoding
|
|
||||||
// for such block is not ideal.
|
|
||||||
|
|
||||||
static unsigned int remainder[] =
|
|
||||||
{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < 4; ++row)
|
|
||||||
{
|
|
||||||
const unsigned int by = remainder[(bh - 1) * 4 + row];
|
|
||||||
uint16* const pDst = (uint16*)(((uint8*)imgA16) + pitch * (y + by));
|
|
||||||
uint16 r, g, b;
|
|
||||||
|
|
||||||
const ColorRGBA16* const pSrc = &m_color[row * 4];
|
|
||||||
|
|
||||||
for (unsigned int col = 0; col < 4; ++col)
|
|
||||||
{
|
|
||||||
const unsigned int bx = remainder[(bw - 1) * 4 + col];
|
|
||||||
|
|
||||||
pSrc[col].getRGBA(r, g, b, pDst[x + bx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ColorBlockRGBA4x4s::isSingleColorIgnoringAlpha() const
|
|
||||||
{
|
|
||||||
for (unsigned int i = 1; i < COLOR_COUNT; ++i)
|
|
||||||
{
|
|
||||||
if ((m_color[0].b != m_color[i].b) ||
|
|
||||||
(m_color[0].g != m_color[i].g) ||
|
|
||||||
(m_color[0].r != m_color[i].r))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include "ColorTypes.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
// Uncompressed 4x4 color block of 16bit integers.
|
|
||||||
struct ColorBlockRGBA4x4s
|
|
||||||
{
|
|
||||||
ColorBlockRGBA4x4s()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA16(const void* imgRGBA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
void getRGBA16(void* imgRGBA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
void setA16(const void* imgA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
void getA16(void* imgA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
bool isSingleColorIgnoringAlpha() const;
|
|
||||||
|
|
||||||
const ColorRGBA16* colors() const
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA16* colors()
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA16 color(unsigned int i) const
|
|
||||||
{
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA16& color(unsigned int i)
|
|
||||||
{
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const unsigned int COLOR_COUNT = 4 * 4;
|
|
||||||
|
|
||||||
ColorRGBA16 m_color[COLOR_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,228 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
// 32 bit 8888 RGBA color
|
|
||||||
struct ColorRGBA8
|
|
||||||
{
|
|
||||||
ColorRGBA8()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA8(const ColorRGBA8& a_c)
|
|
||||||
: u(a_c.u)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA8(uint8 a_r, uint8 a_g, uint8 a_b, uint8 a_a)
|
|
||||||
: r(a_r)
|
|
||||||
, g(a_g)
|
|
||||||
, b(a_b)
|
|
||||||
, a(a_a)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit ColorRGBA8(uint32 a_u)
|
|
||||||
: u(a_u)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA(uint8 a_r, uint8 a_g, uint8 a_b, uint8 a_a)
|
|
||||||
{
|
|
||||||
r = a_r;
|
|
||||||
g = a_g;
|
|
||||||
b = a_b;
|
|
||||||
a = a_a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA(const uint8* a_pRGBA8)
|
|
||||||
{
|
|
||||||
r = a_pRGBA8[0];
|
|
||||||
g = a_pRGBA8[1];
|
|
||||||
b = a_pRGBA8[2];
|
|
||||||
a = a_pRGBA8[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
void getRGBA(uint8& a_r, uint8& a_g, uint8& a_b, uint8& a_a) const
|
|
||||||
{
|
|
||||||
a_r = r;
|
|
||||||
a_g = g;
|
|
||||||
a_b = b;
|
|
||||||
a_a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getRGBA(uint8* a_pRGBA8) const
|
|
||||||
{
|
|
||||||
a_pRGBA8[0] = r;
|
|
||||||
a_pRGBA8[1] = g;
|
|
||||||
a_pRGBA8[2] = b;
|
|
||||||
a_pRGBA8[3] = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8 r;
|
|
||||||
uint8 g;
|
|
||||||
uint8 b;
|
|
||||||
uint8 a;
|
|
||||||
};
|
|
||||||
uint32 u;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 64 bit 16161616 RGBA color
|
|
||||||
struct ColorRGBA16
|
|
||||||
{
|
|
||||||
ColorRGBA16()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA16(const ColorRGBA16& a_c)
|
|
||||||
: u(a_c.u)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA16(uint16 a_r, uint16 a_g, uint16 a_b, uint16 a_a)
|
|
||||||
: r(a_r)
|
|
||||||
, g(a_g)
|
|
||||||
, b(a_b)
|
|
||||||
, a(a_a)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit ColorRGBA16(AZ::u64 a_u)
|
|
||||||
: u(a_u)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA(uint16 a_r, uint16 a_g, uint16 a_b, uint16 a_a)
|
|
||||||
{
|
|
||||||
r = a_r;
|
|
||||||
g = a_g;
|
|
||||||
b = a_b;
|
|
||||||
a = a_a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA(const uint16* a_pRGBA16)
|
|
||||||
{
|
|
||||||
r = a_pRGBA16[0];
|
|
||||||
g = a_pRGBA16[1];
|
|
||||||
b = a_pRGBA16[2];
|
|
||||||
a = a_pRGBA16[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void getRGBA(uint16& a_r, uint16& a_g, uint16& a_b, uint16& a_a) const
|
|
||||||
{
|
|
||||||
a_r = r;
|
|
||||||
a_g = g;
|
|
||||||
a_b = b;
|
|
||||||
a_a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getRGBA(uint16* a_pRGBA16) const
|
|
||||||
{
|
|
||||||
a_pRGBA16[0] = r;
|
|
||||||
a_pRGBA16[1] = g;
|
|
||||||
a_pRGBA16[2] = b;
|
|
||||||
a_pRGBA16[3] = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16 r;
|
|
||||||
uint16 g;
|
|
||||||
uint16 b;
|
|
||||||
uint16 a;
|
|
||||||
};
|
|
||||||
AZ::u64 u;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 128 bit (4 floats) RGBA color
|
|
||||||
struct ColorRGBAf
|
|
||||||
{
|
|
||||||
ColorRGBAf()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBAf(const ColorRGBAf& a_c)
|
|
||||||
: r(a_c.r)
|
|
||||||
, g(a_c.g)
|
|
||||||
, b(a_c.b)
|
|
||||||
, a(a_c.a)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBAf(float a_r, float a_g, float a_b, float a_a)
|
|
||||||
: r(a_r)
|
|
||||||
, g(a_g)
|
|
||||||
, b(a_b)
|
|
||||||
, a(a_a)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA(float a_r, float a_g, float a_b, float a_a)
|
|
||||||
{
|
|
||||||
r = a_r;
|
|
||||||
g = a_g;
|
|
||||||
b = a_b;
|
|
||||||
a = a_a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRGBA(const float* a_pRGBAf)
|
|
||||||
{
|
|
||||||
r = a_pRGBAf[0];
|
|
||||||
g = a_pRGBAf[1];
|
|
||||||
b = a_pRGBAf[2];
|
|
||||||
a = a_pRGBAf[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
void getRGBA(float& a_r, float& a_g, float& a_b, float& a_a) const
|
|
||||||
{
|
|
||||||
a_r = r;
|
|
||||||
a_g = g;
|
|
||||||
a_b = b;
|
|
||||||
a_a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getRGBA(float* a_pRGBAf) const
|
|
||||||
{
|
|
||||||
a_pRGBAf[0] = r;
|
|
||||||
a_pRGBAf[1] = g;
|
|
||||||
a_pRGBAf[2] = b;
|
|
||||||
a_pRGBAf[3] = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
float r;
|
|
||||||
float g;
|
|
||||||
float b;
|
|
||||||
float a;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(ColorRGBA8) == 4, "Expected size of ColorRGBA8 to be 4 bytes!");
|
|
||||||
static_assert(sizeof(ColorRGBA16) == 8, "Expected size of ColorRGBA16 to be 4 bytes!");
|
|
||||||
static_assert(sizeof(ColorRGBAf) == 16, "Expected size of ColorRGBAf to be 4 bytes!");
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,657 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include <ImageProcessing_Traits_Platform.h>
|
|
||||||
#include "ColorBlockRGBA4x4c.h"
|
|
||||||
#include "ColorBlockRGBA4x4s.h"
|
|
||||||
#include "ColorBlockRGBA4x4f.h"
|
|
||||||
#include "CryTextureSquisher.h"
|
|
||||||
|
|
||||||
#include <AzCore/std/parallel/mutex.h>
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
# pragma clang diagnostic push
|
|
||||||
# pragma clang diagnostic ignored "-Wnull-dereference"
|
|
||||||
# pragma clang diagnostic ignored "-Wsometimes-uninitialized"
|
|
||||||
# pragma clang diagnostic ignored "-Wshift-negative-value"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL
|
|
||||||
#define __fastcall
|
|
||||||
#define _fastcall
|
|
||||||
#define __assume(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <squish-ccr/squish.h>
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// number of bytes per block per type
|
|
||||||
#define BLOCKSIZE_BC1 8
|
|
||||||
#define BLOCKSIZE_BC2 16
|
|
||||||
#define BLOCKSIZE_BC3 16
|
|
||||||
#define BLOCKSIZE_BC4 8
|
|
||||||
#define BLOCKSIZE_BC5 16
|
|
||||||
#define BLOCKSIZE_BC6 16
|
|
||||||
#define BLOCKSIZE_BC7 16
|
|
||||||
#define BLOCKSIZE_CTX1 8
|
|
||||||
#define BLOCKSIZE_LIMIT 16
|
|
||||||
|
|
||||||
#define PTROFFSET_R 0
|
|
||||||
#define PTROFFSET_G 1
|
|
||||||
#define PTROFFSET_B 2
|
|
||||||
#define PTROFFSET_A 3
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
AZStd::mutex s_squishLock;
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------------------------------------------
|
|
||||||
* internal presets
|
|
||||||
*/
|
|
||||||
static struct ParameterMatrix
|
|
||||||
{
|
|
||||||
int flagsBaseline;
|
|
||||||
int flagsUniform;
|
|
||||||
int flagsPerceptual;
|
|
||||||
int flagsQuality[CryTextureSquisher::EQualityProfile::eQualityProfile_Num];
|
|
||||||
|
|
||||||
size_t offset;
|
|
||||||
bool alphaOnly;
|
|
||||||
} P2P[] =
|
|
||||||
{
|
|
||||||
// eCompressorPreset_BC1U,
|
|
||||||
{
|
|
||||||
squish::kBtc1 + squish::kExcludeAlphaFromPalette,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC2U,
|
|
||||||
{
|
|
||||||
squish::kBtc2,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC3U,
|
|
||||||
{
|
|
||||||
squish::kBtc3,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC4U,
|
|
||||||
{
|
|
||||||
squish::kBtc4,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_R, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC5U,
|
|
||||||
{
|
|
||||||
squish::kBtc5,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_R, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC6UH,
|
|
||||||
{
|
|
||||||
squish::kBtc6,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC7U,
|
|
||||||
{
|
|
||||||
squish::kBtc7,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_BC4S,
|
|
||||||
{
|
|
||||||
squish::kBtc4 + squish::kSignedInternal,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_R, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC5S,
|
|
||||||
{
|
|
||||||
squish::kBtc5 + squish::kSignedInternal,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_R, false
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_BC1Un,
|
|
||||||
{
|
|
||||||
squish::kBtc1 + squish::kExcludeAlphaFromPalette,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC2Un,
|
|
||||||
{
|
|
||||||
squish::kBtc2,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC3Un,
|
|
||||||
{
|
|
||||||
squish::kBtc3,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ squish::kNormalRangeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC4Un,
|
|
||||||
{
|
|
||||||
squish::kBtc4,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_B, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC5Un,
|
|
||||||
{
|
|
||||||
squish::kBtc5,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_R, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC6UHn,
|
|
||||||
{
|
|
||||||
squish::kBtc6,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC7Un,
|
|
||||||
{
|
|
||||||
squish::kBtc7,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_BC4Sn,
|
|
||||||
{
|
|
||||||
squish::kBtc4 + squish::kSignedInternal,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_B, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC5Sn,
|
|
||||||
{
|
|
||||||
squish::kBtc5 + squish::kSignedInternal,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_R, false
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_BC1Ua,
|
|
||||||
{
|
|
||||||
squish::kBtc1 + squish::kWeightColourByAlpha,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC2Ut,
|
|
||||||
{
|
|
||||||
squish::kBtc2 + squish::kWeightColourByAlpha,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC3Ut,
|
|
||||||
{
|
|
||||||
squish::kBtc3 + squish::kWeightColourByAlpha,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC4Ua,
|
|
||||||
{
|
|
||||||
squish::kBtc4,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_A, true
|
|
||||||
},
|
|
||||||
// eCompressorPreset_BC7Ut
|
|
||||||
{
|
|
||||||
squish::kBtc7 + squish::kWeightColourByAlpha,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricPerceptual,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_BC4Sa,
|
|
||||||
{
|
|
||||||
squish::kBtc4 + squish::kSignedInternal,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
|
|
||||||
|
|
||||||
PTROFFSET_A, true
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_BC7Ug
|
|
||||||
{
|
|
||||||
squish::kBtc7,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourClusterFit * 15, squish::kColourClusterFit * 15 },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
|
|
||||||
// eCompressorPreset_CTX1U
|
|
||||||
{
|
|
||||||
squish::kCtx1,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
squish::kColourMetricUniform,
|
|
||||||
{ squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
// eCompressorPreset_CTX1Un
|
|
||||||
{
|
|
||||||
squish::kCtx1,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
squish::kColourMetricUnit,
|
|
||||||
{ squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
|
|
||||||
|
|
||||||
0, false
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------------------------------------------
|
|
||||||
* compression functions
|
|
||||||
*/
|
|
||||||
void CryTextureSquisher::Compress(const CryTextureSquisher::CompressorParameters& compress)
|
|
||||||
{
|
|
||||||
const unsigned int w = compress.width;
|
|
||||||
const unsigned int h = compress.height;
|
|
||||||
const size_t offset = P2P[compress.preset].offset;
|
|
||||||
int flags = P2P[compress.preset].flagsBaseline + P2P[compress.preset].flagsQuality[compress.quality] +
|
|
||||||
(!compress.perceptual ? P2P[compress.preset].flagsUniform : P2P[compress.preset].flagsPerceptual);
|
|
||||||
const bool bAlphaOnly = P2P[compress.preset].alphaOnly;
|
|
||||||
|
|
||||||
squish::sqio::dtp datatype;
|
|
||||||
switch (compress.srcType)
|
|
||||||
{
|
|
||||||
case eBufferType_sint8:
|
|
||||||
flags += squish::kSignedExternal;
|
|
||||||
case eBufferType_uint8:
|
|
||||||
datatype = squish::sqio::dtp::DT_U8;
|
|
||||||
break;
|
|
||||||
case eBufferType_sint16:
|
|
||||||
flags += squish::kSignedExternal;
|
|
||||||
case eBufferType_uint16:
|
|
||||||
datatype = squish::sqio::dtp::DT_U16;
|
|
||||||
break;
|
|
||||||
case eBufferType_sfloat:
|
|
||||||
flags += squish::kSignedExternal;
|
|
||||||
case eBufferType_ufloat:
|
|
||||||
datatype = squish::sqio::dtp::DT_F23;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
__assume(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
|
|
||||||
{
|
|
||||||
flags |= squish::kColourMetricCustom;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags);
|
|
||||||
|
|
||||||
if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
|
|
||||||
{
|
|
||||||
s_squishLock.lock();
|
|
||||||
}
|
|
||||||
if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
|
|
||||||
{
|
|
||||||
squish::SetWeights(sqio.flags, &compress.weights[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__);
|
|
||||||
|
|
||||||
switch (compress.srcType)
|
|
||||||
{
|
|
||||||
// compress an unsigned 8bit texture --------------------------------------------------
|
|
||||||
// compress a signed 8bit texture -----------------------------------------------------
|
|
||||||
case eBufferType_uint8:
|
|
||||||
case eBufferType_sint8:
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0U; y < h; y += 4U)
|
|
||||||
{
|
|
||||||
ColorBlockRGBA4x4c srcBlock;
|
|
||||||
uint8 dstBlock[BLOCKSIZE_LIMIT];
|
|
||||||
|
|
||||||
uint8* const targetBlock = dstBlock;
|
|
||||||
const uint8* const sourceRgba = (const uint8*)srcBlock.colors() + offset;
|
|
||||||
|
|
||||||
for (unsigned int x = 0U; x < w; x += 4U)
|
|
||||||
{
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
srcBlock.setRGBA8(compress.srcBuffer, w, h, compress.pitch, x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcBlock.setA8(compress.srcBuffer, w, h, compress.pitch, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
|
|
||||||
|
|
||||||
if (compress.userOutputFunction)
|
|
||||||
{
|
|
||||||
compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// compress an unsigned 16bit texture -------------------------------------------------
|
|
||||||
// compress a signed 16bit texture ----------------------------------------------------
|
|
||||||
case eBufferType_uint16:
|
|
||||||
case eBufferType_sint16:
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0U; y < h; y += 4U)
|
|
||||||
{
|
|
||||||
ColorBlockRGBA4x4s srcBlock;
|
|
||||||
uint8 dstBlock[BLOCKSIZE_LIMIT];
|
|
||||||
|
|
||||||
uint8* const targetBlock = dstBlock;
|
|
||||||
const float* const sourceRgba = (const float*)srcBlock.colors() + offset;
|
|
||||||
|
|
||||||
for (unsigned int x = 0U; x < w; x += 4U)
|
|
||||||
{
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
srcBlock.setRGBA16(compress.srcBuffer, w, h, compress.pitch, x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcBlock.setA16(compress.srcBuffer, w, h, compress.pitch, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
|
|
||||||
|
|
||||||
if (compress.userOutputFunction)
|
|
||||||
{
|
|
||||||
compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// compress an unsigned floating point texture ----------------------------------------
|
|
||||||
// compress a signed floating point texture -------------------------------------------
|
|
||||||
case eBufferType_ufloat:
|
|
||||||
case eBufferType_sfloat:
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0U; y < h; y += 4U)
|
|
||||||
{
|
|
||||||
ColorBlockRGBA4x4f srcBlock;
|
|
||||||
uint8 dstBlock[BLOCKSIZE_LIMIT];
|
|
||||||
|
|
||||||
uint8* const targetBlock = dstBlock;
|
|
||||||
const float* const sourceRgba = (const float*)srcBlock.colors() + offset;
|
|
||||||
|
|
||||||
for (unsigned int x = 0U; x < w; x += 4U)
|
|
||||||
{
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
srcBlock.setRGBAf(compress.srcBuffer, w, h, compress.pitch, x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcBlock.setAf(compress.srcBuffer, w, h, compress.pitch, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
|
|
||||||
|
|
||||||
if (compress.userOutputFunction)
|
|
||||||
{
|
|
||||||
compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
AZ_Assert(false, "%s: Unexpected compress source type", __FUNCTION__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
|
|
||||||
{
|
|
||||||
s_squishLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CryTextureSquisher::Decompress(const DecompressorParameters& decompress)
|
|
||||||
{
|
|
||||||
const unsigned int w = decompress.width;
|
|
||||||
const unsigned int h = decompress.height;
|
|
||||||
const size_t offset = P2P[decompress.preset].offset;
|
|
||||||
int flags = P2P[decompress.preset].flagsBaseline +
|
|
||||||
P2P[decompress.preset].flagsUniform;
|
|
||||||
const bool bAlphaOnly = P2P[decompress.preset].alphaOnly;
|
|
||||||
|
|
||||||
squish::sqio::dtp datatype;
|
|
||||||
switch (decompress.dstType)
|
|
||||||
{
|
|
||||||
case eBufferType_sint8:
|
|
||||||
flags += squish::kSignedExternal;
|
|
||||||
case eBufferType_uint8:
|
|
||||||
datatype = squish::sqio::dtp::DT_U8;
|
|
||||||
break;
|
|
||||||
case eBufferType_sint16:
|
|
||||||
flags += squish::kSignedExternal;
|
|
||||||
case eBufferType_uint16:
|
|
||||||
datatype = squish::sqio::dtp::DT_U16;
|
|
||||||
break;
|
|
||||||
case eBufferType_sfloat:
|
|
||||||
flags += squish::kSignedExternal;
|
|
||||||
case eBufferType_ufloat:
|
|
||||||
datatype = squish::sqio::dtp::DT_F23;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
__assume(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags);
|
|
||||||
|
|
||||||
AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__);
|
|
||||||
|
|
||||||
switch (decompress.dstType)
|
|
||||||
{
|
|
||||||
// decompress an unsigned 8bit texture --------------------------------------------------
|
|
||||||
// decompress a signed 8bit texture -----------------------------------------------------
|
|
||||||
case eBufferType_uint8:
|
|
||||||
case eBufferType_sint8:
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0U; y < h; y += 4U)
|
|
||||||
{
|
|
||||||
uint8 srcBlock[BLOCKSIZE_LIMIT];
|
|
||||||
ColorBlockRGBA4x4c dstBlock;
|
|
||||||
|
|
||||||
uint8* const sourceBlock = srcBlock;
|
|
||||||
uint8* const targetRgba = (uint8*)dstBlock.colors() + offset;
|
|
||||||
|
|
||||||
for (unsigned int x = 0U; x < w; x += 4U)
|
|
||||||
{
|
|
||||||
if (decompress.userInputFunction)
|
|
||||||
{
|
|
||||||
decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
dstBlock.setRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqio.decoder(targetRgba, sourceBlock, sqio.flags);
|
|
||||||
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
dstBlock.getRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstBlock.getA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// decompress an unsigned 16bit texture -------------------------------------------------
|
|
||||||
// decompress a signed 16bit texture ----------------------------------------------------
|
|
||||||
case eBufferType_uint16:
|
|
||||||
case eBufferType_sint16:
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0U; y < h; y += 4U)
|
|
||||||
{
|
|
||||||
uint8 srcBlock[BLOCKSIZE_LIMIT];
|
|
||||||
ColorBlockRGBA4x4s dstBlock;
|
|
||||||
|
|
||||||
uint8* const sourceBlock = srcBlock;
|
|
||||||
uint16* const targetRgba = (uint16*)dstBlock.colors() + offset;
|
|
||||||
|
|
||||||
for (unsigned int x = 0U; x < w; x += 4U)
|
|
||||||
{
|
|
||||||
if (decompress.userInputFunction)
|
|
||||||
{
|
|
||||||
decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqio.decoder(targetRgba, sourceBlock, sqio.flags);
|
|
||||||
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstBlock.getA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// decompress an unsigned floating point texture ----------------------------------------
|
|
||||||
// decompress a signed floating point texture -------------------------------------------
|
|
||||||
case eBufferType_ufloat:
|
|
||||||
case eBufferType_sfloat:
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0U; y < h; y += 4U)
|
|
||||||
{
|
|
||||||
uint8 srcBlock[BLOCKSIZE_LIMIT];
|
|
||||||
ColorBlockRGBA4x4f dstBlock;
|
|
||||||
|
|
||||||
uint8* const sourceBlock = srcBlock;
|
|
||||||
float* const targetRgba = (float*)dstBlock.colors() + offset;
|
|
||||||
|
|
||||||
for (unsigned int x = 0U; x < w; x += 4U)
|
|
||||||
{
|
|
||||||
if (decompress.userInputFunction)
|
|
||||||
{
|
|
||||||
decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
dstBlock.setRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
sqio.decoder(targetRgba, sourceBlock, sqio.flags);
|
|
||||||
|
|
||||||
if (!bAlphaOnly)
|
|
||||||
{
|
|
||||||
dstBlock.getRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstBlock.getAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
AZ_Assert(false, "%s: Unexpected compress destination type", __FUNCTION__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class CryTextureSquisher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum EBufferType
|
|
||||||
{
|
|
||||||
eBufferType_uint8, // native support: BC1-5/7,CTX1
|
|
||||||
eBufferType_sint8, // native support: BC4-5
|
|
||||||
eBufferType_uint16, // native support: BC1-7,CTX1
|
|
||||||
eBufferType_sint16, // native support: BC4-6
|
|
||||||
eBufferType_ufloat, // native support: BC1-7,CTX1
|
|
||||||
eBufferType_sfloat, // native support: BC4-6
|
|
||||||
};
|
|
||||||
|
|
||||||
enum EQualityProfile
|
|
||||||
{
|
|
||||||
eQualityProfile_Low = 0,// as-fast-as-possible
|
|
||||||
eQualityProfile_Medium, // not so bad (nightly builds)
|
|
||||||
eQualityProfile_High, // relative good (weekly builds)
|
|
||||||
eQualityProfile_Best, // as-best-as-possible (final build for release)
|
|
||||||
|
|
||||||
eQualityProfile_Num
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ECodingPreset
|
|
||||||
{
|
|
||||||
eCompressorPreset_BC1U = 0,
|
|
||||||
eCompressorPreset_BC2U,
|
|
||||||
eCompressorPreset_BC3U,
|
|
||||||
eCompressorPreset_BC4U, // r-channel from RGBA
|
|
||||||
eCompressorPreset_BC5U, // rg-channels from RGBA
|
|
||||||
eCompressorPreset_BC6UH,
|
|
||||||
eCompressorPreset_BC7U,
|
|
||||||
|
|
||||||
eCompressorPreset_BC4S, // r-channel from RGBA
|
|
||||||
eCompressorPreset_BC5S, // rg-channels from RGBA
|
|
||||||
|
|
||||||
// normal vectors -> unit metric
|
|
||||||
eCompressorPreset_BC1Un,
|
|
||||||
eCompressorPreset_BC2Un,
|
|
||||||
eCompressorPreset_BC3Un,
|
|
||||||
eCompressorPreset_BC4Un, // z-channel from XYZD
|
|
||||||
eCompressorPreset_BC5Un, // xy-channels from XYZD, xyz must be a valid unit-vector
|
|
||||||
eCompressorPreset_BC6UHn,
|
|
||||||
eCompressorPreset_BC7Un,
|
|
||||||
|
|
||||||
eCompressorPreset_BC4Sn, // z-channel from XYZD
|
|
||||||
eCompressorPreset_BC5Sn, // xy-channels from XYZD, xyz must be a valid unit-vector
|
|
||||||
|
|
||||||
// transparency -> weighted alpha
|
|
||||||
eCompressorPreset_BC1Ua,
|
|
||||||
eCompressorPreset_BC2Ut,
|
|
||||||
eCompressorPreset_BC3Ut,
|
|
||||||
eCompressorPreset_BC4Ua, // a-channel from RGBA
|
|
||||||
eCompressorPreset_BC7Ut,
|
|
||||||
|
|
||||||
eCompressorPreset_BC4Sa, // a-channel from RGBA
|
|
||||||
|
|
||||||
// grey-scale -> 12+ bits of precision
|
|
||||||
eCompressorPreset_BC7Ug,
|
|
||||||
|
|
||||||
// special ones
|
|
||||||
eCompressorPreset_CTX1U, // rg-channels from RGBA
|
|
||||||
eCompressorPreset_CTX1Un, // xy-channels from XYZD, xyz must be a valid unit-vector
|
|
||||||
|
|
||||||
eCompressorPreset_Num
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompressorParameters
|
|
||||||
{
|
|
||||||
// source's parameters
|
|
||||||
EBufferType srcType;
|
|
||||||
const void* srcBuffer;
|
|
||||||
unsigned int width;
|
|
||||||
unsigned int height;
|
|
||||||
unsigned int pitch;
|
|
||||||
|
|
||||||
// coding preset
|
|
||||||
ECodingPreset preset;
|
|
||||||
EQualityProfile quality;
|
|
||||||
|
|
||||||
// either if "srgb==1" or if "rgbweights!=uniform"
|
|
||||||
bool perceptual;
|
|
||||||
float weights[4];
|
|
||||||
|
|
||||||
void* userPtr;
|
|
||||||
int userInt;
|
|
||||||
|
|
||||||
void(*userOutputFunction)(const CompressorParameters& compress, const void* compressedData, unsigned int compressedSize, unsigned int oy, unsigned int ox);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DecompressorParameters
|
|
||||||
{
|
|
||||||
// destination's parameters
|
|
||||||
EBufferType dstType;
|
|
||||||
void* dstBuffer;
|
|
||||||
unsigned int width;
|
|
||||||
unsigned int height;
|
|
||||||
unsigned int pitch;
|
|
||||||
|
|
||||||
// coding preset
|
|
||||||
ECodingPreset preset;
|
|
||||||
|
|
||||||
void* userPtr;
|
|
||||||
int userInt;
|
|
||||||
|
|
||||||
void(*userInputFunction)(const DecompressorParameters& decompress, void* compressedData, unsigned int compressedSize, unsigned int oy, unsigned int ox);
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void Compress(const CompressorParameters& compress);
|
|
||||||
static void Decompress(const DecompressorParameters& decompress);
|
|
||||||
};
|
|
||||||
|
|
||||||
} //namespace ImageProcessing
|
|
||||||
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <Processing/ImageFlags.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
#include <Compressors/ETC2.h>
|
|
||||||
|
|
||||||
#include <EtcConfig.h>
|
|
||||||
#include <Etc.h>
|
|
||||||
#include <EtcImage.h>
|
|
||||||
#include <EtcColorFloatRGBA.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//limited to 1 thread because AP requires so. We may change to n when AP allocate n thread to a job in the furture
|
|
||||||
static const int MAX_COMP_JOBS = 1;
|
|
||||||
static const int MIN_COMP_JOBS = 1;
|
|
||||||
static const float ETC_LOW_EFFORT_LEVEL = 25.0f;
|
|
||||||
static const float ETC_MED_EFFORT_LEVEL = 40.0f;
|
|
||||||
static const float ETC_HIGH_EFFORT_LEVEL = 80.0f;
|
|
||||||
|
|
||||||
//Grab the Etc2Comp specific pixel format enum
|
|
||||||
static Etc::Image::Format FindEtc2PixelFormat(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_EAC_RG11:
|
|
||||||
return Etc::Image::Format::RG11;
|
|
||||||
case ePixelFormat_EAC_R11:
|
|
||||||
return Etc::Image::Format::R11;
|
|
||||||
case ePixelFormat_ETC2:
|
|
||||||
return Etc::Image::Format::RGB8;
|
|
||||||
case ePixelFormat_ETC2a:
|
|
||||||
return Etc::Image::Format::RGBA8;
|
|
||||||
default:
|
|
||||||
return Etc::Image::Format::FORMATS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the errmetric required for the compression
|
|
||||||
static Etc::ErrorMetric FindErrMetric(Etc::Image::Format fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case Etc::Image::Format::RG11:
|
|
||||||
return Etc::ErrorMetric::NORMALXYZ;
|
|
||||||
case Etc::Image::Format::R11:
|
|
||||||
return Etc::ErrorMetric::NUMERIC;
|
|
||||||
case Etc::Image::Format::RGB8:
|
|
||||||
return Etc::ErrorMetric::RGBX;
|
|
||||||
case Etc::Image::Format::RGBA8:
|
|
||||||
return Etc::ErrorMetric::RGBA;
|
|
||||||
default:
|
|
||||||
return Etc::ErrorMetric::ERROR_METRICS;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//Convert to sRGB format
|
|
||||||
static Etc::Image::Format FindGammaEtc2PixelFormat(Etc::Image::Format fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case Etc::Image::Format::RGB8:
|
|
||||||
return Etc::Image::Format::SRGB8;
|
|
||||||
case Etc::Image::Format::RGBA8:
|
|
||||||
return Etc::Image::Format::SRGBA8;
|
|
||||||
case Etc::Image::Format::RGB8A1:
|
|
||||||
return Etc::Image::Format::SRGB8A1;
|
|
||||||
default:
|
|
||||||
return Etc::Image::Format::FORMATS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ETC2Compressor::IsCompressedPixelFormatSupported(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
return (FindEtc2PixelFormat(fmt) != Etc::Image::Format::FORMATS);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ETC2Compressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
//for uncompress format
|
|
||||||
if (fmt == ePixelFormat_R8G8B8A8)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EPixelFormat ETC2Compressor::GetSuggestedUncompressedFormat([[maybe_unused]] EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt)
|
|
||||||
{
|
|
||||||
return ePixelFormat_R8G8B8A8;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ETC2Compressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr ETC2Compressor::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst,
|
|
||||||
const CompressOption *compressOption)
|
|
||||||
{
|
|
||||||
const size_t srcPixelSize = 4;
|
|
||||||
|
|
||||||
//validate input
|
|
||||||
EPixelFormat fmtSrc = srcImage->GetPixelFormat();
|
|
||||||
|
|
||||||
//src format need to be uncompressed and dst format need to compressed.
|
|
||||||
if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst));
|
|
||||||
|
|
||||||
//determinate compression quality
|
|
||||||
ICompressor::EQuality quality = ICompressor::eQuality_Normal;
|
|
||||||
//get setting from compression option
|
|
||||||
if (compressOption)
|
|
||||||
{
|
|
||||||
quality = compressOption->compressQuality;
|
|
||||||
}
|
|
||||||
|
|
||||||
float qualityEffort = 0.0f;
|
|
||||||
switch (quality)
|
|
||||||
{
|
|
||||||
case eQuality_Preview:
|
|
||||||
case eQuality_Fast:
|
|
||||||
{
|
|
||||||
qualityEffort = ETC_LOW_EFFORT_LEVEL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eQuality_Normal:
|
|
||||||
{
|
|
||||||
qualityEffort = ETC_MED_EFFORT_LEVEL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
qualityEffort = ETC_HIGH_EFFORT_LEVEL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Etc::Image::Format dstEtc2Format = FindEtc2PixelFormat(fmtDst);
|
|
||||||
if (srcImage->GetImageFlags() & EIF_SRGBRead)
|
|
||||||
{
|
|
||||||
dstEtc2Format = FindGammaEtc2PixelFormat(dstEtc2Format);
|
|
||||||
}
|
|
||||||
|
|
||||||
//use to read pixel data from src image
|
|
||||||
IPixelOperationPtr pixelOp = CreatePixelOperation(fmtSrc);
|
|
||||||
//get count of bytes per pixel for images
|
|
||||||
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtSrc)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
const AZ::u32 mipCount = dstImage->GetMipCount();
|
|
||||||
for (AZ::u32 mip = 0; mip < mipCount; ++mip)
|
|
||||||
{
|
|
||||||
const AZ::u32 width = srcImage->GetWidth(mip);
|
|
||||||
const AZ::u32 height = srcImage->GetHeight(mip);
|
|
||||||
|
|
||||||
// Prepare source data
|
|
||||||
AZ::u8* srcMem;
|
|
||||||
AZ::u32 srcPitch;
|
|
||||||
srcImage->GetImagePointer(mip, srcMem, srcPitch);
|
|
||||||
const AZ::u32 pixelCount = srcImage->GetPixelCount(mip);
|
|
||||||
|
|
||||||
Etc::ColorFloatRGBA* rgbaPixels = new Etc::ColorFloatRGBA[pixelCount];
|
|
||||||
Etc::ColorFloatRGBA* rgbaPixelPtr = rgbaPixels;
|
|
||||||
float r, g, b, a;
|
|
||||||
for (AZ::u32 pixelIdx = 0; pixelIdx < pixelCount; pixelIdx++, srcMem += pixelBytes, rgbaPixelPtr++)
|
|
||||||
{
|
|
||||||
pixelOp->GetRGBA(srcMem, r, g, b, a);
|
|
||||||
rgbaPixelPtr->fA = a;
|
|
||||||
rgbaPixelPtr->fR = r;
|
|
||||||
rgbaPixelPtr->fG = g;
|
|
||||||
rgbaPixelPtr->fB = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Call into etc2Comp lib to compress. https://medium.com/@duhroach/building-a-blazing-fast-etc2-compressor-307f3e9aad99
|
|
||||||
Etc::ErrorMetric errMetric = FindErrMetric(dstEtc2Format);
|
|
||||||
unsigned char* paucEncodingBits;
|
|
||||||
unsigned int uiEncodingBitsBytes;
|
|
||||||
unsigned int uiExtendedWidth;
|
|
||||||
unsigned int uiExtendedHeight;
|
|
||||||
int iEncodingTime_ms;
|
|
||||||
|
|
||||||
Etc::Encode(reinterpret_cast<float*>(rgbaPixels),
|
|
||||||
width, height,
|
|
||||||
dstEtc2Format,
|
|
||||||
errMetric,
|
|
||||||
qualityEffort,
|
|
||||||
MIN_COMP_JOBS,
|
|
||||||
MAX_COMP_JOBS,
|
|
||||||
&paucEncodingBits, &uiEncodingBitsBytes,
|
|
||||||
&uiExtendedWidth, &uiExtendedHeight,
|
|
||||||
&iEncodingTime_ms);
|
|
||||||
|
|
||||||
AZ::u8* dstMem;
|
|
||||||
AZ::u32 dstPitch;
|
|
||||||
dstImage->GetImagePointer(mip, dstMem, dstPitch);
|
|
||||||
|
|
||||||
memcpy(dstMem, paucEncodingBits, uiEncodingBitsBytes);
|
|
||||||
delete[] rgbaPixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dstImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr ETC2Compressor::DecompressImage(IImageObjectPtr srcImage, [[maybe_unused]] EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
//etc2Comp doesn't support decompression
|
|
||||||
//Since PVRTexLib support ETC formats too. It may take over the decompression.
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Compressors/Compressor.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class ETC2Compressor : public ICompressor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bool IsCompressedPixelFormatSupported(EPixelFormat fmt);
|
|
||||||
static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt);
|
|
||||||
static bool DoesSupportDecompress(EPixelFormat fmtDst);
|
|
||||||
|
|
||||||
IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) override;
|
|
||||||
IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) override;
|
|
||||||
|
|
||||||
EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,389 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include <ImageProcessing_Traits_Platform.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <Processing/ImageFlags.h>
|
|
||||||
#include <Compressors/PVRTC.h>
|
|
||||||
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT
|
|
||||||
//_WINDLL_IMPORT need to be defined before including PVRTexLib header files to avoid linking error on windows.
|
|
||||||
#define _WINDLL_IMPORT
|
|
||||||
// NOMINMAX needs to be defined before including PVRTexLib header files (which include Windows.h)
|
|
||||||
// so that Windows.h doesn't define min/max. Otherwise, a compile error may arise in Uber builds
|
|
||||||
#ifndef NOMINMAX
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <PVRTexture.h>
|
|
||||||
#include <PVRTextureUtilities.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
// Note: PVRTexLib supports ASTC formats, ETC formats, PVRTC formats and BC formats
|
|
||||||
// We haven't tested the performace to compress BC formats compare to CTSquisher
|
|
||||||
// For PVRTC formats, we only added PVRTC 1 support for now
|
|
||||||
// The compression for ePVRTPF_EAC_R11 and ePVRTPF_EAC_RG11 are very slow. It takes 7 and 14 minutes for a 2048x2048 texture.
|
|
||||||
EPVRTPixelFormat FindPvrPixelFormat(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_ASTC_4x4:
|
|
||||||
return ePVRTPF_ASTC_4x4;
|
|
||||||
case ePixelFormat_ASTC_5x4:
|
|
||||||
return ePVRTPF_ASTC_5x4;
|
|
||||||
case ePixelFormat_ASTC_5x5:
|
|
||||||
return ePVRTPF_ASTC_5x5;
|
|
||||||
case ePixelFormat_ASTC_6x5:
|
|
||||||
return ePVRTPF_ASTC_6x5;
|
|
||||||
case ePixelFormat_ASTC_6x6:
|
|
||||||
return ePVRTPF_ASTC_6x6;
|
|
||||||
case ePixelFormat_ASTC_8x5:
|
|
||||||
return ePVRTPF_ASTC_8x5;
|
|
||||||
case ePixelFormat_ASTC_8x6:
|
|
||||||
return ePVRTPF_ASTC_8x6;
|
|
||||||
case ePixelFormat_ASTC_8x8:
|
|
||||||
return ePVRTPF_ASTC_8x8;
|
|
||||||
case ePixelFormat_ASTC_10x5:
|
|
||||||
return ePVRTPF_ASTC_10x5;
|
|
||||||
case ePixelFormat_ASTC_10x6:
|
|
||||||
return ePVRTPF_ASTC_10x6;
|
|
||||||
case ePixelFormat_ASTC_10x8:
|
|
||||||
return ePVRTPF_ASTC_10x8;
|
|
||||||
case ePixelFormat_ASTC_10x10:
|
|
||||||
return ePVRTPF_ASTC_10x10;
|
|
||||||
case ePixelFormat_ASTC_12x10:
|
|
||||||
return ePVRTPF_ASTC_12x10;
|
|
||||||
case ePixelFormat_ASTC_12x12:
|
|
||||||
return ePVRTPF_ASTC_12x12;
|
|
||||||
case ePixelFormat_PVRTC2:
|
|
||||||
return ePVRTPF_PVRTCI_2bpp_RGBA;
|
|
||||||
case ePixelFormat_PVRTC4:
|
|
||||||
return ePVRTPF_PVRTCI_4bpp_RGBA;
|
|
||||||
case ePixelFormat_EAC_R11:
|
|
||||||
return ePVRTPF_EAC_R11;
|
|
||||||
case ePixelFormat_EAC_RG11:
|
|
||||||
return ePVRTPF_EAC_RG11;
|
|
||||||
case ePixelFormat_ETC2:
|
|
||||||
return ePVRTPF_ETC2_RGB;
|
|
||||||
case ePixelFormat_ETC2a:
|
|
||||||
return ePVRTPF_ETC2_RGBA;
|
|
||||||
default:
|
|
||||||
return ePVRTPF_NumCompressedPFs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PVRTCCompressor::IsCompressedPixelFormatSupported(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
return (FindPvrPixelFormat(fmt) != ePVRTPF_NumCompressedPFs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PVRTCCompressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt)
|
|
||||||
{
|
|
||||||
//for uncompress format
|
|
||||||
if (fmt == ePixelFormat_R8G8B8A8)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EPixelFormat PVRTCCompressor::GetSuggestedUncompressedFormat([[maybe_unused]] EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt)
|
|
||||||
{
|
|
||||||
return ePixelFormat_R8G8B8A8;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool PVRTCCompressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr PVRTCCompressor::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst,
|
|
||||||
const CompressOption *compressOption)
|
|
||||||
{
|
|
||||||
//validate input
|
|
||||||
EPixelFormat fmtSrc = srcImage->GetPixelFormat();
|
|
||||||
|
|
||||||
//src format need to be uncompressed and dst format need to compressed.
|
|
||||||
if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst));
|
|
||||||
|
|
||||||
//determinate compression quality
|
|
||||||
pvrtexture::ECompressorQuality internalQuality = pvrtexture::eETCFast;
|
|
||||||
ICompressor::EQuality quality = ICompressor::eQuality_Normal;
|
|
||||||
AZ::Vector3 uniformWeights = AZ::Vector3(0.3333f, 0.3334f, 0.3333f);
|
|
||||||
AZ::Vector3 weights = uniformWeights;
|
|
||||||
bool isUniform = true;
|
|
||||||
//get setting from compression option
|
|
||||||
if (compressOption)
|
|
||||||
{
|
|
||||||
quality = compressOption->compressQuality;
|
|
||||||
weights = compressOption->rgbWeight;
|
|
||||||
isUniform = (weights == uniformWeights);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsETCFormat(fmtDst))
|
|
||||||
{
|
|
||||||
if ((quality <= eQuality_Normal) && isUniform)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eETCFast;
|
|
||||||
}
|
|
||||||
else if (quality <= eQuality_Normal)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eETCNormal;
|
|
||||||
}
|
|
||||||
else if (isUniform)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eETCSlow;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eETCSlow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsASTCFormat(fmtDst))
|
|
||||||
{
|
|
||||||
if (quality == eQuality_Preview)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eASTCVeryFast;
|
|
||||||
}
|
|
||||||
else if (quality == eQuality_Fast)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eASTCFast;
|
|
||||||
}
|
|
||||||
else if (quality == eQuality_Normal)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eASTCMedium;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::eASTCThorough;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (quality == eQuality_Preview)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::ePVRTCFastest;
|
|
||||||
}
|
|
||||||
else if (quality == eQuality_Fast)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::ePVRTCFast;
|
|
||||||
}
|
|
||||||
else if (quality == eQuality_Normal)
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::ePVRTCNormal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
internalQuality = pvrtexture::ePVRTCHigh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup color space
|
|
||||||
EPVRTColourSpace cspace = ePVRTCSpacelRGB;
|
|
||||||
if (srcImage->GetImageFlags() & EIF_SRGBRead)
|
|
||||||
{
|
|
||||||
cspace = ePVRTCSpacesRGB;
|
|
||||||
}
|
|
||||||
|
|
||||||
//setup src texture for compression
|
|
||||||
const pvrtexture::PixelType srcPixelType('r', 'g', 'b', 'a', 8, 8, 8, 8);
|
|
||||||
const AZ::u32 dstMips = dstImage->GetMipCount();
|
|
||||||
for (AZ::u32 mip = 0; mip < dstMips; ++mip)
|
|
||||||
{
|
|
||||||
const AZ::u32 width = srcImage->GetWidth(mip);
|
|
||||||
const AZ::u32 height = srcImage->GetHeight(mip);
|
|
||||||
|
|
||||||
// Prepare source data
|
|
||||||
AZ::u8* srcMem;
|
|
||||||
uint32 srcPitch;
|
|
||||||
srcImage->GetImagePointer(mip, srcMem, srcPitch);
|
|
||||||
|
|
||||||
const pvrtexture::CPVRTextureHeader srcHeader(
|
|
||||||
srcPixelType.PixelTypeID, // AZ::u64 u64PixelFormat,
|
|
||||||
width, // uint32 u32Height=1,
|
|
||||||
height, // uint32 u32Width=1,
|
|
||||||
1, // uint32 u32Depth=1,
|
|
||||||
1, // uint32 u32NumMipMaps=1,
|
|
||||||
1, // uint32 u32NumArrayMembers=1,
|
|
||||||
1, // uint32 u32NumFaces=1,
|
|
||||||
cspace, // EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB,
|
|
||||||
ePVRTVarTypeUnsignedByteNorm, // EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm,
|
|
||||||
false); // bool bPreMultiplied=false);
|
|
||||||
|
|
||||||
pvrtexture::CPVRTexture compressTexture(srcHeader, srcMem);
|
|
||||||
|
|
||||||
//compressing
|
|
||||||
bool isSuccess = false;
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
try
|
|
||||||
#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
{
|
|
||||||
isSuccess = pvrtexture::Transcode(
|
|
||||||
compressTexture,
|
|
||||||
pvrtexture::PixelType(FindPvrPixelFormat(fmtDst)),
|
|
||||||
ePVRTVarTypeUnsignedByteNorm,
|
|
||||||
cspace,
|
|
||||||
internalQuality);
|
|
||||||
}
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Unknown exception in PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
|
|
||||||
if (!isSuccess)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Failed to compress image with PVRTexLib. You may not have astcenc.exe for compressing ASTC formates");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getting compressed data
|
|
||||||
const void* const compressedData = compressTexture.getDataPtr();
|
|
||||||
if (!compressedData)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Failed to obtain compressed image data by using PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AZ::u32 compressedDataSize = compressTexture.getDataSize();
|
|
||||||
if (dstImage->GetMipBufSize(mip) != compressedDataSize)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Compressed image data size mismatch while using PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//save compressed data to dst image
|
|
||||||
AZ::u8* dstMem;
|
|
||||||
AZ::u32 dstPitch;
|
|
||||||
dstImage->GetImagePointer(mip, dstMem, dstPitch);
|
|
||||||
memcpy(dstMem, compressedData, compressedDataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dstImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr PVRTCCompressor::DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
//validate input
|
|
||||||
EPixelFormat fmtSrc = srcImage->GetPixelFormat(); //compressed
|
|
||||||
|
|
||||||
if (!IsCompressedPixelFormatSupported(fmtSrc) || !IsUncompressedPixelFormatSupported(fmtDst))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
EPVRTColourSpace colorSpace = ePVRTCSpacelRGB;
|
|
||||||
if (srcImage->GetImageFlags() & EIF_SRGBRead)
|
|
||||||
{
|
|
||||||
colorSpace = ePVRTCSpacesRGB;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst));
|
|
||||||
|
|
||||||
const AZ::u32 mipCount = dstImage->GetMipCount();
|
|
||||||
for (AZ::u32 mip = 0; mip < mipCount; ++mip)
|
|
||||||
{
|
|
||||||
const AZ::u32 width = srcImage->GetWidth(mip);
|
|
||||||
const AZ::u32 height = srcImage->GetHeight(mip);
|
|
||||||
|
|
||||||
// Preparing source compressed data
|
|
||||||
const pvrtexture::CPVRTextureHeader compressedHeader(
|
|
||||||
FindPvrPixelFormat(fmtSrc), // AZ::u64 u64PixelFormat,
|
|
||||||
width, // uint32 u32Height=1,
|
|
||||||
height, // uint32 u32Width=1,
|
|
||||||
1, // uint32 u32Depth=1,
|
|
||||||
1, // uint32 u32NumMipMaps=1,
|
|
||||||
1, // uint32 u32NumArrayMembers=1,
|
|
||||||
1, // uint32 u32NumFaces=1,
|
|
||||||
colorSpace, // EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB,
|
|
||||||
ePVRTVarTypeUnsignedByteNorm, // EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm,
|
|
||||||
false); // bool bPreMultiplied=false);
|
|
||||||
|
|
||||||
const AZ::u32 compressedDataSize = compressedHeader.getDataSize();
|
|
||||||
if (srcImage->GetMipBufSize(mip) != compressedDataSize)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Decompressed image data size mismatch while using PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::u8* srcMem;
|
|
||||||
AZ::u32 srcPitch;
|
|
||||||
srcImage->GetImagePointer(mip, srcMem, srcPitch);
|
|
||||||
pvrtexture::CPVRTexture cTexture(compressedHeader, srcMem);
|
|
||||||
|
|
||||||
// Decompress
|
|
||||||
bool bOk = false;
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
bOk = pvrtexture::Transcode(
|
|
||||||
cTexture,
|
|
||||||
pvrtexture::PVRStandard8PixelType,
|
|
||||||
ePVRTVarTypeUnsignedByteNorm,
|
|
||||||
colorSpace,
|
|
||||||
pvrtexture::ePVRTCHigh);
|
|
||||||
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Unknown exception in PVRTexLib when decompressing");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH
|
|
||||||
|
|
||||||
if (!bOk)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Failed to decompress an image by using PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getting decompressed data
|
|
||||||
const void* const pDecompressedData = cTexture.getDataPtr();
|
|
||||||
if (!pDecompressedData)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Failed to obtain decompressed image data by using PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AZ::u32 decompressedDataSize = cTexture.getDataSize();
|
|
||||||
if (dstImage->GetMipBufSize(mip) != decompressedDataSize)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "Decompressed image data size mismatch while using PVRTexLib");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//save decompressed image to dst image
|
|
||||||
AZ::u8* dstMem;
|
|
||||||
AZ::u32 dstPitch;
|
|
||||||
dstImage->GetImagePointer(mip, dstMem, dstPitch);
|
|
||||||
memcpy(dstMem, pDecompressedData, decompressedDataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dstImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace ImageProcessing
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Compressors/Compressor.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class PVRTCCompressor : public ICompressor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bool IsCompressedPixelFormatSupported(EPixelFormat fmt);
|
|
||||||
static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt);
|
|
||||||
static bool DoesSupportDecompress(EPixelFormat fmtDst);
|
|
||||||
|
|
||||||
IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) override;
|
|
||||||
IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) override;
|
|
||||||
|
|
||||||
EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageConvert.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//functions for maintaining alpha coverage.
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
void CImageObject::TransferAlphaCoverage(const TextureSettings* textureSetting, const IImageObjectPtr srcImg)
|
|
||||||
{
|
|
||||||
EPixelFormat srcFmt = srcImg->GetPixelFormat();
|
|
||||||
//both this image and src image need to be uncompressed
|
|
||||||
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)
|
|
||||||
|| !CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcFmt))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "Both source image and dest image need to be uncompressed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fAlphaRef = 0.5f; // Seems to give good overall results
|
|
||||||
const float fDesiredAlphaCoverage = srcImg->ComputeAlphaCoverage(0, fAlphaRef);
|
|
||||||
|
|
||||||
//create pixel operation function
|
|
||||||
IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat);
|
|
||||||
//get count of bytes per pixel
|
|
||||||
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
for (uint32 mip = 0; mip < GetMipCount(); mip++)
|
|
||||||
{
|
|
||||||
const float fAlphaOffset = textureSetting->ComputeMIPAlphaOffset(mip);
|
|
||||||
const float fAlphaScale = ComputeAlphaCoverageScaleFactor(mip, fDesiredAlphaCoverage, fAlphaRef);
|
|
||||||
|
|
||||||
AZ::u8* pixelBuf = m_mips[mip]->m_pData;
|
|
||||||
const AZ::u32 pixelCount = GetPixelCount(mip);
|
|
||||||
|
|
||||||
for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes)
|
|
||||||
{
|
|
||||||
float r, g, b, a;
|
|
||||||
pixelOp->GetRGBA(pixelBuf, r, g, b, a);
|
|
||||||
a = AZ::GetMin(a * fAlphaScale + fAlphaOffset, 1.0f);
|
|
||||||
pixelOp->SetRGBA(pixelBuf, r, g, b, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float CImageObject::ComputeAlphaCoverageScaleFactor(AZ::u32 mip, float fDesiredCoverage, float fAlphaRef) const
|
|
||||||
{
|
|
||||||
float minAlphaRef = 0.0f;
|
|
||||||
float maxAlphaRef = 1.0f;
|
|
||||||
float midAlphaRef = 0.5f;
|
|
||||||
|
|
||||||
// Find best alpha test reference value using a binary search
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
const float currentCoverage = ComputeAlphaCoverage(mip, midAlphaRef);
|
|
||||||
|
|
||||||
if (currentCoverage > fDesiredCoverage)
|
|
||||||
{
|
|
||||||
minAlphaRef = midAlphaRef;
|
|
||||||
}
|
|
||||||
else if (currentCoverage < fDesiredCoverage)
|
|
||||||
{
|
|
||||||
maxAlphaRef = midAlphaRef;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
midAlphaRef = (minAlphaRef + maxAlphaRef) * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fAlphaRef / midAlphaRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
float CImageObject::ComputeAlphaCoverage(AZ::u32 mip, float fAlphaRef) const
|
|
||||||
{
|
|
||||||
//This function only works with uncompressed image
|
|
||||||
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "This image need to be uncompressed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 coverage = 0;
|
|
||||||
|
|
||||||
//create pixel operation function
|
|
||||||
IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat);
|
|
||||||
//get count of bytes per pixel
|
|
||||||
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
AZ::u8* pixelBuf = m_mips[mip]->m_pData;
|
|
||||||
const AZ::u32 pixelCount = GetPixelCount(mip);
|
|
||||||
|
|
||||||
for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes)
|
|
||||||
{
|
|
||||||
float r, g, b, a;
|
|
||||||
pixelOp->GetRGBA(pixelBuf, r, g, b, a);
|
|
||||||
coverage += a > fAlphaRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (float)coverage / (float)(pixelCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,314 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
const int COLORCHART_IMAGE_WIDTH = 78;
|
|
||||||
const int COLORCHART_IMAGE_HEIGHT = 66;
|
|
||||||
|
|
||||||
// color chart in cry engine is a special image data, with size 78x66, you may see in game screenshot which is defined by a rectangle
|
|
||||||
// area with a yellow-black dash line boarder
|
|
||||||
// Create color chart function is to read that block of image data and convert it to a color table then save it to another image
|
|
||||||
// with size 256x16.
|
|
||||||
|
|
||||||
class C3dLutColorChart
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
C3dLutColorChart() {}
|
|
||||||
~C3dLutColorChart() {};
|
|
||||||
|
|
||||||
//generate default color chart data
|
|
||||||
void GenerateDefault();
|
|
||||||
|
|
||||||
//generate color chart data from input image
|
|
||||||
bool GenerateFromInput(IImageObjectPtr image);
|
|
||||||
|
|
||||||
//ouput the color chart data to an image object
|
|
||||||
IImageObjectPtr GenerateChartImage();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//extract color chart data from specified location in an image
|
|
||||||
void ExtractFromImageAt(IImageObjectPtr pImg, AZ::u32 x, AZ::u32 y);
|
|
||||||
|
|
||||||
//find color chart location in an image
|
|
||||||
static bool FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY);
|
|
||||||
|
|
||||||
//if there is a color chart at specified location
|
|
||||||
static bool IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch);
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum EPrimaryShades
|
|
||||||
{
|
|
||||||
ePS_Red = 16,
|
|
||||||
ePS_Green = 16,
|
|
||||||
ePS_Blue = 16,
|
|
||||||
|
|
||||||
ePS_NumColors = ePS_Red * ePS_Green * ePS_Blue
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SColor
|
|
||||||
{
|
|
||||||
unsigned char r, g, b, _padding;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef AZStd::vector<SColor> ColorMapping;
|
|
||||||
|
|
||||||
ColorMapping m_mapping;
|
|
||||||
};
|
|
||||||
|
|
||||||
void C3dLutColorChart::GenerateDefault()
|
|
||||||
{
|
|
||||||
m_mapping.reserve(ePS_NumColors);
|
|
||||||
|
|
||||||
for (int b = 0; b < ePS_Blue; ++b)
|
|
||||||
{
|
|
||||||
for (int g = 0; g < ePS_Green; ++g)
|
|
||||||
{
|
|
||||||
for (int r = 0; r < ePS_Red; ++r)
|
|
||||||
{
|
|
||||||
SColor col;
|
|
||||||
col.r = 255 * r / (ePS_Red);
|
|
||||||
col.g = 255 * g / (ePS_Green);
|
|
||||||
col.b = 255 * b / (ePS_Blue);
|
|
||||||
int l = 255 - (col.r * 3 + col.g * 6 + col.b) / 10;
|
|
||||||
col.r = col.g = col.b = (unsigned char)l;
|
|
||||||
m_mapping.push_back(col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//find color chart location in a image
|
|
||||||
bool C3dLutColorChart::FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY)
|
|
||||||
{
|
|
||||||
const AZ::u32 width = pImg->GetWidth(0);
|
|
||||||
const AZ::u32 height = pImg->GetHeight(0);
|
|
||||||
|
|
||||||
//the origin image is too small to have a color chart
|
|
||||||
if (width < COLORCHART_IMAGE_WIDTH || height < COLORCHART_IMAGE_HEIGHT)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::u8* pData;
|
|
||||||
AZ::u32 pitch;
|
|
||||||
pImg->GetImagePointer(0, pData, pitch);
|
|
||||||
|
|
||||||
//check all the posible start location on whether there might be a color chart
|
|
||||||
for (AZ::u32 y = 0; y <= height - COLORCHART_IMAGE_HEIGHT; ++y)
|
|
||||||
{
|
|
||||||
for (AZ::u32 x = 0; x <= width - COLORCHART_IMAGE_WIDTH; ++x)
|
|
||||||
{
|
|
||||||
if (IsColorChartAt(x, y, pData, pitch))
|
|
||||||
{
|
|
||||||
outLocX = x;
|
|
||||||
outLocY = y;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool C3dLutColorChart::GenerateFromInput(IImageObjectPtr image)
|
|
||||||
{
|
|
||||||
AZ::u32 outLocX, outLocY;
|
|
||||||
if (FindColorChart(image, outLocX, outLocY))
|
|
||||||
{
|
|
||||||
ExtractFromImageAt(image, outLocX, outLocY);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr C3dLutColorChart::GenerateChartImage()
|
|
||||||
{
|
|
||||||
const AZ::u32 mipCount = 1;
|
|
||||||
IImageObjectPtr image( IImageObject::CreateImage(ePS_Red * ePS_Blue, ePS_Green, 1, ePixelFormat_R8G8B8A8));
|
|
||||||
|
|
||||||
{
|
|
||||||
AZ::u8* pData;
|
|
||||||
AZ::u32 pitch;
|
|
||||||
image->GetImagePointer(0, pData, pitch);
|
|
||||||
|
|
||||||
size_t nSlicePitch = (pitch / ePS_Blue);
|
|
||||||
AZ::u32 src = 0;
|
|
||||||
for (int b = 0; b < ePS_Blue; ++b)
|
|
||||||
{
|
|
||||||
for (int g = 0; g < ePS_Green; ++g)
|
|
||||||
{
|
|
||||||
|
|
||||||
AZ::u8* p = pData + g * pitch + b * nSlicePitch;
|
|
||||||
for (int r = 0; r < ePS_Red; ++r)
|
|
||||||
{
|
|
||||||
const SColor& c = m_mapping[src];
|
|
||||||
p[0] = c.r;
|
|
||||||
p[1] = c.g;
|
|
||||||
p[2] = c.b;
|
|
||||||
p[3] = 255;
|
|
||||||
++src;
|
|
||||||
p += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C3dLutColorChart::ExtractFromImageAt(IImageObjectPtr image, AZ::u32 x, AZ::u32 y)
|
|
||||||
{
|
|
||||||
int ox = x + 1;
|
|
||||||
int oy = y + 1;
|
|
||||||
|
|
||||||
AZ::u8* pData;
|
|
||||||
AZ::u32 pitch;
|
|
||||||
image->GetImagePointer(0, pData, pitch);
|
|
||||||
|
|
||||||
m_mapping.reserve(ePS_NumColors);
|
|
||||||
|
|
||||||
for (int b = 0; b < ePS_Blue; ++b)
|
|
||||||
{
|
|
||||||
int px = ox + ePS_Red * (b % 4);
|
|
||||||
int py = oy + ePS_Green * (b / 4);
|
|
||||||
|
|
||||||
for (int g = 0; g < ePS_Green; ++g)
|
|
||||||
{
|
|
||||||
for (int r = 0; r < ePS_Red; ++r)
|
|
||||||
{
|
|
||||||
AZ::u8* p = pData + pitch * (py + g) + (px + r) * 4;
|
|
||||||
|
|
||||||
SColor col;
|
|
||||||
col.r = p[0];
|
|
||||||
col.g = p[1];
|
|
||||||
col.b = p[2];
|
|
||||||
m_mapping.push_back(col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//check if image data at location x and y could be a color chart
|
|
||||||
//based on if the boarder is dash lines with two pixel each segement
|
|
||||||
//the idea and implementation are both coming from CryEngine.
|
|
||||||
bool C3dLutColorChart::IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch)
|
|
||||||
{
|
|
||||||
struct Color
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int c[3];
|
|
||||||
|
|
||||||
public:
|
|
||||||
Color(AZ::u32 x, AZ::u32 y, void* pPixels, AZ::u32 pitch)
|
|
||||||
{
|
|
||||||
const uint8* p = (const uint8*)pPixels + pitch * y + x * 4;
|
|
||||||
c[0] = p[0];
|
|
||||||
c[1] = p[1];
|
|
||||||
c[2] = p[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSimilar(const Color& a, int maxDiff) const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
abs(a.c[0] - c[0]) <= maxDiff &&
|
|
||||||
abs(a.c[1] - c[1]) <= maxDiff &&
|
|
||||||
abs(a.c[2] - c[2]) <= maxDiff;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Color colorRef[2] =
|
|
||||||
{
|
|
||||||
Color(x, y, pData, pitch),
|
|
||||||
Color(x + 2, y, pData, pitch)
|
|
||||||
};
|
|
||||||
|
|
||||||
// We require two colors of the border to be at least a bit different
|
|
||||||
if (colorRef[0].isSimilar(colorRef[1], 15))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int kMaxDiff = 3;
|
|
||||||
|
|
||||||
int refIdx = 0;
|
|
||||||
//rectangle's top
|
|
||||||
for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2)
|
|
||||||
{
|
|
||||||
if (!colorRef[refIdx].isSimilar(Color(x + i, y, pData, pitch), kMaxDiff) ||
|
|
||||||
!colorRef[refIdx].isSimilar(Color(x + i + 1, y, pData, pitch), kMaxDiff))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
refIdx ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
refIdx = 0;
|
|
||||||
//left
|
|
||||||
for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2)
|
|
||||||
{
|
|
||||||
if (!colorRef[refIdx].isSimilar(Color(x, y + i, pData, pitch), kMaxDiff) ||
|
|
||||||
!colorRef[refIdx].isSimilar(Color(x, y + i + 1, pData, pitch), kMaxDiff))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
refIdx ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
refIdx = 0;
|
|
||||||
//right
|
|
||||||
for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2)
|
|
||||||
{
|
|
||||||
if (!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i, pData, pitch), kMaxDiff) ||
|
|
||||||
!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i + 1, pData, pitch), kMaxDiff))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
refIdx ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
refIdx = 0;
|
|
||||||
//bottom
|
|
||||||
for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2)
|
|
||||||
{
|
|
||||||
if (!colorRef[refIdx].isSimilar(Color(x + i, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff) ||
|
|
||||||
!colorRef[refIdx].isSimilar(Color(x + i + 1, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
refIdx ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ImageToProcess::CreateColorChart()
|
|
||||||
{
|
|
||||||
C3dLutColorChart colorChart;
|
|
||||||
|
|
||||||
//get color chart data from source image.
|
|
||||||
if (!colorChart.GenerateFromInput(m_img))
|
|
||||||
{
|
|
||||||
//if load from image failed then generate default color data
|
|
||||||
colorChart.GenerateDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
//save color chart data to an image and save as current
|
|
||||||
m_img = colorChart.GenerateChartImage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
|
|
||||||
#include <Compressors/Compressor.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//functions for maintaining alpha coverage.
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
void ImageToProcess::ConvertFormat(EPixelFormat fmtDst)
|
|
||||||
{
|
|
||||||
//pixel format before convertion
|
|
||||||
EPixelFormat fmtSrc = Get()->GetPixelFormat();
|
|
||||||
|
|
||||||
//return directly if the image already has the desired pixel format
|
|
||||||
if (fmtDst == fmtSrc)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 dwWidth, dwHeight, dwMips;
|
|
||||||
dwWidth = Get()->GetWidth(0);
|
|
||||||
dwHeight = Get()->GetHeight(0);
|
|
||||||
dwMips = Get()->GetMipCount();
|
|
||||||
|
|
||||||
//if the output image size doesn't work the desired pixel format. set to fallback format
|
|
||||||
const PixelFormatInfo* dstFmtInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtDst);
|
|
||||||
if (!CPixelFormats::GetInstance().IsImageSizeValid(fmtDst, dwWidth, dwHeight, true))
|
|
||||||
{
|
|
||||||
AZ_Warning("Image Processing", false, "Output pixel format %d doesn't work with output image size %d x %d",
|
|
||||||
fmtDst, dwWidth, dwHeight);
|
|
||||||
|
|
||||||
//fall back to safe texture format
|
|
||||||
if (dstFmtInfo->nChannels == 1)
|
|
||||||
{
|
|
||||||
fmtDst = dstFmtInfo->bHasAlpha ? ePixelFormat_A8 : ePixelFormat_R8;
|
|
||||||
}
|
|
||||||
else if (dstFmtInfo->nChannels == 2)
|
|
||||||
{
|
|
||||||
fmtDst = ePixelFormat_R8G8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fmtDst = dstFmtInfo->bHasAlpha ? ePixelFormat_R8G8B8A8 : ePixelFormat_R8G8B8X8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//convert src image to uncompressed formats if it's compressed format
|
|
||||||
bool isSrcUncompressed = CPixelFormats::GetInstance().IsPixelFormatUncompressed(fmtSrc);
|
|
||||||
bool isDstUncompressed = CPixelFormats::GetInstance().IsPixelFormatUncompressed(fmtDst);
|
|
||||||
|
|
||||||
if (isSrcUncompressed && isDstUncompressed)
|
|
||||||
{//both are uncompressed
|
|
||||||
ConvertFormatUncompressed(fmtDst);
|
|
||||||
}
|
|
||||||
else if (!isSrcUncompressed && !isDstUncompressed)
|
|
||||||
{ //both are compressed
|
|
||||||
AZ_Assert(false, "unusual user case. but we can still handle it");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //one fmt is compressed format
|
|
||||||
//use the compressed format to find right compressor
|
|
||||||
EPixelFormat compressedFmt = isSrcUncompressed ? fmtDst : fmtSrc;
|
|
||||||
EPixelFormat uncompressedFmt = isSrcUncompressed ? fmtSrc : fmtDst;
|
|
||||||
ICompressorPtr compressor = ICompressor::FindCompressor(compressedFmt, isSrcUncompressed);
|
|
||||||
|
|
||||||
if (compressor == nullptr)
|
|
||||||
{
|
|
||||||
//no avaible compressor for compressed format
|
|
||||||
AZ_Warning("Image Processing", false, "No avaliable compressor for pixel format %d", compressedFmt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check if the uncompressed fmt also supported by the compressor
|
|
||||||
EPixelFormat desiredUncompressedFmt = compressor->GetSuggestedUncompressedFormat(compressedFmt, uncompressedFmt);
|
|
||||||
if (desiredUncompressedFmt != uncompressedFmt)
|
|
||||||
{
|
|
||||||
//we need to do intermedia convertion to convert to the temperory format
|
|
||||||
ConvertFormat(desiredUncompressedFmt);
|
|
||||||
ConvertFormat(fmtDst);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IImageObjectPtr dstImage = nullptr;
|
|
||||||
if (isSrcUncompressed)
|
|
||||||
{
|
|
||||||
dstImage = compressor->CompressImage(Get(), fmtDst, &m_compressOption);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstImage = compressor->DecompressImage(Get(), fmtDst);
|
|
||||||
}
|
|
||||||
|
|
||||||
Set(dstImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Get() == nullptr)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "The selected compressor failed to compress this image");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageToProcess::ConvertFormatUncompressed(EPixelFormat fmtTo)
|
|
||||||
{
|
|
||||||
IImageObjectPtr srcImage = m_img;
|
|
||||||
EPixelFormat srcFmt = srcImage->GetPixelFormat();
|
|
||||||
EPixelFormat dstFmt = fmtTo;
|
|
||||||
|
|
||||||
if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcFmt)
|
|
||||||
&& CPixelFormats::GetInstance().IsPixelFormatUncompressed(dstFmt)))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "both source and dest images' pixel format need to be uncompressed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(m_img->AllocateImage(fmtTo));
|
|
||||||
|
|
||||||
AZ_Assert(srcImage->GetPixelCount(0) == dstImage->GetPixelCount(0), "dest image has different size than source image");
|
|
||||||
|
|
||||||
//create pixel operation function for src and dst images
|
|
||||||
IPixelOperationPtr srcOp = CreatePixelOperation(srcFmt);
|
|
||||||
IPixelOperationPtr dstOp = CreatePixelOperation(dstFmt);
|
|
||||||
|
|
||||||
//get count of bytes per pixel for both src and dst images
|
|
||||||
uint32 srcPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(srcFmt)->bitsPerBlock / 8;
|
|
||||||
uint32 dstPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
const uint32 dwMips = dstImage->GetMipCount();
|
|
||||||
float r, g, b, a;
|
|
||||||
for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
|
|
||||||
{
|
|
||||||
uint8* srcPixelBuf;
|
|
||||||
uint32 srcPitch;
|
|
||||||
srcImage->GetImagePointer(dwMip, srcPixelBuf, srcPitch);
|
|
||||||
uint8* dstPixelBuf;
|
|
||||||
uint32 dstPitch;
|
|
||||||
dstImage->GetImagePointer(dwMip, dstPixelBuf, dstPitch);
|
|
||||||
|
|
||||||
const uint32 pixelCount = srcImage->GetPixelCount(dwMip);
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, srcPixelBuf += srcPixelBytes, dstPixelBuf += dstPixelBytes)
|
|
||||||
{
|
|
||||||
srcOp->GetRGBA(srcPixelBuf, r, g, b, a);
|
|
||||||
dstOp->SetRGBA(dstPixelBuf, r, g, b, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_img = dstImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,620 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <Processing/ImageConvert.h>
|
|
||||||
#include <Processing/ImageFlags.h>
|
|
||||||
|
|
||||||
#include <Compressors/Compressor.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
|
|
||||||
#include <Converters/Cubemap.h>
|
|
||||||
#include <CubeMapGen/CCubeMapProcessor.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
CubemapLayoutInfo CubemapLayout::s_layoutList[CubemapLayoutTypeCount];
|
|
||||||
|
|
||||||
template <class TInteger>
|
|
||||||
inline bool IsPowerOfTwo(TInteger x)
|
|
||||||
{
|
|
||||||
return (x & (x - 1)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayoutInfo::CubemapLayoutInfo()
|
|
||||||
: m_type(CubemapLayoutNone)
|
|
||||||
, m_rows(0)
|
|
||||||
, m_columns(0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapLayoutInfo::SetFaceInfo(CubemapFace face, AZ::u8 row, AZ::u8 col, CubemapFaceDirection dir)
|
|
||||||
{
|
|
||||||
m_faceInfos[face].row = row;
|
|
||||||
m_faceInfos[face].column = col;
|
|
||||||
m_faceInfos[face].direction = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapLayout::InitCubemapLayoutInfos()
|
|
||||||
{
|
|
||||||
//CubemapLayoutHorizontal
|
|
||||||
//left , right, front, back, top, bottom;
|
|
||||||
//NOTE: this layout is widely used in game projects by Jan 2018 since other layouts weren't supported correctly
|
|
||||||
//but the faces in one has unusual directions compare to other format.
|
|
||||||
//The direction matters when using it as input for Cubemap generation filter.
|
|
||||||
//Left: rotated left 90 degree. Right: rotated right 90 degree
|
|
||||||
//Front: rotated 180 degree. Back: no rotation
|
|
||||||
//Top: rotate 180 degree. Bottom: no rotation
|
|
||||||
CubemapLayoutInfo *info = &s_layoutList[CubemapLayoutHorizontal];
|
|
||||||
info->m_rows = 1;
|
|
||||||
info->m_columns = 6;
|
|
||||||
info->m_type = CubemapLayoutHorizontal;
|
|
||||||
info->SetFaceInfo(FaceLeft, 0, 0, CubemapFaceDirection::DirRotateLeft90);
|
|
||||||
info->SetFaceInfo(FaceRight, 0, 1, CubemapFaceDirection::DirRotateRight90);
|
|
||||||
info->SetFaceInfo(FaceFront, 0, 2, CubemapFaceDirection::DirRotate180);
|
|
||||||
info->SetFaceInfo(FaceBack, 0, 3, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceTop, 0, 4, CubemapFaceDirection::DirRotate180);
|
|
||||||
info->SetFaceInfo(FaceBottom, 0, 5, CubemapFaceDirection::DirNoRotation);
|
|
||||||
|
|
||||||
//CubemapLayoutHorizontalCross
|
|
||||||
// top
|
|
||||||
// left front right back
|
|
||||||
// bottom
|
|
||||||
info = &s_layoutList[CubemapLayoutHorizontalCross];
|
|
||||||
info->m_rows = 3;
|
|
||||||
info->m_columns = 4;
|
|
||||||
info->m_type = CubemapLayoutHorizontalCross;
|
|
||||||
info->SetFaceInfo(FaceLeft, 1, 0, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceRight, 1, 2, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceFront, 1, 1, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceBack, 1, 3, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceTop, 0, 1, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceBottom, 2, 1, CubemapFaceDirection::DirNoRotation);
|
|
||||||
|
|
||||||
//CubemapLayoutVerticalCross
|
|
||||||
// top
|
|
||||||
// left front right
|
|
||||||
// bottom
|
|
||||||
// back
|
|
||||||
info = &s_layoutList[CubemapLayoutVerticalCross];
|
|
||||||
info->m_rows = 4;
|
|
||||||
info->m_columns = 3;
|
|
||||||
info->m_type = CubemapLayoutVerticalCross;
|
|
||||||
info->SetFaceInfo(FaceLeft, 1, 0, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceRight, 1, 2, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceFront, 1, 1, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceBack, 3, 1, CubemapFaceDirection::DirRotate180);
|
|
||||||
info->SetFaceInfo(FaceTop, 0, 1, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceBottom, 2, 1, CubemapFaceDirection::DirNoRotation);
|
|
||||||
|
|
||||||
//CubemapLayoutVertical
|
|
||||||
// left
|
|
||||||
// right
|
|
||||||
// front
|
|
||||||
// back
|
|
||||||
// top
|
|
||||||
// bottom
|
|
||||||
info = &s_layoutList[CubemapLayoutVertical];
|
|
||||||
info->m_rows = 6;
|
|
||||||
info->m_columns = 1;
|
|
||||||
info->m_type = CubemapLayoutVertical;
|
|
||||||
info->SetFaceInfo(FaceLeft, 0, 0, CubemapFaceDirection::DirRotateLeft90);
|
|
||||||
info->SetFaceInfo(FaceRight, 1, 0, CubemapFaceDirection::DirRotateRight90);
|
|
||||||
info->SetFaceInfo(FaceFront, 2, 0, CubemapFaceDirection::DirRotate180);
|
|
||||||
info->SetFaceInfo(FaceBack, 3, 0, CubemapFaceDirection::DirNoRotation);
|
|
||||||
info->SetFaceInfo(FaceTop, 4, 0, CubemapFaceDirection::DirRotate180);
|
|
||||||
info->SetFaceInfo(FaceBottom, 5, 0, CubemapFaceDirection::DirNoRotation);
|
|
||||||
|
|
||||||
//make sure all types were initialized
|
|
||||||
for (int i = 0; i < CubemapLayoutTypeCount; i++)
|
|
||||||
{
|
|
||||||
AZ_Assert(s_layoutList[i].m_type == i, "layout %d is not initialized", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const float* GetTransformMatrix(CubemapFaceDirection dir, bool isInvert)
|
|
||||||
{
|
|
||||||
switch (dir)
|
|
||||||
{
|
|
||||||
case CubemapFaceDirection::DirNoRotation:
|
|
||||||
{
|
|
||||||
static const float mat[] = { 1, 0, 0, 1 };
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
case CubemapFaceDirection::DirRotateLeft90:
|
|
||||||
{
|
|
||||||
//thelta = 90 degree
|
|
||||||
//{cos, -sin, sin, cos}
|
|
||||||
if (isInvert)
|
|
||||||
{
|
|
||||||
return GetTransformMatrix(CubemapFaceDirection::DirRotateRight90, false);
|
|
||||||
}
|
|
||||||
static const float mat[] = { 0, -1, 1, 0 };
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
case CubemapFaceDirection::DirRotateRight90:
|
|
||||||
{
|
|
||||||
//thelta = -90 degree
|
|
||||||
if (isInvert)
|
|
||||||
{
|
|
||||||
return GetTransformMatrix(CubemapFaceDirection::DirRotateLeft90, false);
|
|
||||||
}
|
|
||||||
static const float mat[] = { 0, 1, -1, 0 };
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
case CubemapFaceDirection::DirRotate180:
|
|
||||||
{
|
|
||||||
//thelta = 180 degree
|
|
||||||
static const float mat[] = { -1, 0, 0, -1 };
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
case CubemapFaceDirection::DirMirrorHorizontal:
|
|
||||||
{
|
|
||||||
static const float mat[] = { 1, 0, 0, -1 };
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "unimplemented direction matrix");
|
|
||||||
static const float mat[] = { 1, 0, 0, 1 };
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TransformImage(CubemapFaceDirection srcDir, CubemapFaceDirection dstDir, const AZ::u8* srcImageBuf,
|
|
||||||
AZ::u8* dstImageBuf, AZ::u8 bytePerPixel, AZ::u32 rectSize)
|
|
||||||
{
|
|
||||||
//get final matrix to transform dst back to src
|
|
||||||
const float* m1 = GetTransformMatrix(dstDir, true);
|
|
||||||
const float* m2 = GetTransformMatrix(srcDir, false);
|
|
||||||
float mtx[4];
|
|
||||||
mtx[0] = m1[0] * m2[0] + m1[1] * m2[2];
|
|
||||||
mtx[1] = m1[0] * m2[1] + m1[1] * m2[3];
|
|
||||||
mtx[2] = m1[2] * m2[0] + m1[3] * m2[2];
|
|
||||||
mtx[3] = m1[2] * m2[1] + m1[3] * m2[3];
|
|
||||||
|
|
||||||
const float* noRotate = GetTransformMatrix(CubemapFaceDirection::DirNoRotation, false);
|
|
||||||
|
|
||||||
if (memcmp(noRotate, mtx, 4 * sizeof(float)) == 0)
|
|
||||||
{
|
|
||||||
memcpy(dstImageBuf, srcImageBuf, rectSize*rectSize*bytePerPixel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//for each pixel in dst image, find it's location in src and copy the data from there
|
|
||||||
float halfSize = rectSize / 2;
|
|
||||||
for (AZ::u32 row = 0; row < rectSize; row++)
|
|
||||||
{
|
|
||||||
for (AZ::u32 col = 0; col < rectSize; col++)
|
|
||||||
{
|
|
||||||
//coordinate in image center as origin and right as positive X, up as positive Y
|
|
||||||
float dstX = col + 0.5f - halfSize;
|
|
||||||
float dstY = halfSize - row - 0.5f;
|
|
||||||
float srcX = dstX * mtx[0] + dstY * mtx[1];
|
|
||||||
float srcY = dstX * mtx[2] + dstY * mtx[3];
|
|
||||||
AZ::u32 srcCol = srcX + halfSize;
|
|
||||||
AZ::u32 srcRow = halfSize - srcY;
|
|
||||||
|
|
||||||
memcpy(&dstImageBuf[(row*rectSize + col)*bytePerPixel],
|
|
||||||
&srcImageBuf[(srcRow*rectSize + srcCol)*bytePerPixel], bytePerPixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayout::CubemapLayout()
|
|
||||||
: m_info(nullptr)
|
|
||||||
, m_image(nullptr)
|
|
||||||
, m_faceSize(256)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayout* CubemapLayout::CreateCubemapLayout(IImageObjectPtr image)
|
|
||||||
{
|
|
||||||
//only support uncompressed format.
|
|
||||||
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(image->GetPixelFormat()))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "CubemapLayout only support uncompressed image");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayout* layout = nullptr;
|
|
||||||
CubemapLayoutInfo* info = GetCubemapLayoutInfo(image);
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
layout = new CubemapLayout();
|
|
||||||
layout->m_info = GetCubemapLayoutInfo(image);
|
|
||||||
layout->m_image = image;
|
|
||||||
layout->m_faceSize = image->GetWidth(0)/layout->m_info->m_columns;
|
|
||||||
}
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CubemapLayoutInfo* CubemapLayout::GetCubemapLayoutInfo(CubemapLayoutType type)
|
|
||||||
{
|
|
||||||
if (type == CubemapLayoutNone)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if it's never initialized
|
|
||||||
if (s_layoutList[0].m_type == CubemapLayoutNone)
|
|
||||||
{
|
|
||||||
InitCubemapLayoutInfos();
|
|
||||||
}
|
|
||||||
|
|
||||||
return &s_layoutList[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayoutInfo* CubemapLayout::GetCubemapLayoutInfo(IImageObjectPtr image)
|
|
||||||
{
|
|
||||||
//if it's never initialized
|
|
||||||
if (s_layoutList[0].m_type == CubemapLayoutNone)
|
|
||||||
{
|
|
||||||
InitCubemapLayoutInfos();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image == nullptr)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 width, height;
|
|
||||||
width = image->GetWidth(0);
|
|
||||||
height = image->GetHeight(0);
|
|
||||||
CubemapLayoutInfo* info = nullptr;
|
|
||||||
|
|
||||||
for (int i = 0; i < CubemapLayoutTypeCount; i++)
|
|
||||||
{
|
|
||||||
if (width * s_layoutList[i].m_rows == height*s_layoutList[i].m_columns)
|
|
||||||
{
|
|
||||||
info = &s_layoutList[i];
|
|
||||||
|
|
||||||
//we require the face size need to be power of two
|
|
||||||
if (IsPowerOfTwo(width / info->m_columns))
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//public functions to get faces information for associated image
|
|
||||||
AZ::u32 CubemapLayout::GetFaceSize()
|
|
||||||
{
|
|
||||||
return m_faceSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayoutInfo* CubemapLayout::GetLayoutInfo()
|
|
||||||
{
|
|
||||||
return m_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapFaceDirection CubemapLayout::GetFaceDirection(CubemapFace face)
|
|
||||||
{
|
|
||||||
return m_info->m_faceInfos[face].direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapLayout::GetFaceData(CubemapFace face, void* outBuffer, AZ::u32& outSize)
|
|
||||||
{
|
|
||||||
//only valid for uncompressed
|
|
||||||
AZ::u32 sizePerPixel = CPixelFormats::GetInstance().GetPixelFormatInfo(m_image->GetPixelFormat())->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
AZ::u8* imageBuf;
|
|
||||||
AZ::u32 dwPitch;
|
|
||||||
m_image->GetImagePointer(0, imageBuf, dwPitch);
|
|
||||||
AZ::u8* dstBuf = (AZ::u8*)outBuffer;
|
|
||||||
|
|
||||||
AZ::u32 startX = m_info->m_faceInfos[face].column * m_faceSize;
|
|
||||||
AZ::u32 startY = m_info->m_faceInfos[face].row * m_faceSize;
|
|
||||||
|
|
||||||
//face size is same as rows for uncompressed format
|
|
||||||
for (AZ::u32 y = 0; y < m_faceSize; y++)
|
|
||||||
{
|
|
||||||
AZ::u32 scanlineSize = m_faceSize*sizePerPixel;
|
|
||||||
AZ::u8* srcBuf = &imageBuf[(startY + y) * dwPitch + startX*sizePerPixel];
|
|
||||||
memcpy(dstBuf, srcBuf, scanlineSize);
|
|
||||||
dstBuf += scanlineSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
outSize = m_faceSize*m_faceSize*sizePerPixel;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapLayout::SetFaceData(CubemapFace face, void* dataBuffer, [[maybe_unused]] AZ::u32 dataSize)
|
|
||||||
{
|
|
||||||
//only valid for uncompressed
|
|
||||||
AZ::u32 sizePerPixel = CPixelFormats::GetInstance().GetPixelFormatInfo(m_image->GetPixelFormat())->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
AZ::u8* imageBuf;
|
|
||||||
AZ::u32 dwPitch;
|
|
||||||
m_image->GetImagePointer(0, imageBuf, dwPitch);
|
|
||||||
AZ::u8* srcBuf = (AZ::u8*)dataBuffer;
|
|
||||||
|
|
||||||
AZ::u32 startX = m_info->m_faceInfos[face].column * m_faceSize;
|
|
||||||
AZ::u32 startY = m_info->m_faceInfos[face].row * m_faceSize;
|
|
||||||
|
|
||||||
//face size is same as rows for uncompressed format
|
|
||||||
for (AZ::u32 y = 0; y < m_faceSize; y++)
|
|
||||||
{
|
|
||||||
AZ::u32 scanlineSize = m_faceSize*sizePerPixel;
|
|
||||||
AZ::u8* dstBuf = &imageBuf[(startY + y) * dwPitch + startX*sizePerPixel];
|
|
||||||
memcpy(dstBuf, srcBuf, scanlineSize);
|
|
||||||
srcBuf += scanlineSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* CubemapLayout::GetFaceMemBuffer(AZ::u32 mip, CubemapFace face, AZ::u32& outPitch)
|
|
||||||
{
|
|
||||||
if (CubemapLayoutVertical != m_info->m_type)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "this should only be used for CubemapLayoutVertical which has continous memory for each face");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::u32 faceSize = m_faceSize >> mip;
|
|
||||||
AZ::u8* imageBuf;
|
|
||||||
m_image->GetImagePointer(mip, imageBuf, outPitch);
|
|
||||||
AZ::u32 startY = m_info->m_faceInfos[face].row * faceSize;
|
|
||||||
|
|
||||||
//use startY is same as rows from m_image since the pixel format is uncompressed
|
|
||||||
return &imageBuf[startY * outPitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapLayout::SetToFaceMemBuffer(AZ::u32 mip, CubemapFace face, void* dataBuffer)
|
|
||||||
{
|
|
||||||
if (CubemapLayoutVertical != m_info->m_type)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "this should only be used for CubemapLayoutVertical which has continuous memory for each face");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::u32 faceSize = m_faceSize >> mip;
|
|
||||||
AZ::u32 pitch;
|
|
||||||
AZ::u8* imageBuf;
|
|
||||||
m_image->GetImagePointer(mip, imageBuf, pitch);
|
|
||||||
AZ::u32 startY = m_info->m_faceInfos[face].row * faceSize;
|
|
||||||
|
|
||||||
//use startY is same as rows from m_image since the pixel format is uncompressed
|
|
||||||
memcpy(&imageBuf[startY * pitch], dataBuffer, faceSize*pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubemapLayout::GetRectForFace(AZ::u32 mip, CubemapFace face, QRect& outRect)
|
|
||||||
{
|
|
||||||
AZ::u32 faceSize = m_faceSize >> mip;
|
|
||||||
AZ::u32 startY = m_info->m_faceInfos[face].row * faceSize;
|
|
||||||
AZ::u32 startX = m_info->m_faceInfos[face].column * faceSize;
|
|
||||||
|
|
||||||
outRect.setRect(startX, startY, faceSize, faceSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImageToProcess::ConvertCubemapLayout(CubemapLayoutType dstLayoutType)
|
|
||||||
{
|
|
||||||
const EPixelFormat srcPixelFormat = m_img->GetPixelFormat();
|
|
||||||
|
|
||||||
//it need to be uncompressed format
|
|
||||||
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcPixelFormat))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "Please convert the image to uncompressed pixel format before calling ConvertCubemapLayout");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check if it's valid cubemap size
|
|
||||||
CubemapLayoutInfo* layoutInfo = CubemapLayout::GetCubemapLayoutInfo(m_img);
|
|
||||||
if (layoutInfo == nullptr)
|
|
||||||
{
|
|
||||||
AZ_Error("Image Processing", false, "The original image doesn't have a valid size (layout) as cubemap");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if the source is same as output layout, return directly
|
|
||||||
if (layoutInfo->m_type == dstLayoutType)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayoutInfo* dstLayoutInfo = CubemapLayout::GetCubemapLayoutInfo(dstLayoutType);
|
|
||||||
|
|
||||||
//create cubemap layout for source image for later operation.
|
|
||||||
CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_img);
|
|
||||||
AZ::u32 faceSize = srcCubemap->GetFaceSize();
|
|
||||||
|
|
||||||
//create new image with same pixel format and copy prperties from source image
|
|
||||||
IImageObjectPtr newImage(IImageObject::CreateImage(faceSize * dstLayoutInfo->m_columns,
|
|
||||||
faceSize*dstLayoutInfo->m_rows, 1, srcPixelFormat));
|
|
||||||
CubemapLayout *dstCubemap = CubemapLayout::CreateCubemapLayout(newImage);
|
|
||||||
newImage->CopyPropertiesFrom(newImage);
|
|
||||||
|
|
||||||
//copy data from src cube to dst cube for each face
|
|
||||||
//temp buf for copy over data
|
|
||||||
AZ::u32 sizePerPixel = CPixelFormats::GetInstance().GetPixelFormatInfo(srcPixelFormat)->bitsPerBlock/8; //only valid for uncompressed
|
|
||||||
AZ::u8 *buf = new AZ::u8[faceSize*faceSize*sizePerPixel];
|
|
||||||
AZ::u8 *tempBuf = new AZ::u8[faceSize*faceSize*sizePerPixel];
|
|
||||||
|
|
||||||
for (AZ::u32 faceIdx = 0; faceIdx < FaceCount; faceIdx++)
|
|
||||||
{
|
|
||||||
AZ::u32 outSize = 0;
|
|
||||||
CubemapFace face = (CubemapFace)faceIdx;
|
|
||||||
srcCubemap->GetFaceData(face, buf, outSize);
|
|
||||||
CubemapFaceDirection srcDir = srcCubemap->GetFaceDirection(face);
|
|
||||||
CubemapFaceDirection dstDir = dstCubemap->GetFaceDirection(face);
|
|
||||||
if (srcDir == dstDir)
|
|
||||||
{
|
|
||||||
dstCubemap->SetFaceData(face, buf, outSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//transform the image
|
|
||||||
TransformImage(srcDir, dstDir, buf, tempBuf, sizePerPixel, faceSize);
|
|
||||||
dstCubemap->SetFaceData(face, tempBuf, outSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//clean up
|
|
||||||
delete[] buf;
|
|
||||||
delete[] tempBuf;
|
|
||||||
delete srcCubemap;
|
|
||||||
delete dstCubemap;
|
|
||||||
|
|
||||||
newImage->AddImageFlags(EIF_Cubemap);
|
|
||||||
m_img = newImage;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImageConvertProcess::FillCubemapMipmaps()
|
|
||||||
{
|
|
||||||
//this function only works with pixel format rgba32f
|
|
||||||
const EPixelFormat srcPixelFormat = m_image->Get()->GetPixelFormat();
|
|
||||||
if (srcPixelFormat != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s only works with pixel format rgba32f", __FUNCTION__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//only if the src image has one mip
|
|
||||||
if (m_image->Get()->GetMipCount() != 1)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s called for a mipmapped image. ", __FUNCTION__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_image->Get());
|
|
||||||
|
|
||||||
uint32 outWidth;
|
|
||||||
uint32 outHeight;
|
|
||||||
uint32 outReduce = 0;
|
|
||||||
AZ::u32 srcFaceSize = srcCubemap->GetFaceSize();
|
|
||||||
//get output face size
|
|
||||||
GetOutputExtent(srcFaceSize, srcFaceSize, outWidth, outHeight, outReduce, &m_textureSetting, &m_presetSetting);
|
|
||||||
AZ_Assert(outWidth == outHeight, "something wrong with GetOutputExtent function");
|
|
||||||
|
|
||||||
//get final cubemap image size
|
|
||||||
outWidth *= srcCubemap->GetLayoutInfo()->m_columns;
|
|
||||||
outHeight *= srcCubemap->GetLayoutInfo()->m_rows;
|
|
||||||
|
|
||||||
//max mipmap count
|
|
||||||
uint32 maxMipCount;
|
|
||||||
if (m_presetSetting.m_mipmapSetting == nullptr || !m_textureSetting.m_enableMipmap)
|
|
||||||
{
|
|
||||||
maxMipCount = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//calculate based on face size, and use final export format which may save some low level mip calculation
|
|
||||||
maxMipCount = CPixelFormats::GetInstance().ComputeMaxMipCount(m_presetSetting.m_pixelFormat, srcFaceSize, srcFaceSize);
|
|
||||||
|
|
||||||
//the FilterImage function won't do well with rect size 1. avoiding cubemap with face size 1
|
|
||||||
if (srcFaceSize >> maxMipCount == 1 && maxMipCount > 1)
|
|
||||||
{
|
|
||||||
maxMipCount -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//create new new output image with proper face
|
|
||||||
IImageObjectPtr outImage(IImageObject::CreateImage(outWidth, outHeight, maxMipCount, srcPixelFormat));
|
|
||||||
outImage->CopyPropertiesFrom(m_image->Get());
|
|
||||||
CubemapLayout *dstCubemap = CubemapLayout::CreateCubemapLayout(outImage);
|
|
||||||
AZ::u32 outFaceSize = dstCubemap->GetFaceSize();
|
|
||||||
AZ::u32 dstMipCount = outImage->GetMipCount();
|
|
||||||
|
|
||||||
//filter the image for top mip first
|
|
||||||
for (int iSide = 0; iSide < 6; ++iSide)
|
|
||||||
{
|
|
||||||
QRect srcRect;
|
|
||||||
QRect dstRect;
|
|
||||||
|
|
||||||
srcRect.setLeft(0);
|
|
||||||
srcRect.setRight(srcFaceSize);
|
|
||||||
srcRect.setTop(iSide * srcFaceSize);
|
|
||||||
srcRect.setBottom((iSide + 1) * srcFaceSize);
|
|
||||||
|
|
||||||
dstRect.setLeft(0);
|
|
||||||
dstRect.setRight(outFaceSize);
|
|
||||||
dstRect.setTop(iSide * outFaceSize);
|
|
||||||
dstRect.setBottom((iSide + 1) * outFaceSize);
|
|
||||||
|
|
||||||
FilterImage(m_textureSetting.m_mipGenType, m_textureSetting.m_mipGenEval, 0, 0, m_image->Get(), 0,
|
|
||||||
outImage, 0, &srcRect, &dstRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CCubeMapProcessor atiCubemanGen;
|
|
||||||
//ATI's cubemap generator to filter the image edges to avoid seam problem
|
|
||||||
// https://gpuopen.com/archive/gamescgi/cubemapgen/
|
|
||||||
|
|
||||||
//the thread support was done with windows thread function so it's removed for multi-dev platform support
|
|
||||||
atiCubemanGen.m_NumFilterThreads = 0;
|
|
||||||
|
|
||||||
// input and output cubemap set to have save dimensions,
|
|
||||||
atiCubemanGen.Init(outFaceSize, outFaceSize, dstMipCount, 4);
|
|
||||||
|
|
||||||
// Load the 6 faces of the input cubemap and copy them into the cubemap processor
|
|
||||||
void* pMem;
|
|
||||||
uint32 nPitch;
|
|
||||||
|
|
||||||
for (int iFace = 0; iFace < 6; ++iFace)
|
|
||||||
{
|
|
||||||
pMem = dstCubemap->GetFaceMemBuffer(0, (CubemapFace)iFace, nPitch);
|
|
||||||
atiCubemanGen.SetInputFaceData(
|
|
||||||
iFace, // FaceIdx,
|
|
||||||
CP_VAL_FLOAT32, // SrcType,
|
|
||||||
4, // SrcNumChannels,
|
|
||||||
nPitch, // SrcPitch,
|
|
||||||
pMem, // SrcDataPtr,
|
|
||||||
1000000.0f, // MaxClamp,
|
|
||||||
1.0f, // Degamma,
|
|
||||||
1.0f); // Scale
|
|
||||||
}
|
|
||||||
|
|
||||||
//Filter cubemap
|
|
||||||
atiCubemanGen.InitiateFiltering(
|
|
||||||
m_presetSetting.m_cubemapSetting->m_angle, //BaseFilterAngle,
|
|
||||||
m_presetSetting.m_cubemapSetting->m_mipAngle, //InitialMipAngle,
|
|
||||||
m_presetSetting.m_cubemapSetting->m_mipSlope, //MipAnglePerLevelScale,
|
|
||||||
(int)m_presetSetting.m_cubemapSetting->m_filter, //FilterType, CP_FILTER_TYPE_COSINE for diffuse cube
|
|
||||||
m_presetSetting.m_cubemapSetting->m_edgeFixup > 0? CP_FIXUP_PULL_LINEAR : CP_FIXUP_NONE, //FixupType, CP_FIXUP_PULL_LINEAR if FixupWidth> 0
|
|
||||||
m_presetSetting.m_cubemapSetting->m_edgeFixup, //FixupWidth,
|
|
||||||
true, //bUseSolidAngle,
|
|
||||||
16, //GlossScale,
|
|
||||||
0, //GlossBias
|
|
||||||
128); //SampleCountGGX
|
|
||||||
|
|
||||||
// Download data into it
|
|
||||||
for (int iFace = 0; iFace < 6; ++iFace)
|
|
||||||
{
|
|
||||||
for (unsigned int dstMip = 0; dstMip < dstMipCount; ++dstMip)
|
|
||||||
{
|
|
||||||
pMem = dstCubemap->GetFaceMemBuffer(dstMip, (CubemapFace)iFace, nPitch);
|
|
||||||
atiCubemanGen.GetOutputFaceData(iFace, dstMip, CP_VAL_FLOAT32, 4, nPitch, pMem, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete srcCubemap;
|
|
||||||
delete dstCubemap;
|
|
||||||
|
|
||||||
//set back to image
|
|
||||||
m_image->Set(outImage);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
// note: O3DE is right hand Z up coordinate
|
|
||||||
// please don't change the order of the enum since we are using it to match the face id defined in AMD's CubemapGen
|
|
||||||
// and they are using left hand Y up coordinate
|
|
||||||
enum CubemapFace
|
|
||||||
{
|
|
||||||
FaceLeft = 0,
|
|
||||||
FaceRight,
|
|
||||||
FaceFront,
|
|
||||||
FaceBack,
|
|
||||||
FaceTop,
|
|
||||||
FaceBottom,
|
|
||||||
FaceCount
|
|
||||||
};
|
|
||||||
|
|
||||||
//we are treating the orientation of faces in 4x3 layout as the original direction.
|
|
||||||
enum class CubemapFaceDirection
|
|
||||||
{
|
|
||||||
DirNoRotation = 0,
|
|
||||||
DirRotateLeft90,
|
|
||||||
DirRotateRight90,
|
|
||||||
DirRotate180,
|
|
||||||
DirMirrorHorizontal
|
|
||||||
};
|
|
||||||
|
|
||||||
//this class contains information to describe a cubemap layout
|
|
||||||
class CubemapLayoutInfo
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct FaceInfo
|
|
||||||
{
|
|
||||||
AZ::u8 row;
|
|
||||||
AZ::u8 column;
|
|
||||||
CubemapFaceDirection direction;
|
|
||||||
};
|
|
||||||
|
|
||||||
//rows and columns of how cubemap's faces laid
|
|
||||||
AZ::u8 m_rows;
|
|
||||||
AZ::u8 m_columns;
|
|
||||||
|
|
||||||
//the type of this layout info for
|
|
||||||
CubemapLayoutType m_type;
|
|
||||||
|
|
||||||
//the index of row and column where all the faces located
|
|
||||||
FaceInfo m_faceInfos[FaceCount];
|
|
||||||
|
|
||||||
CubemapLayoutInfo();
|
|
||||||
void SetFaceInfo(CubemapFace face, AZ::u8 row, AZ::u8 col, CubemapFaceDirection dir);
|
|
||||||
};
|
|
||||||
|
|
||||||
//class to help doing operations with faces for an image as cubemap
|
|
||||||
class CubemapLayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//create a cubemapLayout object for the image. It can be used later to get image information as a cubemap
|
|
||||||
static CubemapLayout* CreateCubemapLayout(IImageObjectPtr image);
|
|
||||||
|
|
||||||
//get layout info for input layout type
|
|
||||||
static CubemapLayoutInfo* GetCubemapLayoutInfo(CubemapLayoutType type);
|
|
||||||
|
|
||||||
//get layout info for input image based on its size
|
|
||||||
static CubemapLayoutInfo* GetCubemapLayoutInfo(IImageObjectPtr image);
|
|
||||||
|
|
||||||
//public functions to get faces information for associated image
|
|
||||||
AZ::u32 GetFaceSize();
|
|
||||||
|
|
||||||
//get the rect where the face in the image
|
|
||||||
void GetRectForFace(AZ::u32 mip, CubemapFace face, QRect& outRect);
|
|
||||||
|
|
||||||
CubemapLayoutInfo* GetLayoutInfo();
|
|
||||||
|
|
||||||
//set/get pixels' data from/to specific face. only works for mip 0
|
|
||||||
void GetFaceData(CubemapFace face, void* outBuffer, AZ::u32& outSize);
|
|
||||||
void SetFaceData(CubemapFace face, void* dataBuffer, AZ::u32 dataSize);
|
|
||||||
|
|
||||||
//get the face's direction
|
|
||||||
CubemapFaceDirection GetFaceDirection(CubemapFace face);
|
|
||||||
|
|
||||||
//get memory for a face from Image data. only works for CubemapLayoutVertical since its memory for each face is continuous
|
|
||||||
void* GetFaceMemBuffer(AZ::u32 mip, CubemapFace face, AZ::u32& outPitch);
|
|
||||||
void SetToFaceMemBuffer(AZ::u32 mip, CubemapFace face, void* dataBuffer);
|
|
||||||
|
|
||||||
private:
|
|
||||||
//information for all supported cubemap layouts
|
|
||||||
static CubemapLayoutInfo s_layoutList[CubemapLayoutTypeCount];
|
|
||||||
|
|
||||||
//the image associated for this CubemapLayout
|
|
||||||
IImageObjectPtr m_image;
|
|
||||||
//the layout information of m_image
|
|
||||||
CubemapLayoutInfo *m_info;
|
|
||||||
//the size of the cubemap's face (which is square and power of 2).
|
|
||||||
uint32 m_faceSize;
|
|
||||||
|
|
||||||
//private constructor. User should always use CreateCubemapLayout create a layout for an image object
|
|
||||||
CubemapLayout();
|
|
||||||
|
|
||||||
//initialize information of all available cubemap layouts
|
|
||||||
static void InitCubemapLayoutInfos();
|
|
||||||
};
|
|
||||||
|
|
||||||
}//end namspace ImageProcessing
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,329 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include "FIR-Weights.h"
|
|
||||||
|
|
||||||
/* ####################################################################################################################
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
void calculateFilterRange(unsigned int srcFactor, int& srcFirst, int& srcLast,
|
|
||||||
unsigned int dstFactor, int dstFirst, int dstLast,
|
|
||||||
double blurFactor, class IWindowFunction<double>* windowFunction)
|
|
||||||
{
|
|
||||||
double s, t, u, scaleFactor; /* scale factors */
|
|
||||||
double srcRadius, srcCenter; /* window position and size */
|
|
||||||
|
|
||||||
#define s0 0
|
|
||||||
#define s1 srcFactor
|
|
||||||
#define d0 0
|
|
||||||
#define d1 dstFactor
|
|
||||||
|
|
||||||
/* the mapping from discrete destination coordinates to continuous source coordinates: */
|
|
||||||
#define MAP(b, scaleFactor, offset) ((b) + (offset)) / (scaleFactor)
|
|
||||||
|
|
||||||
/* relation of dstFactor to srcFactor */
|
|
||||||
s = (double)dstFactor / srcFactor;
|
|
||||||
t = d0 - s * (s0 - 0.5) - 0.5;
|
|
||||||
|
|
||||||
/* compute offsets for MAP */
|
|
||||||
u = d0 - s * (s0 - 0.5) - t;
|
|
||||||
|
|
||||||
/* find scale of filter
|
|
||||||
* when minifying, scaleFactor = 1/s, but when magnifying, scaleFactor = 1
|
|
||||||
*/
|
|
||||||
scaleFactor = (blurFactor == 0.0 ? 1.0 : (blurFactor > 0.0 ? (1.0 + blurFactor) : 1.0 / (1.0 - blurFactor))) * maximum(1., 1. / s);
|
|
||||||
|
|
||||||
/* find support radius of scaled filter
|
|
||||||
* if the window's length is <= 0.5 then we've got point sampling.
|
|
||||||
*/
|
|
||||||
srcRadius = maximum(0.5, scaleFactor * windowFunction->getLength());
|
|
||||||
|
|
||||||
/* sample the continuous filter, scaled by scaleFactor and
|
|
||||||
* positioned at continuous source coordinate srcCenter
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
srcCenter = MAP(dstFirst + 0, s, u);
|
|
||||||
|
|
||||||
/* find the source coordinate range of this positioned filter window */
|
|
||||||
srcFirst = int(floor(srcCenter - srcRadius + 0.5));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
srcCenter = MAP(dstLast - 1, s, u);
|
|
||||||
|
|
||||||
/* find the source coordinate range of this positioned filter window */
|
|
||||||
srcLast = int(floor(srcCenter + srcRadius + 0.5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
FilterWeights<signed short int>* calculateFilterWeights<signed short int>(unsigned int srcFactor, int srcFirst, int srcLast,
|
|
||||||
unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions,
|
|
||||||
double blurFactor, class IWindowFunction<double>* windowFunction,
|
|
||||||
bool peaknorm, bool& plusminus)
|
|
||||||
|
|
||||||
{
|
|
||||||
#define WEIGHTBITS 15
|
|
||||||
#define WEIGHTONE (1 << WEIGHTBITS) /* filter weight of one */
|
|
||||||
|
|
||||||
double s, t, u, scaleFactor; /* scale factors */
|
|
||||||
double srcRadius, srcCenter; /* window position and size */
|
|
||||||
double sumfWeights, neg, pos, nrmWeights, fWeight; /* window position and size */
|
|
||||||
int i, i0, i1; /* window position and size */
|
|
||||||
int dstPosition;
|
|
||||||
signed short int n;
|
|
||||||
bool trimZeros = true, stillzero;
|
|
||||||
int lastnonzero, hWeight, highest;
|
|
||||||
signed int sumiWeights, iWeight;
|
|
||||||
signed short int* weightsPtr, *weightsMem;
|
|
||||||
FilterWeights<signed short int>* weightsObjs;
|
|
||||||
bool pm, pma = false;
|
|
||||||
|
|
||||||
/* pre-calculate filter window solutions for all rows
|
|
||||||
*/
|
|
||||||
weightsObjs = new FilterWeights<signed short int>[dstLast - dstFirst];
|
|
||||||
|
|
||||||
#define s0 0
|
|
||||||
#define s1 srcFactor
|
|
||||||
#define d0 0
|
|
||||||
#define d1 dstFactor
|
|
||||||
|
|
||||||
/* relation of dstFactor to srcFactor */
|
|
||||||
s = (double)dstFactor / srcFactor;
|
|
||||||
t = d0 - s * (s0 - 0.5) - 0.5;
|
|
||||||
|
|
||||||
/* compute offsets for MAP */
|
|
||||||
u = d0 - s * (s0 - 0.5) - t;
|
|
||||||
|
|
||||||
/* find scale of filter
|
|
||||||
* when minifying, scaleFactor = 1/s, but when magnifying, scaleFactor = 1
|
|
||||||
*/
|
|
||||||
scaleFactor = (blurFactor == 0.0 ? 1.0 : (blurFactor > 0.0 ? (1.0 + blurFactor) : 1.0 / (1.0 - blurFactor))) * maximum(1., 1. / s);
|
|
||||||
|
|
||||||
/* find support radius of scaled filter
|
|
||||||
* if the window's length is <= 0.5 then we've got point sampling.
|
|
||||||
*/
|
|
||||||
srcRadius = maximum(0.5, scaleFactor * windowFunction->getLength());
|
|
||||||
|
|
||||||
/* sample the continuous filter, scaled by ap->scaleFactor and
|
|
||||||
* positioned at continuous source coordinate srcCenter, for source coordinates in
|
|
||||||
* the range [0..len-1], writing the weights into wtab.
|
|
||||||
* Scale the weights so they sum up to WEIGHTONE, and trim leading and trailing
|
|
||||||
* zeros if trimZeros is true.
|
|
||||||
*/
|
|
||||||
#undef NORMALIZE_SUMMED_PEAK
|
|
||||||
#define NORMALIZE_MAXXED_PEAK
|
|
||||||
for (dstPosition = dstFirst, pm = false; dstPosition < dstLast; dstPosition++)
|
|
||||||
{
|
|
||||||
srcCenter = MAP(dstPosition, s, u);
|
|
||||||
|
|
||||||
/* find the source coordinate range of this positioned filter window */
|
|
||||||
i0 = int(floor(srcCenter - srcRadius + 0.5));
|
|
||||||
i1 = int(floor(srcCenter + srcRadius + 0.5));
|
|
||||||
|
|
||||||
/* clip against the source-range */
|
|
||||||
if (i0 < srcFirst)
|
|
||||||
{
|
|
||||||
i0 = srcFirst;
|
|
||||||
}
|
|
||||||
if (i1 > srcLast)
|
|
||||||
{
|
|
||||||
i1 = srcLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this is possible if we hit the final line */
|
|
||||||
if (i1 <= i0)
|
|
||||||
{
|
|
||||||
if (i1 >= srcLast)
|
|
||||||
{
|
|
||||||
i0 = i1 - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i1 = i0 + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ_Assert(i0 >= srcFirst, "%s: Invalid source coordinate range!", __FUNCTION__);
|
|
||||||
AZ_Assert(i1 <= srcLast, "%s: Invalid source coordinate range!", __FUNCTION__);
|
|
||||||
AZ_Assert(i0 < i1, "%s: Invalid source coordinate range!", __FUNCTION__);
|
|
||||||
|
|
||||||
/* find maximum peak to normalize the filter */
|
|
||||||
for (sumfWeights = 0, pos = 0, neg = 0, i = i0; i < i1; i++)
|
|
||||||
{
|
|
||||||
/* evaluate the filter function: */
|
|
||||||
fWeight = (*windowFunction)((i + 0.5 - srcCenter) / scaleFactor);
|
|
||||||
|
|
||||||
#if defined(NORMALIZE_SUMMED_PEAK)
|
|
||||||
/* get positive and negative summed peaks */
|
|
||||||
if (fWeight >= 0)
|
|
||||||
{
|
|
||||||
pos += fWeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
neg += fWeight;
|
|
||||||
}
|
|
||||||
#elif defined(NORMALIZE_MAXXED_PEAK)
|
|
||||||
/* get positive and negative maximum peaks */
|
|
||||||
minmax(fWeight, neg, pos);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sumfWeights += fWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the range of source samples to buffer: */
|
|
||||||
weightsMem = new signed short int[(i1 - i0) * abs(numRepetitions)];
|
|
||||||
|
|
||||||
/* set nrmWeights so that sumWeights of windowFunction() is approximately WEIGHTONE
|
|
||||||
* this needs to be adjusted because the maximum weight-coefficient
|
|
||||||
* is NOT allowed to leave [-32768,32767]
|
|
||||||
* a case like {+1.25,-0.25} does produce a sumWeights of 1.0 BUT
|
|
||||||
* produced a weight much too high (-40000)
|
|
||||||
*/
|
|
||||||
#if defined(NORMALIZE_SUMMED_PEAK)
|
|
||||||
sumfWeights = maximum(-neg, pos);
|
|
||||||
#elif defined(NORMALIZE_MAXXED_PEAK)
|
|
||||||
sumfWeights = maximum(sumfWeights, maximum(-neg, pos));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!peaknorm)
|
|
||||||
{
|
|
||||||
nrmWeights = (sumfWeights == 0. ? WEIGHTONE : (-neg > pos ? WEIGHTONE - 1 : WEIGHTONE) / sumfWeights);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nrmWeights = (sumfWeights == 0. ? WEIGHTONE : (-neg > pos ? WEIGHTONE - 1 : WEIGHTONE) / maximum(-neg, pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compute the discrete, sampled filter coefficients */
|
|
||||||
stillzero = trimZeros;
|
|
||||||
for (sumiWeights = 0, hWeight = -WEIGHTONE, weightsPtr = weightsMem, i = i0; i < i1; i++)
|
|
||||||
{
|
|
||||||
/* evaluate the filter function: */
|
|
||||||
fWeight = (*windowFunction)((i + 0.5 - srcCenter) / scaleFactor);
|
|
||||||
|
|
||||||
/* normalize against the peak sumWeights, because the sums are not allowed to leave -32768/32767 */
|
|
||||||
fWeight = fWeight * nrmWeights;
|
|
||||||
iWeight = int(round(fWeight));
|
|
||||||
|
|
||||||
/* find first nonzero */
|
|
||||||
if (stillzero && (iWeight == 0))
|
|
||||||
{
|
|
||||||
i0++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Assert((-fWeight >= -32768.5) && (-fWeight <= 32767.5), "%s:The weight exceeded the maximum weight-coefficient.", __FUNCTION__);
|
|
||||||
|
|
||||||
if (!peaknorm)
|
|
||||||
{
|
|
||||||
sumiWeights += iWeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sumiWeights = maximum(sumiWeights, iWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define sgnextend(n, iWeight) (n & 1 ? (iWeight < 0 ? -1 : 0) : iWeight)
|
|
||||||
if (numRepetitions < 0)
|
|
||||||
{
|
|
||||||
/* add weight to table, interleaved sign */
|
|
||||||
for (n = 0; n < -numRepetitions; n++)
|
|
||||||
{
|
|
||||||
*weightsPtr++ = sgnextend(n, -iWeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* add weight to table */
|
|
||||||
for (n = 0; n < numRepetitions; n++)
|
|
||||||
{
|
|
||||||
*weightsPtr++ = -iWeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stillzero = false;
|
|
||||||
|
|
||||||
/* find last nonzero */
|
|
||||||
if (iWeight != 0)
|
|
||||||
{
|
|
||||||
lastnonzero = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for negative values */
|
|
||||||
if (iWeight < 0)
|
|
||||||
{
|
|
||||||
pm = pma = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find most influential value */
|
|
||||||
if (iWeight >= hWeight)
|
|
||||||
{
|
|
||||||
highest = i;
|
|
||||||
hWeight = iWeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sumiWeights == 0)
|
|
||||||
{
|
|
||||||
i0 = (i0 + i1) >> 1;
|
|
||||||
i1 = (i0 + 1);
|
|
||||||
|
|
||||||
for (n = 0, weightsPtr = weightsMem; n < numRepetitions; n++)
|
|
||||||
{
|
|
||||||
*weightsPtr++ = -WEIGHTONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* skip leading and trailing zeros */
|
|
||||||
if (trimZeros)
|
|
||||||
{
|
|
||||||
/* set i0 and i1 to the nonzero support of the filter */
|
|
||||||
i0 = i0;
|
|
||||||
i1 = i1 = lastnonzero + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sumiWeights != WEIGHTONE)
|
|
||||||
{
|
|
||||||
/* Fudge with the highest value */
|
|
||||||
i = highest;
|
|
||||||
|
|
||||||
/* fudge srcCenter sample */
|
|
||||||
iWeight = WEIGHTONE - sumiWeights;
|
|
||||||
|
|
||||||
for (n = 0, weightsPtr = weightsMem + (i - i0) * numRepetitions; n < numRepetitions; n++)
|
|
||||||
{
|
|
||||||
*weightsPtr++ -= iWeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the new adjusted range of source samples to buffer: */
|
|
||||||
weightsObjs[dstPosition].first = i0;
|
|
||||||
weightsObjs[dstPosition].last = i1;
|
|
||||||
weightsObjs[dstPosition].hasNegativeWeights = pm;
|
|
||||||
weightsObjs[dstPosition].weights = weightsMem;
|
|
||||||
}
|
|
||||||
|
|
||||||
plusminus = pma;
|
|
||||||
return weightsObjs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "FIR-Windows.h"
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
/* ####################################################################################################################
|
|
||||||
*/
|
|
||||||
template<class DataType>
|
|
||||||
inline DataType abs (const DataType& ths) { return (ths < 0 ? -ths : ths); }
|
|
||||||
template<class DataType>
|
|
||||||
inline void minmax (const DataType& ths, DataType& mn, DataType& mx) { mn = (mn > ths ? ths : mn); mx = (mx < ths ? ths : mx); }
|
|
||||||
template<class DataType>
|
|
||||||
inline DataType minimum(const DataType& ths, const DataType& tht) { return (ths < tht ? ths : tht); }
|
|
||||||
template<class DataType>
|
|
||||||
inline DataType maximum(const DataType& ths, const DataType& tht) { return (ths > tht ? ths : tht); }
|
|
||||||
|
|
||||||
/* ####################################################################################################################
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class FilterWeights
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FilterWeights()
|
|
||||||
: weights(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~FilterWeights()
|
|
||||||
{
|
|
||||||
delete[] weights;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// window-position
|
|
||||||
int first, last;
|
|
||||||
|
|
||||||
// do we encounter positive as well as negative weights
|
|
||||||
bool hasNegativeWeights;
|
|
||||||
|
|
||||||
/* weights, summing up to -(1 << 15),
|
|
||||||
* means weights are given negative
|
|
||||||
* that enables us to use signed short
|
|
||||||
* multiplication while occupying 0x8000
|
|
||||||
*/
|
|
||||||
T* weights;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ####################################################################################################################
|
|
||||||
*/
|
|
||||||
|
|
||||||
void calculateFilterRange (unsigned int srcFactor, int& srcFirst, int& srcLast,
|
|
||||||
unsigned int dstFactor, int dstFirst, int dstLast,
|
|
||||||
double blurFactor, class IWindowFunction<double>* windowFunction);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
FilterWeights<T>* calculateFilterWeights(unsigned int srcFactor, int srcFirst, int srcLast,
|
|
||||||
unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions,
|
|
||||||
double blurFactor, class IWindowFunction<double>* windowFunction,
|
|
||||||
bool peaknorm, bool& plusminus);
|
|
||||||
|
|
||||||
template<>
|
|
||||||
FilterWeights<signed short int>* calculateFilterWeights<signed short int>(unsigned int srcFactor, int srcFirst, int srcLast,
|
|
||||||
unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions,
|
|
||||||
double blurFactor, class IWindowFunction<double>* windowFunction,
|
|
||||||
bool peaknorm, bool& plusminus);
|
|
||||||
|
|
||||||
|
|
||||||
} //end namespace ImageProcessing
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,260 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
|
|
||||||
#include <Converters/FIR-Weights.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageFlags.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Lookup table for a function 'float fn(float x)'.
|
|
||||||
// Computed function values are stored in the table for x in [0.0; 1.0].
|
|
||||||
//
|
|
||||||
// If passed x is less than xMin (xMin must be >= 0) or greater than 1.0,
|
|
||||||
// then the original function is called.
|
|
||||||
// Otherwise, a value from the table (linearly interpolated)
|
|
||||||
// is returned.
|
|
||||||
template <int TABLE_SIZE>
|
|
||||||
class FunctionLookupTable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FunctionLookupTable(float(*fn)(float x), float xMin, float maxAllowedDifference)
|
|
||||||
: m_fn(fn)
|
|
||||||
, m_xMin(xMin)
|
|
||||||
, m_fMaxDiff(maxAllowedDifference)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Initialize() const
|
|
||||||
{
|
|
||||||
m_initialized = true;
|
|
||||||
AZ_Assert(m_xMin >= 0.0f, "wrong initial data for m_xMin");
|
|
||||||
for (int i = 0; i <= TABLE_SIZE; ++i)
|
|
||||||
{
|
|
||||||
const float x = i / (float)TABLE_SIZE;
|
|
||||||
const float y = (*m_fn)(x);
|
|
||||||
m_table[i] = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float compute(float x) const
|
|
||||||
{
|
|
||||||
if (x < m_xMin || x > 1)
|
|
||||||
{
|
|
||||||
return m_fn(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float f = x * TABLE_SIZE;
|
|
||||||
|
|
||||||
const int i = int(f);
|
|
||||||
|
|
||||||
if (!m_initialized)
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= TABLE_SIZE)
|
|
||||||
{
|
|
||||||
return m_table[TABLE_SIZE];
|
|
||||||
}
|
|
||||||
|
|
||||||
const float alpha = f - i;
|
|
||||||
return (1 - alpha) * m_table[i] + alpha * m_table[i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool Test(const float maxDifferenceAllowed) const
|
|
||||||
{
|
|
||||||
if (int(-0.99f) != 0 ||
|
|
||||||
int(+0.00f) != 0 ||
|
|
||||||
int(+0.01f) != 0 ||
|
|
||||||
int(+0.99f) != 0 ||
|
|
||||||
int(+1.00f) != 1 ||
|
|
||||||
int(+1.01f) != 1 ||
|
|
||||||
int(+1.99f) != 1 ||
|
|
||||||
int(+2.00f) != 2 ||
|
|
||||||
int(+2.01f) != 2)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_xMin < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int n = 1000000;
|
|
||||||
for (int i = 0; i <= n; ++i)
|
|
||||||
{
|
|
||||||
const float x = 1.1f * (i / (float)n);
|
|
||||||
const float resOriginal = m_fn(x);
|
|
||||||
const float resTable = compute(x);
|
|
||||||
const float difference = resOriginal - resTable;
|
|
||||||
|
|
||||||
if (fabs(difference) > maxDifferenceAllowed)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
float(*m_fn)(float x);
|
|
||||||
float m_xMin;
|
|
||||||
mutable float m_table[TABLE_SIZE + 1];
|
|
||||||
mutable bool m_initialized = false;
|
|
||||||
float m_fMaxDiff = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static float GammaToLinear(float x)
|
|
||||||
{
|
|
||||||
return (x <= 0.04045f) ? x / 12.92f : powf((x + 0.055f) / 1.055f, 2.4f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float LinearToGamma(float x)
|
|
||||||
{
|
|
||||||
return (x <= 0.0031308f) ? x * 12.92f : 1.055f * powf(x, 1.0f / 2.4f) - 0.055f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FunctionLookupTable<1024> s_lutGammaToLinear(GammaToLinear, 0.04045f, 0.00001f);
|
|
||||||
static FunctionLookupTable<1024> s_lutLinearToGamma(LinearToGamma, 0.05f, 0.00001f);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ImageToProcess::GammaToLinearRGBA32F(bool bDeGamma)
|
|
||||||
{
|
|
||||||
// return immediately if there is no need to de-gamma image and the source is in the desired format
|
|
||||||
EPixelFormat srcFmt = m_img->GetPixelFormat();
|
|
||||||
if (!bDeGamma && (srcFmt == ePixelFormat_R32G32B32A32F))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//convert to 32F first
|
|
||||||
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcFmt))
|
|
||||||
{
|
|
||||||
AZ_Warning("Image Processing", false, "This is not common user case with compressed format input. But it may continue");
|
|
||||||
ConvertFormat(ePixelFormat_R32G32B32A32F);
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr srcImage = m_img;
|
|
||||||
EPixelFormat dstFmt = ePixelFormat_R32G32B32A32F;
|
|
||||||
IImageObjectPtr dstImage(m_img->AllocateImage(dstFmt));
|
|
||||||
|
|
||||||
//create pixel operation function for src and dst images
|
|
||||||
IPixelOperationPtr srcOp = CreatePixelOperation(srcFmt);
|
|
||||||
IPixelOperationPtr dstOp = CreatePixelOperation(dstFmt);
|
|
||||||
|
|
||||||
//get count of bytes per pixel for both src and dst images
|
|
||||||
uint32 srcPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(srcFmt)->bitsPerBlock / 8;
|
|
||||||
uint32 dstPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
const uint32 dwMips = dstImage->GetMipCount();
|
|
||||||
float r, g, b, a;
|
|
||||||
for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
|
|
||||||
{
|
|
||||||
uint8* srcPixelBuf;
|
|
||||||
uint32 srcPitch;
|
|
||||||
srcImage->GetImagePointer(dwMip, srcPixelBuf, srcPitch);
|
|
||||||
uint8* dstPixelBuf;
|
|
||||||
uint32 dstPitch;
|
|
||||||
dstImage->GetImagePointer(dwMip, dstPixelBuf, dstPitch);
|
|
||||||
|
|
||||||
const uint32 pixelCount = srcImage->GetPixelCount(dwMip);
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, srcPixelBuf += srcPixelBytes, dstPixelBuf += dstPixelBytes)
|
|
||||||
{
|
|
||||||
srcOp->GetRGBA(srcPixelBuf, r, g, b, a);
|
|
||||||
if (bDeGamma)
|
|
||||||
{
|
|
||||||
r = s_lutGammaToLinear.compute(r);
|
|
||||||
g = s_lutGammaToLinear.compute(g);
|
|
||||||
b = s_lutGammaToLinear.compute(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
dstOp->SetRGBA(dstPixelBuf, r, g, b, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_img = dstImage;
|
|
||||||
|
|
||||||
if (bDeGamma)
|
|
||||||
{
|
|
||||||
m_img->RemoveImageFlags(EIF_SRGBRead);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageToProcess::LinearToGamma()
|
|
||||||
{
|
|
||||||
if (Get()->HasImageFlags(EIF_SRGBRead))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s: input image is already SRGB", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_img->GetPixelFormat()))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "This is not common user case with compressed format input. But it may continue");
|
|
||||||
ConvertFormat(ePixelFormat_R32G32B32A32F);
|
|
||||||
}
|
|
||||||
|
|
||||||
EPixelFormat srcFmt = m_img->GetPixelFormat();
|
|
||||||
IImageObjectPtr srcImage = m_img;
|
|
||||||
|
|
||||||
IImageObjectPtr dstImage(m_img->AllocateImage(srcFmt));
|
|
||||||
|
|
||||||
//create pixel operation function
|
|
||||||
IPixelOperationPtr pixelOp = CreatePixelOperation(srcFmt);
|
|
||||||
|
|
||||||
//get count of bytes per pixel for both src and dst images
|
|
||||||
uint32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(srcFmt)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
const uint32 dwMips = srcImage->GetMipCount();
|
|
||||||
float r, g, b, a;
|
|
||||||
for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
|
|
||||||
{
|
|
||||||
uint8* srcPixelBuf;
|
|
||||||
uint32 srcPitch;
|
|
||||||
srcImage->GetImagePointer(dwMip, srcPixelBuf, srcPitch);
|
|
||||||
uint8* dstPixelBuf;
|
|
||||||
uint32 dstPitch;
|
|
||||||
dstImage->GetImagePointer(dwMip, dstPixelBuf, dstPitch);
|
|
||||||
|
|
||||||
const uint32 pixelCount = srcImage->GetPixelCount(dwMip);
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, srcPixelBuf += pixelBytes, dstPixelBuf += pixelBytes)
|
|
||||||
{
|
|
||||||
pixelOp->GetRGBA(srcPixelBuf, r, g, b, a);
|
|
||||||
r = s_lutLinearToGamma.compute(r);
|
|
||||||
g = s_lutLinearToGamma.compute(g);
|
|
||||||
b = s_lutLinearToGamma.compute(b);
|
|
||||||
pixelOp->SetRGBA(dstPixelBuf, r, g, b, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_img = dstImage;
|
|
||||||
Get()->AddImageFlags(EIF_SRGBRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
#include <Processing/ImageConvert.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <Converters/FIR-Windows.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
|
|
||||||
// higher mip level is subtracted by lower mip level when applying the [cheap] high pass filter
|
|
||||||
void ImageToProcess::CreateHighPass(AZ::u32 dwMipDown)
|
|
||||||
{
|
|
||||||
//no need to convert if mip go down 0
|
|
||||||
if (dwMipDown == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EPixelFormat ePixelFormat = m_img->GetPixelFormat();
|
|
||||||
|
|
||||||
if (ePixelFormat != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "You need convert the orginal image to ePixelFormat_R32G32B32A32F before call this function");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AZ::u32 dwWidth, dwHeight, dwMips;
|
|
||||||
dwWidth = m_img->GetWidth(0);
|
|
||||||
dwHeight = m_img->GetHeight(0);
|
|
||||||
dwMips = m_img->GetMipCount();
|
|
||||||
|
|
||||||
if (dwMipDown >= dwMips)
|
|
||||||
{
|
|
||||||
AZ_Warning("Image Processing", false, "CreateHighPass can't go down %i MIP levels for high pass as there are not\
|
|
||||||
enough MIP levels available, going down by %i instead", dwMipDown, dwMips - 1);
|
|
||||||
dwMipDown = dwMips - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
IImageObjectPtr newImage(IImageObject::CreateImage(dwWidth, dwHeight, dwMips, ePixelFormat));
|
|
||||||
newImage->CopyPropertiesFrom(m_img);
|
|
||||||
|
|
||||||
IPixelOperationPtr pixelOp = CreatePixelOperation(ePixelFormat);
|
|
||||||
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
AZ::u32 dstMips = newImage->GetMipCount();
|
|
||||||
for (AZ::u32 dstMip = 0; dstMip < dwMipDown; ++dstMip)
|
|
||||||
{
|
|
||||||
// linear interpolation
|
|
||||||
FilterImage(MipGenType::triangle, MipGenEvalType::sum, 0.0f, 0.0f, m_img, dwMipDown, newImage, dstMip, NULL, NULL);
|
|
||||||
|
|
||||||
const AZ::u32 pixelCountIn = m_img->GetWidth(dstMip) *m_img->GetHeight(dstMip);
|
|
||||||
const AZ::u32 pixelCountOut = newImage->GetWidth(dstMip) * newImage->GetHeight(dstMip);
|
|
||||||
|
|
||||||
//substraction
|
|
||||||
AZ::u8* srcPixelBuf;
|
|
||||||
AZ::u32 srcPitch;
|
|
||||||
m_img->GetImagePointer(dstMip, srcPixelBuf, srcPitch);
|
|
||||||
AZ::u8* dstPixelBuf;
|
|
||||||
AZ::u32 dstPitch;
|
|
||||||
newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch);
|
|
||||||
const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip);
|
|
||||||
|
|
||||||
for (AZ::u32 i = 0; i < pixelCount; ++i, srcPixelBuf += pixelBytes, dstPixelBuf += pixelBytes)
|
|
||||||
{
|
|
||||||
float r1, g1, b1, a1, r2, g2, b2, a2;
|
|
||||||
pixelOp->GetRGBA(srcPixelBuf, r1, g1, b1, a1);
|
|
||||||
pixelOp->GetRGBA(dstPixelBuf, r2, g2, b2, a2);
|
|
||||||
|
|
||||||
r2 = AZ::GetClamp<float>(r1 - r2 + 0.5f, 0.0f, 1.0f);
|
|
||||||
g2 = AZ::GetClamp<float>(g1 - g2 + 0.5f, 0.0f, 1.0f);
|
|
||||||
b2 = AZ::GetClamp<float>(b1 - b2 + 0.5f, 0.0f, 1.0f);
|
|
||||||
a2 = AZ::GetClamp<float>(a1 - a2 + 0.5f, 0.0f, 1.0f);
|
|
||||||
pixelOp->SetRGBA(dstPixelBuf, r2, g2, b2, a2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mips below the chosen highpass mip are grey
|
|
||||||
for (AZ::u32 dstMip = dwMipDown; dstMip < dstMips; ++dstMip)
|
|
||||||
{
|
|
||||||
AZ::u8* dstPixelBuf;
|
|
||||||
AZ::u32 dstPitch;
|
|
||||||
newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch);
|
|
||||||
const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip);
|
|
||||||
|
|
||||||
for (AZ::u32 i = 0; i < pixelCount; ++i, dstPixelBuf += pixelBytes)
|
|
||||||
{
|
|
||||||
pixelOp->SetRGBA(dstPixelBuf, 0.5f, 0.5f, 0.5f, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_img = newImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
|
|
||||||
#include <Converters/Histogram.h>
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
float GetLuminance(const float& r, const float& g, const float& b)
|
|
||||||
{
|
|
||||||
return (r * 0.30f + g * 0.59f + b * 0.11f);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ComputeLuminanceHistogram(IImageObjectPtr imageObject, Histogram<256>& histogram)
|
|
||||||
{
|
|
||||||
EPixelFormat pixelFormat = imageObject->GetPixelFormat();
|
|
||||||
if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(pixelFormat)))
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//create pixel operation function
|
|
||||||
IPixelOperationPtr pixelOp = CreatePixelOperation(pixelFormat);
|
|
||||||
|
|
||||||
//setup histogram bin
|
|
||||||
static const size_t binCount = 256;
|
|
||||||
Histogram<binCount>::Bins bins;
|
|
||||||
Histogram<binCount>::clearBins(bins);
|
|
||||||
|
|
||||||
//get count of bytes per pixel
|
|
||||||
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormat)->bitsPerBlock / 8;
|
|
||||||
|
|
||||||
const AZ::u32 mipCount = imageObject->GetMipCount();
|
|
||||||
float color[4];
|
|
||||||
for (uint32 mip = 0; mip < mipCount; ++mip)
|
|
||||||
{
|
|
||||||
AZ::u8* pixelBuf;
|
|
||||||
AZ::u32 pitch;
|
|
||||||
imageObject->GetImagePointer(mip, pixelBuf, pitch);
|
|
||||||
const uint32 pixelCount = imageObject->GetPixelCount(mip);
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes)
|
|
||||||
{
|
|
||||||
pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]);
|
|
||||||
|
|
||||||
const float luminance = AZ::GetClamp(GetLuminance(color[0], color[1], color[2]), 0.0f, 1.0f);
|
|
||||||
const float f = luminance * binCount;
|
|
||||||
if (f <= 0)
|
|
||||||
{
|
|
||||||
++bins[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const int bin = int(f);
|
|
||||||
++bins[(bin < binCount) ? bin : binCount - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
histogram.set(bins);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} // end namespace ImageProcessing
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
template <size_t BIN_COUNT>
|
|
||||||
class Histogram
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef AZ::u64 Bins[BIN_COUNT];
|
|
||||||
|
|
||||||
public:
|
|
||||||
Histogram()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clearBins(Bins& bins)
|
|
||||||
{
|
|
||||||
memset(&bins, 0, sizeof(bins));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(const Bins& bins)
|
|
||||||
{
|
|
||||||
m_bins[0] = bins[0];
|
|
||||||
m_binsCumulative[0] = bins[0];
|
|
||||||
double sum = 0.0f;
|
|
||||||
for (size_t i = 1; i < BIN_COUNT; ++i)
|
|
||||||
{
|
|
||||||
m_bins[i] = bins[i];
|
|
||||||
m_binsCumulative[i] = m_binsCumulative[i - 1] + bins[i];
|
|
||||||
sum += i * double(bins[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const AZ::u64 totalCount = getTotalSampleCount();
|
|
||||||
m_meanBin = (totalCount <= 0) ? 0.0f : float(sum / totalCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::u64 getTotalSampleCount() const
|
|
||||||
{
|
|
||||||
return m_binsCumulative[BIN_COUNT - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
float getPercentage(size_t minBin, size_t maxBin) const
|
|
||||||
{
|
|
||||||
const AZ::u64 totalCount = getTotalSampleCount();
|
|
||||||
|
|
||||||
if ((totalCount <= 0) || (minBin > maxBin) || (maxBin < 0) || (minBin >= BIN_COUNT))
|
|
||||||
{
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
minBin = AZ::GetMax(minBin, size_t(0));
|
|
||||||
maxBin = AZ::GetMin(maxBin, BIN_COUNT-1);
|
|
||||||
|
|
||||||
const AZ::u64 count = m_binsCumulative[maxBin] - ((minBin <= 0) ? 0 : m_binsCumulative[minBin-1]);
|
|
||||||
|
|
||||||
return float((double(count) * 100.0) / double(totalCount));
|
|
||||||
}
|
|
||||||
|
|
||||||
float getMeanBin() const
|
|
||||||
{
|
|
||||||
return m_meanBin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Bins m_bins;
|
|
||||||
Bins m_binsCumulative;
|
|
||||||
float m_meanBin;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool ComputeLuminanceHistogram(IImageObjectPtr imageObject, Histogram<256>& histogram);
|
|
||||||
}
|
|
||||||
@ -1,420 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageFlags.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
template<const int qBits>
|
|
||||||
static void AdjustScaleForQuantization(float fBaseValue, float fBaseLine, float& cScale, float& cMinColor, float& cMaxColor)
|
|
||||||
{
|
|
||||||
const int qOne = (1 << qBits) - 1;
|
|
||||||
const int qUpperBits = (8 - qBits);
|
|
||||||
const int qLowerBits = qBits - qUpperBits;
|
|
||||||
|
|
||||||
const int v = int(floor(fBaseValue * qOne));
|
|
||||||
|
|
||||||
int v0 = v - (v != 0);
|
|
||||||
int v1 = v + 0;
|
|
||||||
int v2 = v + (v != qOne);
|
|
||||||
|
|
||||||
v0 = (v0 << qUpperBits) | (v0 >> qLowerBits);
|
|
||||||
v1 = (v1 << qUpperBits) | (v1 >> qLowerBits);
|
|
||||||
v2 = (v2 << qUpperBits) | (v2 >> qLowerBits);
|
|
||||||
|
|
||||||
const float f0 = v0 / 255.0f;
|
|
||||||
const float f1 = v1 / 255.0f;
|
|
||||||
const float f2 = v2 / 255.0f;
|
|
||||||
|
|
||||||
float fBaseLock = -1;
|
|
||||||
|
|
||||||
if (fabsf(f0 - fBaseValue) < fabsf(fBaseLock - fBaseValue))
|
|
||||||
{
|
|
||||||
fBaseLock = f0;
|
|
||||||
}
|
|
||||||
if (fabsf(f1 - fBaseValue) < fabsf(fBaseLock - fBaseValue))
|
|
||||||
{
|
|
||||||
fBaseLock = f1;
|
|
||||||
}
|
|
||||||
if (fabsf(f2 - fBaseValue) < fabsf(fBaseLock - fBaseValue))
|
|
||||||
{
|
|
||||||
fBaseLock = f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
float lScale = (1.0f - fBaseLock) / (1.0f - fBaseLine);
|
|
||||||
float vScale = (1.0f - fBaseValue) / (1.0f - fBaseLine);
|
|
||||||
float sScale = lScale / vScale;
|
|
||||||
|
|
||||||
float csScale = (cScale / sScale);
|
|
||||||
float csBias = cMinColor - (1.0f - sScale) * (cScale / sScale);
|
|
||||||
|
|
||||||
if ((csBias > 0.0f) && ((csScale + csBias) < 1.0f))
|
|
||||||
{
|
|
||||||
cMinColor = csBias;
|
|
||||||
cScale = csScale;
|
|
||||||
cMaxColor = csScale + csBias;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void CImageObject::NormalizeImageRange(EColorNormalization eColorNorm, EAlphaNormalization eAlphaNorm, bool bMaintainBlack, int nExponentBits)
|
|
||||||
{
|
|
||||||
if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s: unsupported source format", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 dwWidth, dwHeight, dwMips;
|
|
||||||
GetExtent(dwWidth, dwHeight, dwMips);
|
|
||||||
|
|
||||||
// find image's range, can be negative
|
|
||||||
float cMinColor[4] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
|
|
||||||
float cMaxColor[4] = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
|
|
||||||
|
|
||||||
for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
|
|
||||||
{
|
|
||||||
uint8* pSrcMem;
|
|
||||||
uint32 dwSrcPitch;
|
|
||||||
GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
|
|
||||||
|
|
||||||
dwHeight = GetHeight(dwMip);
|
|
||||||
dwWidth = GetWidth(dwMip);
|
|
||||||
for (uint32 dwY = 0; dwY < dwHeight; ++dwY)
|
|
||||||
{
|
|
||||||
const float* pSrcPix = (float*)&pSrcMem[dwY * dwSrcPitch];
|
|
||||||
for (uint32 dwX = 0; dwX < dwWidth; ++dwX)
|
|
||||||
{
|
|
||||||
cMinColor[0] = AZ::GetMin(cMinColor[0], pSrcPix[0]);
|
|
||||||
cMinColor[1] = AZ::GetMin(cMinColor[1], pSrcPix[1]);
|
|
||||||
cMinColor[2] = AZ::GetMin(cMinColor[2], pSrcPix[2]);
|
|
||||||
cMinColor[3] = AZ::GetMin(cMinColor[3], pSrcPix[3]);
|
|
||||||
|
|
||||||
cMaxColor[0] = AZ::GetMax(cMaxColor[0], pSrcPix[0]);
|
|
||||||
cMaxColor[1] = AZ::GetMax(cMaxColor[1], pSrcPix[1]);
|
|
||||||
cMaxColor[2] = AZ::GetMax(cMaxColor[2], pSrcPix[2]);
|
|
||||||
cMaxColor[3] = AZ::GetMax(cMaxColor[3], pSrcPix[3]);
|
|
||||||
|
|
||||||
pSrcPix += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bMaintainBlack)
|
|
||||||
{
|
|
||||||
cMinColor[0] = AZ::GetMin(0.f, cMinColor[0]);
|
|
||||||
cMinColor[1] = AZ::GetMin(0.f, cMinColor[1]);
|
|
||||||
cMinColor[2] = AZ::GetMin(0.f, cMinColor[2]);
|
|
||||||
cMinColor[3] = AZ::GetMin(0.f, cMinColor[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ_Assert(cMaxColor[0] >= cMinColor[0] && cMaxColor[1] >= cMinColor[1] &&
|
|
||||||
cMaxColor[2] >= cMinColor[2] && cMaxColor[3] >= cMinColor[3], "bad color range");
|
|
||||||
|
|
||||||
// some graceful threshold to avoid extreme cases
|
|
||||||
if (cMaxColor[0] - cMinColor[0] < (3.f / 255))
|
|
||||||
{
|
|
||||||
cMinColor[0] = AZ::GetMax(0.f, cMinColor[0] - (2.f / 255));
|
|
||||||
cMaxColor[0] = AZ::GetMin(1.f, cMaxColor[0] + (2.f / 255));
|
|
||||||
}
|
|
||||||
if (cMaxColor[1] - cMinColor[1] < (3.f / 255))
|
|
||||||
{
|
|
||||||
cMinColor[1] = AZ::GetMax(0.f, cMinColor[1] - (2.f / 255));
|
|
||||||
cMaxColor[1] = AZ::GetMin(1.f, cMaxColor[1] + (2.f / 255));
|
|
||||||
}
|
|
||||||
if (cMaxColor[2] - cMinColor[2] < (3.f / 255))
|
|
||||||
{
|
|
||||||
cMinColor[2] = AZ::GetMax(0.f, cMinColor[2] - (2.f / 255));
|
|
||||||
cMaxColor[2] = AZ::GetMin(1.f, cMaxColor[2] + (2.f / 255));
|
|
||||||
}
|
|
||||||
if (cMaxColor[3] - cMinColor[3] < (3.f / 255))
|
|
||||||
{
|
|
||||||
cMinColor[3] = AZ::GetMax(0.f, cMinColor[3] - (2.f / 255));
|
|
||||||
cMaxColor[3] = AZ::GetMin(1.f, cMaxColor[3] + (2.f / 255));
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate range to normalize to
|
|
||||||
const float fMaxExponent = powf(2.0f, (float)nExponentBits) - 1.0f;
|
|
||||||
const float cUprValue = powf(2.0f, fMaxExponent);
|
|
||||||
|
|
||||||
if (eColorNorm == eColorNormalization_PassThrough)
|
|
||||||
{
|
|
||||||
cMinColor[0] = cMinColor[1] = cMinColor[2] = 0.f;
|
|
||||||
cMaxColor[0] = cMaxColor[1] = cMaxColor[2] = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't touch alpha channel if not used
|
|
||||||
if (eAlphaNorm == eAlphaNormalization_SetToZero)
|
|
||||||
{
|
|
||||||
// Store the range explicitly into the structure for read-back.
|
|
||||||
// The formats which request range expansion don't support alpha.
|
|
||||||
cMinColor[3] = 0.f;
|
|
||||||
cMaxColor[3] = cUprValue;
|
|
||||||
}
|
|
||||||
else if (eAlphaNorm == eAlphaNormalization_PassThrough)
|
|
||||||
{
|
|
||||||
cMinColor[3] = 0.f;
|
|
||||||
cMaxColor[3] = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the origins of the color model's lattice for the range of values
|
|
||||||
// these values need to be encoded as precise as possible under quantization
|
|
||||||
AZ::Vector4 cBaseLines = AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
AZ::Vector4 cScale = AZ::Vector4(cMaxColor[0] - cMinColor[0], cMaxColor[1] - cMinColor[1],
|
|
||||||
cMaxColor[2] - cMinColor[2], cMaxColor[3] - cMinColor[3]);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// NOTE: disabled for now, in the future we can turn this on to force availability
|
|
||||||
// of value to guarantee for example perfect grey-scales (using YFF)
|
|
||||||
switch (GetImageFlags() & EIF_Colormodel)
|
|
||||||
{
|
|
||||||
case EIF_Colormodel_RGB:
|
|
||||||
cBaseLines = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
break;
|
|
||||||
case EIF_Colormodel_CIE:
|
|
||||||
cBaseLines = Vec4(0.0f, 1.f / 3, 1.f / 3, 0.0f);
|
|
||||||
break;
|
|
||||||
case EIF_Colormodel_IRB:
|
|
||||||
cBaseLines = Vec4(0.0f, 1.f / 2, 1.f / 2, 0.0f);
|
|
||||||
break;
|
|
||||||
case EIF_Colormodel_YCC:
|
|
||||||
case EIF_Colormodel_YFF:
|
|
||||||
cBaseLines = Vec4(1.f / 2, 0.0f, 1.f / 2, 0.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4 cBaseScale = cBaseLines;
|
|
||||||
cBaseLines = cBaseLines - cMinColor;
|
|
||||||
cBaseLines = cBaseLines / cScale;
|
|
||||||
|
|
||||||
if ((cBaseLines.x > 0.0f) && (cBaseLines.x < 1.0f))
|
|
||||||
{
|
|
||||||
AdjustScaleForQuantization<5>(cBaseLines.x, cBaseScale.x, cScale.x, cMinColor.x, cMaxColor.x);
|
|
||||||
}
|
|
||||||
if ((cBaseLines.y > 0.0f) && (cBaseLines.y < 1.0f))
|
|
||||||
{
|
|
||||||
AdjustScaleForQuantization<6>(cBaseLines.y, cBaseScale.y, cScale.y, cMinColor.y, cMaxColor.y);
|
|
||||||
}
|
|
||||||
if ((cBaseLines.z > 0.0f) && (cBaseLines.z < 1.0f))
|
|
||||||
{
|
|
||||||
AdjustScaleForQuantization<5>(cBaseLines.z, cBaseScale.z, cScale.z, cMinColor.z, cMaxColor.z);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// normalize the image
|
|
||||||
AZ::Vector4 vMin = AZ::Vector4(cMinColor[0], cMinColor[1], cMinColor[2], cMinColor[3]);
|
|
||||||
for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
|
|
||||||
{
|
|
||||||
uint8* pSrcMem;
|
|
||||||
uint32 dwSrcPitch;
|
|
||||||
GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
|
|
||||||
|
|
||||||
dwHeight = GetHeight(dwMip);
|
|
||||||
dwWidth = GetWidth(dwMip);
|
|
||||||
for (uint32 dwY = 0; dwY < dwHeight; ++dwY)
|
|
||||||
{
|
|
||||||
AZ::Vector4* pSrcPix = (AZ::Vector4*)&pSrcMem[dwY * dwSrcPitch];
|
|
||||||
for (uint32 dwX = 0; dwX < dwWidth; ++dwX)
|
|
||||||
{
|
|
||||||
*pSrcPix = *pSrcPix - vMin;
|
|
||||||
*pSrcPix = *pSrcPix / cScale;
|
|
||||||
*pSrcPix = *pSrcPix * cUprValue;
|
|
||||||
|
|
||||||
pSrcPix++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up a range
|
|
||||||
SetColorRange(AZ::Color(cMinColor[0], cMinColor[1], cMinColor[2], cMinColor[3]),
|
|
||||||
AZ::Color(cMaxColor[0], cMaxColor[1], cMaxColor[2], cMaxColor[3]));
|
|
||||||
|
|
||||||
// set up a flag
|
|
||||||
AddImageFlags(EIF_RenormalizedTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CImageObject::ExpandImageRange([[maybe_unused]] EColorNormalization eColorMode, EAlphaNormalization eAlphaMode, int nExponentBits)
|
|
||||||
{
|
|
||||||
AZ_Assert(!((eAlphaMode != eAlphaNormalization_SetToZero) && (nExponentBits != 0)), "%s: Unexpected alpha mode", __FUNCTION__);
|
|
||||||
|
|
||||||
if (!HasImageFlags(EIF_RenormalizedTexture))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 dwWidth, dwHeight, dwMips;
|
|
||||||
GetExtent(dwWidth, dwHeight, dwMips);
|
|
||||||
|
|
||||||
// calculate range to normalize to
|
|
||||||
const float fMaxExponent = powf(2.0f, (float)nExponentBits) - 1.0f;
|
|
||||||
float cUprValue = powf(2.0f, fMaxExponent);
|
|
||||||
|
|
||||||
// find image's range, can be negative
|
|
||||||
AZ::Color cMinColor = AZ::Color(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
|
|
||||||
AZ::Color cMaxColor = AZ::Color(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX);
|
|
||||||
|
|
||||||
GetColorRange(cMinColor, cMaxColor);
|
|
||||||
|
|
||||||
// don't touch alpha channel if not used
|
|
||||||
if (eAlphaMode == eAlphaNormalization_SetToZero)
|
|
||||||
{
|
|
||||||
// Overwrite the range explicitly into the structure.
|
|
||||||
// The formats which request range expansion don't support alpha.
|
|
||||||
cUprValue = cMaxColor.GetA();
|
|
||||||
|
|
||||||
cMinColor.SetA(1.f);
|
|
||||||
cMaxColor.SetA(1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// expand the image
|
|
||||||
const AZ::Vector4 cScale = cMaxColor.GetAsVector4() - cMinColor.GetAsVector4();
|
|
||||||
for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
|
|
||||||
{
|
|
||||||
uint8* pSrcMem;
|
|
||||||
uint32 dwSrcPitch;
|
|
||||||
GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
|
|
||||||
|
|
||||||
dwHeight = GetHeight(dwMip);
|
|
||||||
dwWidth = GetWidth(dwMip);
|
|
||||||
for (uint32 dwY = 0; dwY < dwHeight; ++dwY)
|
|
||||||
{
|
|
||||||
AZ::Vector4* pSrcPix = (AZ::Vector4*)&pSrcMem[dwY * dwSrcPitch];
|
|
||||||
for (uint32 dwX = 0; dwX < dwWidth; ++dwX)
|
|
||||||
{
|
|
||||||
*pSrcPix = *pSrcPix / cUprValue;
|
|
||||||
*pSrcPix = *pSrcPix * cScale;
|
|
||||||
*pSrcPix = *pSrcPix + cMinColor.GetAsVector4();
|
|
||||||
|
|
||||||
pSrcPix++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up a range
|
|
||||||
SetColorRange(AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
|
|
||||||
// set up a flag
|
|
||||||
RemoveImageFlags(EIF_RenormalizedTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void CImageObject::NormalizeVectors(AZ::u32 firstMip, AZ::u32 maxMipCount)
|
|
||||||
{
|
|
||||||
if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount());
|
|
||||||
for (uint32 mip = firstMip; mip < lastMip; ++mip)
|
|
||||||
{
|
|
||||||
const uint32 pixelCount = GetPixelCount(mip);
|
|
||||||
uint8* imageMem;
|
|
||||||
uint32 pitch;
|
|
||||||
GetImagePointer(mip, imageMem, pitch);
|
|
||||||
float* pPixels = (float*)imageMem;
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4)
|
|
||||||
{
|
|
||||||
AZ::Vector3 vNormal = AZ::Vector3(pPixels[0] * 2.0f - 1.0f, pPixels[1] * 2.0f - 1.0f, pPixels[2] * 2.0f - 1.0f);
|
|
||||||
|
|
||||||
// TODO: every opposing vector addition produces the zero-vector for
|
|
||||||
// normals on the entire sphere, in that case the forward vector [0,0,1]
|
|
||||||
// isn't necessarily right and we should look at the adjacent normals
|
|
||||||
// for a direction
|
|
||||||
if (vNormal.IsZero())
|
|
||||||
{
|
|
||||||
vNormal = AZ::Vector3(1.0f, 0.0f, 0.0f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vNormal.NormalizeSafe();
|
|
||||||
}
|
|
||||||
|
|
||||||
pPixels[0] = vNormal.GetX() * 0.5f + 0.5f;
|
|
||||||
pPixels[1] = vNormal.GetY() * 0.5f + 0.5f;
|
|
||||||
pPixels[2] = vNormal.GetZ() * 0.5f + 0.5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CImageObject::ScaleAndBiasChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& scale, const AZ::Vector4& bias)
|
|
||||||
{
|
|
||||||
if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount());
|
|
||||||
for (uint32 mip = firstMip; mip < lastMip; ++mip)
|
|
||||||
{
|
|
||||||
const uint32 pixelCount = GetPixelCount(mip);
|
|
||||||
uint8* imageMem;
|
|
||||||
uint32 pitch;
|
|
||||||
GetImagePointer(mip, imageMem, pitch);
|
|
||||||
float* pPixels = (float*)imageMem;
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4)
|
|
||||||
{
|
|
||||||
pPixels[0] = pPixels[0] * scale.GetX() + bias.GetX();
|
|
||||||
pPixels[1] = pPixels[1] * scale.GetY() + bias.GetY();
|
|
||||||
pPixels[2] = pPixels[2] * scale.GetZ() + bias.GetZ();
|
|
||||||
pPixels[3] = pPixels[3] * scale.GetW() + bias.GetW();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CImageObject::ClampChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& min, const AZ::Vector4& max)
|
|
||||||
{
|
|
||||||
if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount());
|
|
||||||
for (uint32 mip = firstMip; mip < lastMip; ++mip)
|
|
||||||
{
|
|
||||||
|
|
||||||
const uint32 pixelCount = GetPixelCount(mip);
|
|
||||||
uint8* imageMem;
|
|
||||||
uint32 pitch;
|
|
||||||
GetImagePointer(mip, imageMem, pitch);
|
|
||||||
float* pPixels = (float*)imageMem;
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4)
|
|
||||||
{
|
|
||||||
pPixels[0] = AZ::GetClamp(pPixels[0], float(min.GetX()), float(max.GetX()));
|
|
||||||
pPixels[1] = AZ::GetClamp(pPixels[1], float(min.GetY()), float(max.GetY()));
|
|
||||||
pPixels[2] = AZ::GetClamp(pPixels[2], float(min.GetZ()), float(max.GetZ()));
|
|
||||||
pPixels[3] = AZ::GetClamp(pPixels[3], float(min.GetW()), float(max.GetW()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace ImageProcessing
|
|
||||||
@ -1,487 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
|
|
||||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
|
||||||
|
|
||||||
#include <Processing/ImageObjectImpl.h>
|
|
||||||
#include <Processing/ImageConvert.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <Converters/PixelOperation.h>
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//functions for maintaining alpha coverage.
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//convertion: all data type supported by pixel channel <=> float
|
|
||||||
float U8ToF32(uint8 in)
|
|
||||||
{
|
|
||||||
return in / 255.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 F32ToU8(float in)
|
|
||||||
{
|
|
||||||
return aznumeric_cast<uint8>(round(AZ::GetClamp(in, 0.f, 1.f) * 255));
|
|
||||||
}
|
|
||||||
|
|
||||||
float U16ToF32(uint16 in)
|
|
||||||
{
|
|
||||||
return in / 65535.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 F32ToU16(float in)
|
|
||||||
{
|
|
||||||
return aznumeric_cast<uint16>(round(AZ::GetClamp(in, 0.f, 1.f) * 65535.f));
|
|
||||||
}
|
|
||||||
|
|
||||||
float HalfToF32(SHalf in)
|
|
||||||
{
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHalf F32ToHalf(float in)
|
|
||||||
{
|
|
||||||
return SHalf(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
//stucture for RGBE pixel format
|
|
||||||
struct RgbE
|
|
||||||
{
|
|
||||||
static const int RGB9E5_EXPONENT_BITS = 5;
|
|
||||||
static const int RGB9E5_MANTISSA_BITS = 9;
|
|
||||||
static const int RGB9E5_EXP_BIAS = 15;
|
|
||||||
static const int RGB9E5_MAX_VALID_BIASED_EXP = 31;
|
|
||||||
static const int MAX_RGB9E5_EXP = (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS);
|
|
||||||
static const int RGB9E5_MANTISSA_VALUES = (1 << RGB9E5_MANTISSA_BITS);
|
|
||||||
static const int MAX_RGB9E5_MANTISSA = (RGB9E5_MANTISSA_VALUES - 1);
|
|
||||||
|
|
||||||
static float MAX_RGB9E5;
|
|
||||||
|
|
||||||
unsigned int r : 9;
|
|
||||||
unsigned int g : 9;
|
|
||||||
unsigned int b : 9;
|
|
||||||
unsigned int e : 5;
|
|
||||||
|
|
||||||
static int log2(float x)
|
|
||||||
{
|
|
||||||
int bitfield = *((int*)(&x));
|
|
||||||
bitfield &= ~0x80000000;
|
|
||||||
|
|
||||||
return ((bitfield >> 23) - 127);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetRGBF(float& outR, float& outG, float& outB) const
|
|
||||||
{
|
|
||||||
int exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS;
|
|
||||||
float scale = powf(2.0f, aznumeric_cast<float>(exponent));
|
|
||||||
outR = r * scale;
|
|
||||||
outG = g * scale;
|
|
||||||
outB = b * scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBF(const float& inR, const float& inG, const float& inB)
|
|
||||||
{
|
|
||||||
float rf = AZStd::GetMax(0.0f, AZStd::GetMin(inR, MAX_RGB9E5));
|
|
||||||
float gf = AZStd::GetMax(0.0f, AZStd::GetMin(inG, MAX_RGB9E5));
|
|
||||||
float bf = AZStd::GetMax(0.0f, AZStd::GetMin(inB, MAX_RGB9E5));
|
|
||||||
float mf = AZStd::GetMax(rf, AZStd::GetMax(gf, bf));
|
|
||||||
|
|
||||||
e = AZStd::GetMax(0, log2(mf) + (RGB9E5_EXP_BIAS + 1));
|
|
||||||
|
|
||||||
int exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS;
|
|
||||||
float scale = powf(2.0f, aznumeric_cast<float>(exponent));
|
|
||||||
|
|
||||||
r = AZStd::GetMin(511, (int)floorf(rf / scale + 0.5f));
|
|
||||||
g = AZStd::GetMin(511, (int)floorf(gf / scale + 0.5f));
|
|
||||||
b = AZStd::GetMin(511, (int)floorf(bf / scale + 0.5f));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
float RgbE::MAX_RGB9E5 = (((float)MAX_RGB9E5_MANTISSA) / RGB9E5_MANTISSA_VALUES * (1 << MAX_RGB9E5_EXP));
|
|
||||||
|
|
||||||
//ePixelFormat_R8G8B8A8
|
|
||||||
class PixelOperationR8G8B8A8 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint8* data = buf;
|
|
||||||
r = U8ToF32(data[0]);
|
|
||||||
g = U8ToF32(data[1]);
|
|
||||||
b = U8ToF32(data[2]);
|
|
||||||
a = U8ToF32(data[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override
|
|
||||||
{
|
|
||||||
uint8* data = buf;
|
|
||||||
data[0] = F32ToU8(r);
|
|
||||||
data[1] = F32ToU8(g);
|
|
||||||
data[2] = F32ToU8(b);
|
|
||||||
data[3] = F32ToU8(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R8G8B8X8
|
|
||||||
class PixelOperationR8G8B8X8 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint8* data = buf;
|
|
||||||
r = U8ToF32(data[0]);
|
|
||||||
g = U8ToF32(data[1]);
|
|
||||||
b = U8ToF32(data[2]);
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
uint8* data = buf;
|
|
||||||
data[0] = F32ToU8(r);
|
|
||||||
data[1] = F32ToU8(g);
|
|
||||||
data[2] = F32ToU8(b);
|
|
||||||
data[3] = 0xff;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_B8G8R8A8
|
|
||||||
class PixelOperationB8G8R8A8 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint8* data = buf;
|
|
||||||
r = U8ToF32(data[2]);
|
|
||||||
g = U8ToF32(data[1]);
|
|
||||||
b = U8ToF32(data[0]);
|
|
||||||
a = U8ToF32(data[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override
|
|
||||||
{
|
|
||||||
uint8* data = buf;
|
|
||||||
data[0] = F32ToU8(b);
|
|
||||||
data[1] = F32ToU8(g);
|
|
||||||
data[2] = F32ToU8(r);
|
|
||||||
data[3] = F32ToU8(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R8G8
|
|
||||||
class PixelOperationR8G8 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint8* data = buf;
|
|
||||||
r = U8ToF32(data[0]);
|
|
||||||
g = U8ToF32(data[1]);
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
uint8* data = buf;
|
|
||||||
data[0] = F32ToU8(r);
|
|
||||||
data[1] = F32ToU8(g);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R8
|
|
||||||
class PixelOperationR8 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint8* data = buf;
|
|
||||||
r = U8ToF32(data[0]);
|
|
||||||
g = 0.f;
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
uint8* data = buf;
|
|
||||||
data[0] = F32ToU8(r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_A8
|
|
||||||
class PixelOperationA8 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint8* data = buf;
|
|
||||||
a = U8ToF32(data[0]);
|
|
||||||
//save alpha information to rgb too. useful for preview.
|
|
||||||
r = a;
|
|
||||||
g = a;
|
|
||||||
b = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, [[maybe_unused]] const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, const float& a) override
|
|
||||||
{
|
|
||||||
uint8* data = buf;
|
|
||||||
data[0] = F32ToU8(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R16G16B16A16
|
|
||||||
class PixelOperationR16G16B16A16 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint16* data = (uint16*)(buf);
|
|
||||||
r = U16ToF32(data[0]);
|
|
||||||
g = U16ToF32(data[1]);
|
|
||||||
b = U16ToF32(data[2]);
|
|
||||||
a = U16ToF32(data[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override
|
|
||||||
{
|
|
||||||
uint16* data = (uint16*)(buf);
|
|
||||||
data[0] = F32ToU16(r);
|
|
||||||
data[1] = F32ToU16(g);
|
|
||||||
data[2] = F32ToU16(b);
|
|
||||||
data[3] = F32ToU16(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R16G16
|
|
||||||
class PixelOperationR16G16 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint16* data = (uint16*)(buf);
|
|
||||||
r = U16ToF32(data[0]);
|
|
||||||
g = U16ToF32(data[1]);
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
uint16* data = (uint16*)(buf);
|
|
||||||
data[0] = F32ToU16(r);
|
|
||||||
data[1] = F32ToU16(g);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R16
|
|
||||||
class PixelOperationR16 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const uint16* data = (uint16*)(buf);
|
|
||||||
r = U16ToF32(data[0]);
|
|
||||||
g = 0.f;
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
uint16* data = (uint16*)(buf);
|
|
||||||
data[0] = F32ToU16(r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R9G9B9E5
|
|
||||||
class PixelOperationR9G9B9E5 : public IPixelOperation
|
|
||||||
{
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const RgbE* data = (RgbE*)(buf);
|
|
||||||
data->GetRGBF(r, g, b);
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
RgbE* data = (RgbE*)(buf);
|
|
||||||
data->SetRGBF(r, g, b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R32G32B32A32F
|
|
||||||
class PixelOperationR32G32B32A32F : public IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const float* data = (float*)(buf);
|
|
||||||
r = data[0];
|
|
||||||
g = data[1];
|
|
||||||
b = data[2];
|
|
||||||
a = data[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override
|
|
||||||
{
|
|
||||||
float* data = (float*)(buf);
|
|
||||||
data[0] = r;
|
|
||||||
data[1] = g;
|
|
||||||
data[2] = b;
|
|
||||||
data[3] = a;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R32G32F
|
|
||||||
class PixelOperationR32G32F : public IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const float* data = (float*)(buf);
|
|
||||||
r = data[0];
|
|
||||||
g = data[1];
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
float* data = (float*)(buf);
|
|
||||||
data[0] = r;
|
|
||||||
data[1] = g;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R32F
|
|
||||||
class PixelOperationR32F : public IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const float* data = (float*)(buf);
|
|
||||||
r = data[0];
|
|
||||||
g = 0.f;
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
float* data = (float*)(buf);
|
|
||||||
data[0] = r;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R16G16B16A16F
|
|
||||||
class PixelOperationR16G16B16A16F : public IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const SHalf* data = (SHalf*)(buf);
|
|
||||||
r = data[0];
|
|
||||||
g = data[1];
|
|
||||||
b = data[2];
|
|
||||||
a = data[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override
|
|
||||||
{
|
|
||||||
SHalf* data = (SHalf*)(buf);
|
|
||||||
data[0] = SHalf(r);
|
|
||||||
data[1] = SHalf(g);
|
|
||||||
data[2] = SHalf(b);
|
|
||||||
data[3] = SHalf(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R16G16F
|
|
||||||
class PixelOperationR16G16F : public IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const SHalf* data = (SHalf*)(buf);
|
|
||||||
r = data[0];
|
|
||||||
g = data[1];
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
SHalf* data = (SHalf*)(buf);
|
|
||||||
data[0] = SHalf(r);
|
|
||||||
data[1] = SHalf(g);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ePixelFormat_R16F
|
|
||||||
class PixelOperationR16F : public IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override
|
|
||||||
{
|
|
||||||
const SHalf* data = (SHalf*)(buf);
|
|
||||||
r = data[0];
|
|
||||||
g = 0.f;
|
|
||||||
b = 0.f;
|
|
||||||
a = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override
|
|
||||||
{
|
|
||||||
SHalf* data = (SHalf*)(buf);
|
|
||||||
data[0] = SHalf(r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
IPixelOperationPtr CreatePixelOperation(EPixelFormat pixelFmt)
|
|
||||||
{
|
|
||||||
switch (pixelFmt)
|
|
||||||
{
|
|
||||||
case ePixelFormat_R8G8B8A8:
|
|
||||||
return AZStd::make_shared<PixelOperationR8G8B8A8>();
|
|
||||||
case ePixelFormat_R8G8B8X8:
|
|
||||||
return AZStd::make_shared<PixelOperationR8G8B8X8>();
|
|
||||||
case ePixelFormat_B8G8R8A8:
|
|
||||||
return AZStd::make_shared<PixelOperationB8G8R8A8>();
|
|
||||||
case ePixelFormat_R8G8:
|
|
||||||
return AZStd::make_shared<PixelOperationR8G8>();
|
|
||||||
case ePixelFormat_R8:
|
|
||||||
return AZStd::make_shared<PixelOperationR8>();
|
|
||||||
case ePixelFormat_A8:
|
|
||||||
return AZStd::make_shared<PixelOperationA8>();
|
|
||||||
case ePixelFormat_R16G16B16A16:
|
|
||||||
return AZStd::make_shared<PixelOperationR16G16B16A16>();
|
|
||||||
case ePixelFormat_R16G16:
|
|
||||||
return AZStd::make_shared<PixelOperationR16G16>();
|
|
||||||
case ePixelFormat_R16:
|
|
||||||
return AZStd::make_shared<PixelOperationR16>();
|
|
||||||
case ePixelFormat_R9G9B9E5:
|
|
||||||
return AZStd::make_shared<PixelOperationR9G9B9E5>();
|
|
||||||
case ePixelFormat_R32G32B32A32F:
|
|
||||||
return AZStd::make_shared<PixelOperationR32G32B32A32F>();
|
|
||||||
case ePixelFormat_R32G32F:
|
|
||||||
return AZStd::make_shared<PixelOperationR32G32F>();
|
|
||||||
case ePixelFormat_R32F:
|
|
||||||
return AZStd::make_shared<PixelOperationR32F>();
|
|
||||||
case ePixelFormat_R16G16B16A16F:
|
|
||||||
return AZStd::make_shared<PixelOperationR16G16B16A16F>();
|
|
||||||
case ePixelFormat_R16G16F:
|
|
||||||
return AZStd::make_shared<PixelOperationR16G16F>();
|
|
||||||
case ePixelFormat_R16F:
|
|
||||||
return AZStd::make_shared<PixelOperationR16F>();
|
|
||||||
default:
|
|
||||||
AZ_Assert(false, "This function should be only called for uncompressed pixel format");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class IPixelOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IPixelOperation() {}
|
|
||||||
|
|
||||||
virtual void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) = 0;
|
|
||||||
virtual void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef AZStd::shared_ptr<IPixelOperation> IPixelOperationPtr;
|
|
||||||
IPixelOperationPtr CreatePixelOperation(EPixelFormat pixelFmt);
|
|
||||||
|
|
||||||
}// namespace ImageProcessing
|
|
||||||
@ -1,386 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include <ImageProcessing_Traits_Platform.h>
|
|
||||||
#include <Editor/EditorCommon.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
#include <ImageLoader/ImageLoaders.h>
|
|
||||||
#include <BuilderSettings/TextureSettings.h>
|
|
||||||
#include <BuilderSettings/PresetSettings.h>
|
|
||||||
#include <ImageProcessing/PixelFormats.h>
|
|
||||||
#include <Converters/Cubemap.h>
|
|
||||||
#include <Processing/ImageConvert.h>
|
|
||||||
#include <AzCore/std/string/conversions.h>
|
|
||||||
|
|
||||||
#include <AzFramework/StringFunc/StringFunc.h>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
|
|
||||||
bool EditorHelper::s_IsPixelFormatStringInited = false;
|
|
||||||
const char* EditorHelper::s_PixelFormatString[ImageProcessing::EPixelFormat::ePixelFormat_Count];
|
|
||||||
|
|
||||||
void EditorHelper::InitPixelFormatString()
|
|
||||||
{
|
|
||||||
if (!s_IsPixelFormatStringInited)
|
|
||||||
{
|
|
||||||
s_IsPixelFormatStringInited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPixelFormats& pixelFormats = CPixelFormats::GetInstance();
|
|
||||||
for (int format = 0; format < EPixelFormat::ePixelFormat_Count; format ++)
|
|
||||||
{
|
|
||||||
const PixelFormatInfo* info = pixelFormats.GetPixelFormatInfo((EPixelFormat)format);
|
|
||||||
s_PixelFormatString[(EPixelFormat)format] = "";
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
s_PixelFormatString[(EPixelFormat)format] = info->szName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Cannot find name of EPixelFormat %i", format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const AZStd::string EditorHelper::GetFileSizeString(AZ::u32 fileSizeInBytes)
|
|
||||||
{
|
|
||||||
AZStd::string fileSizeStr;
|
|
||||||
|
|
||||||
static double kb = 1024.0f;
|
|
||||||
static double mb = kb * 1024.0;
|
|
||||||
static double gb = mb * 1024.0;
|
|
||||||
|
|
||||||
static AZStd::string byteStr = "B";
|
|
||||||
static AZStd::string kbStr = "KB";
|
|
||||||
static AZStd::string mbStr = "MB";
|
|
||||||
static AZStd::string gbStr = "GB";
|
|
||||||
|
|
||||||
#if AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX
|
|
||||||
kb = 1000.0;
|
|
||||||
mb = kb * 1000.0;
|
|
||||||
gb = mb * 1000.0;
|
|
||||||
|
|
||||||
kbStr = "kB";
|
|
||||||
mbStr = "mB";
|
|
||||||
gbStr = "gB";
|
|
||||||
#endif // AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX
|
|
||||||
|
|
||||||
if (fileSizeInBytes < kb)
|
|
||||||
{
|
|
||||||
fileSizeStr = AZStd::string::format("%u%s", fileSizeInBytes, byteStr.c_str());
|
|
||||||
}
|
|
||||||
else if (fileSizeInBytes < mb)
|
|
||||||
{
|
|
||||||
double size = fileSizeInBytes / kb;
|
|
||||||
fileSizeStr = AZStd::string::format("%.2f%s", size, kbStr.c_str());
|
|
||||||
}
|
|
||||||
else if (fileSizeInBytes < gb)
|
|
||||||
{
|
|
||||||
double size = fileSizeInBytes / mb;
|
|
||||||
fileSizeStr = AZStd::string::format("%.2f%s", size, mbStr.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double size = fileSizeInBytes / gb;
|
|
||||||
fileSizeStr = AZStd::string::format("%.2f%s", size, gbStr.c_str());
|
|
||||||
}
|
|
||||||
return fileSizeStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AZStd::string EditorHelper::ToReadablePlatformString(const AZStd::string& platformRawStr)
|
|
||||||
{
|
|
||||||
AZStd::string readableString;
|
|
||||||
AZStd::string platformStrLowerCase = platformRawStr;
|
|
||||||
AZStd::to_lower(platformStrLowerCase.begin(), platformStrLowerCase.end());
|
|
||||||
if (platformStrLowerCase == "pc")
|
|
||||||
{
|
|
||||||
readableString = "PC";
|
|
||||||
}
|
|
||||||
else if (platformStrLowerCase == "es3")
|
|
||||||
{
|
|
||||||
readableString = "Android";
|
|
||||||
}
|
|
||||||
else if (platformStrLowerCase == "osx_gl")
|
|
||||||
{
|
|
||||||
readableString = "macOS";
|
|
||||||
}
|
|
||||||
else if (platformStrLowerCase == "provo")
|
|
||||||
{
|
|
||||||
readableString = "Provo";
|
|
||||||
}
|
|
||||||
else if (platformStrLowerCase == "ios")
|
|
||||||
{
|
|
||||||
readableString = "iOS";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return platformRawStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return readableString;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EditorTextureSetting::EditorTextureSetting(const AZ::Uuid& sourceTextureId)
|
|
||||||
{
|
|
||||||
const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* fullDetails = AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::GetSourceByUuid(sourceTextureId);
|
|
||||||
InitFromPath(fullDetails->GetFullPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorTextureSetting::EditorTextureSetting(const AZStd::string& texturePath)
|
|
||||||
{
|
|
||||||
InitFromPath(texturePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorTextureSetting::InitFromPath(const AZStd::string& texturePath)
|
|
||||||
{
|
|
||||||
m_fullPath = texturePath;
|
|
||||||
AzFramework::StringFunc::Path::GetFullFileName(texturePath.c_str(), m_textureName);
|
|
||||||
|
|
||||||
m_img = IImageObjectPtr(LoadImageFromFile(m_fullPath));
|
|
||||||
|
|
||||||
if (m_img == nullptr)
|
|
||||||
{
|
|
||||||
AZ_Warning("Texture Editor", false, "%s is not a valid texture image.", texturePath.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool generatedDefaults = false;
|
|
||||||
m_settingsMap = TextureSettings::GetMultiplatformTextureSetting(m_fullPath, generatedDefaults);
|
|
||||||
|
|
||||||
// Get the preset id from one platform. The preset id for each platform should always be same
|
|
||||||
AZ_Assert(m_settingsMap.size() > 0, "There is no platform information");
|
|
||||||
AZ::Uuid presetId = m_settingsMap.begin()->second.m_preset;
|
|
||||||
const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetId);
|
|
||||||
|
|
||||||
if (!preset)
|
|
||||||
{
|
|
||||||
AZ_Warning("Texture Editor", false, "Cannot find preset %s! Will assign a suggested one for the texture.", presetId.ToString<AZStd::string>().c_str());
|
|
||||||
presetId = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath, m_img);
|
|
||||||
|
|
||||||
for (auto& settingIter : m_settingsMap)
|
|
||||||
{
|
|
||||||
settingIter.second.ApplyPreset(presetId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorTextureSetting::SetIsOverrided()
|
|
||||||
{
|
|
||||||
for (auto& it : m_settingsMap)
|
|
||||||
{
|
|
||||||
m_overrideFromPreset = false;
|
|
||||||
TextureSettings& textureSetting = it.second;
|
|
||||||
const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(textureSetting.m_preset);
|
|
||||||
if (presetSetting != nullptr)
|
|
||||||
{
|
|
||||||
if ((textureSetting.m_sizeReduceLevel != presetSetting->m_sizeReduceLevel) ||
|
|
||||||
(textureSetting.m_suppressEngineReduce != presetSetting->m_suppressEngineReduce) ||
|
|
||||||
(presetSetting->m_mipmapSetting != nullptr && textureSetting.m_mipGenType != presetSetting->m_mipmapSetting->m_type))
|
|
||||||
{
|
|
||||||
m_overrideFromPreset = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Texture Preset %s is not found!", textureSetting.m_preset.ToString<AZStd::string>().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorTextureSetting::SetToPreset(const AZStd::string& presetName)
|
|
||||||
{
|
|
||||||
m_overrideFromPreset = false;
|
|
||||||
|
|
||||||
AZ::Uuid presetId = BuilderSettingManager::Instance()->GetPresetIdFromName(presetName);
|
|
||||||
if (presetId.IsNull())
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Texture Preset %s has no associated UUID.", presetName.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& settingIter : m_settingsMap)
|
|
||||||
{
|
|
||||||
settingIter.second.ApplyPreset(presetId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the texture setting on certain platform
|
|
||||||
TextureSettings& EditorTextureSetting::GetMultiplatformTextureSetting(const AZStd::string& platform)
|
|
||||||
{
|
|
||||||
AZ_Assert(m_settingsMap.size() > 0, "Texture Editor", "There is no texture settings for texture %s", m_fullPath.c_str());
|
|
||||||
PlatformName platformName = platform;
|
|
||||||
if (platform.empty())
|
|
||||||
{
|
|
||||||
platformName = BuilderSettingManager::s_defaultPlatform;
|
|
||||||
}
|
|
||||||
if (m_settingsMap.find(platformName) != m_settingsMap.end())
|
|
||||||
{
|
|
||||||
return m_settingsMap[platformName];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Cannot find texture setting on platform %s", platformName.c_str());
|
|
||||||
}
|
|
||||||
return m_settingsMap.begin()->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EditorTextureSetting::GetFinalInfoForTextureOnPlatform(const AZStd::string& platform, AZ::u32 wantedReduce, ResolutionInfo& outResolutionInfo)
|
|
||||||
{
|
|
||||||
if (m_settingsMap.find(platform) == m_settingsMap.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy current texture setting and set to desired reduce
|
|
||||||
TextureSettings textureSetting = m_settingsMap[platform];
|
|
||||||
wantedReduce = AZStd::min<int>(AZStd::max<int>(s_MinReduceLevel, wantedReduce), s_MaxReduceLevel);
|
|
||||||
textureSetting.m_sizeReduceLevel = wantedReduce;
|
|
||||||
|
|
||||||
const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(textureSetting.m_preset, platform);
|
|
||||||
if (presetSetting)
|
|
||||||
{
|
|
||||||
EPixelFormat pixelFormat = presetSetting->m_pixelFormat;
|
|
||||||
CPixelFormats& pixelFormats = CPixelFormats::GetInstance();
|
|
||||||
|
|
||||||
AZ::u32 inputWidth = m_img->GetWidth(0);
|
|
||||||
AZ::u32 inputHeight = m_img->GetHeight(0);
|
|
||||||
|
|
||||||
// Update input width and height if it's a cubemap
|
|
||||||
if (presetSetting->m_cubemapSetting != nullptr)
|
|
||||||
{
|
|
||||||
CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_img);
|
|
||||||
if (srcCubemap == nullptr)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
inputWidth = srcCubemap->GetFaceSize();
|
|
||||||
inputHeight = inputWidth;
|
|
||||||
outResolutionInfo.arrayCount = 6;
|
|
||||||
delete srcCubemap;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetOutputExtent(inputWidth, inputHeight, outResolutionInfo.width, outResolutionInfo.height, outResolutionInfo.reduce, &textureSetting, presetSetting);
|
|
||||||
|
|
||||||
AZ::u32 mipMapCount = pixelFormats.ComputeMaxMipCount(pixelFormat, outResolutionInfo.width, outResolutionInfo.height);
|
|
||||||
outResolutionInfo.mipCount = presetSetting->m_mipmapSetting != nullptr && textureSetting.m_enableMipmap ? mipMapCount : 1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EditorTextureSetting::RefreshMipSetting(bool enableMip)
|
|
||||||
{
|
|
||||||
bool enabled = true;
|
|
||||||
for (auto& it : m_settingsMap)
|
|
||||||
{
|
|
||||||
const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(it.second.m_preset);
|
|
||||||
if (enableMip)
|
|
||||||
{
|
|
||||||
if (preset && preset->m_mipmapSetting)
|
|
||||||
{
|
|
||||||
it.second.m_enableMipmap = true;
|
|
||||||
it.second.m_mipGenType = preset->m_mipmapSetting->m_type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it.second.m_enableMipmap = false;
|
|
||||||
enabled = false;
|
|
||||||
AZ_Error("Texture Editor", false, "Preset %s does not support mipmap!", preset->m_name.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it.second.m_enableMipmap = false;
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorTextureSetting::PropagateCommonSettings()
|
|
||||||
{
|
|
||||||
if (m_settingsMap.size() <= 1)
|
|
||||||
{
|
|
||||||
//Only one setting available, no need to propagate
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureSettings& texSetting = GetMultiplatformTextureSetting();
|
|
||||||
for (auto& it = ++ m_settingsMap.begin(); it != m_settingsMap.end(); ++it)
|
|
||||||
{
|
|
||||||
const PlatformName defaultPlatform = BuilderSettingManager::s_defaultPlatform;
|
|
||||||
if (it->first != defaultPlatform)
|
|
||||||
{
|
|
||||||
it->second.m_enableMipmap = texSetting.m_enableMipmap;
|
|
||||||
it->second.m_maintainAlphaCoverage = texSetting.m_maintainAlphaCoverage;
|
|
||||||
it->second.m_mipGenEval = texSetting.m_mipGenEval;
|
|
||||||
it->second.m_mipGenType = texSetting.m_mipGenType;
|
|
||||||
for (size_t i = 0; i < TextureSettings::s_MaxMipMaps; i++)
|
|
||||||
{
|
|
||||||
it->second.m_mipAlphaAdjust[i] = texSetting.m_mipAlphaAdjust[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AZStd::list<ResolutionInfo> EditorTextureSetting::GetResolutionInfo(AZStd::string platform, AZ::u32& minReduce, AZ::u32& maxReduce)
|
|
||||||
{
|
|
||||||
AZStd::list<ResolutionInfo> resolutionInfos;
|
|
||||||
// Set the min/max reduce to the global value range first
|
|
||||||
minReduce = s_MaxReduceLevel;
|
|
||||||
maxReduce = s_MinReduceLevel;
|
|
||||||
for (AZ::u32 i = s_MinReduceLevel; i <= s_MaxReduceLevel; i++)
|
|
||||||
{
|
|
||||||
ResolutionInfo resolutionInfo;
|
|
||||||
GetFinalInfoForTextureOnPlatform(platform, i, resolutionInfo);
|
|
||||||
// If actual reduce is lower than desired reduce, it reaches the limit and we can stop try lower resolution
|
|
||||||
if (i > resolutionInfo.reduce)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Finds out the final min/max reduce based on range in different platforms
|
|
||||||
minReduce = AZStd::min<AZ::u32>(resolutionInfo.reduce, minReduce);
|
|
||||||
maxReduce = AZStd::max<AZ::u32>(resolutionInfo.reduce, maxReduce);
|
|
||||||
resolutionInfos.push_back(resolutionInfo);
|
|
||||||
}
|
|
||||||
return resolutionInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
AZStd::list<ResolutionInfo> EditorTextureSetting::GetResolutionInfoForMipmap(AZStd::string platform)
|
|
||||||
{
|
|
||||||
AZStd::list<ResolutionInfo> resolutionInfos;
|
|
||||||
unsigned int baseReduce = m_settingsMap[platform].m_sizeReduceLevel;
|
|
||||||
ResolutionInfo baseInfo;
|
|
||||||
GetFinalInfoForTextureOnPlatform(platform, baseReduce, baseInfo);
|
|
||||||
resolutionInfos.push_back(baseInfo);
|
|
||||||
for (AZ::u32 i = 1; i < baseInfo.mipCount; i++)
|
|
||||||
{
|
|
||||||
ResolutionInfo resolutionInfo = baseInfo;
|
|
||||||
resolutionInfo.width = AZStd::max<AZ::u32>(baseInfo.width >> i, 1);
|
|
||||||
resolutionInfo.height = AZStd::max<AZ::u32>(baseInfo.height >> i, 1);
|
|
||||||
resolutionInfo.reduce = baseInfo.reduce + i;
|
|
||||||
resolutionInfo.mipCount = 1;
|
|
||||||
resolutionInfos.push_back(resolutionInfo);
|
|
||||||
}
|
|
||||||
return resolutionInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BuilderSettings/BuilderSettingManager.h>
|
|
||||||
#include <BuilderSettings/TextureSettings.h>
|
|
||||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
|
||||||
|
|
||||||
#include <QImage>
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class EditorHelper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const char* s_PixelFormatString[ImageProcessing::EPixelFormat::ePixelFormat_Count];
|
|
||||||
static void InitPixelFormatString();
|
|
||||||
static const AZStd::string GetFileSizeString(AZ::u32 fileSizeInBytes);
|
|
||||||
static const AZStd::string ToReadablePlatformString(const AZStd::string& platformRawStr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool s_IsPixelFormatStringInited;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ResolutionInfo
|
|
||||||
{
|
|
||||||
AZ::u32 width = 0;
|
|
||||||
AZ::u32 height = 0;
|
|
||||||
AZ::u32 arrayCount = 1;
|
|
||||||
AZ::u32 reduce = 0;
|
|
||||||
AZ::u32 mipCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EditorTextureSetting
|
|
||||||
{
|
|
||||||
AZStd::string m_textureName = "";
|
|
||||||
AZStd::string m_fullPath = "";
|
|
||||||
ImageProcessing::MultiplatformTextureSettings m_settingsMap;
|
|
||||||
bool m_overrideFromPreset = false;
|
|
||||||
bool m_modified = false;
|
|
||||||
ImageProcessing::IImageObjectPtr m_img;
|
|
||||||
|
|
||||||
EditorTextureSetting(const AZ::Uuid& sourceTextureId);
|
|
||||||
EditorTextureSetting(const AZStd::string& texturePath);
|
|
||||||
~EditorTextureSetting() = default;
|
|
||||||
|
|
||||||
void InitFromPath(const AZStd::string& texturePath);
|
|
||||||
|
|
||||||
void SetIsOverrided();
|
|
||||||
|
|
||||||
void SetToPreset(const AZStd::string& presetName);
|
|
||||||
|
|
||||||
//Get the texture setting on certain platform
|
|
||||||
ImageProcessing::TextureSettings& GetMultiplatformTextureSetting(const AZStd::string& platform = "");
|
|
||||||
|
|
||||||
//Gets the final resolution/reduce/mip count for a texture on a certain platform
|
|
||||||
//@param wantedReduce indicates the reduce level that's preferred
|
|
||||||
//@return successfully get the value or not
|
|
||||||
bool GetFinalInfoForTextureOnPlatform(const AZStd::string& platform, AZ::u32 wantedReduce, ResolutionInfo& outResolutionInfo);
|
|
||||||
|
|
||||||
//Refresh the mip setting when the mip map setting is enabled/disabled.
|
|
||||||
//@return whether the mipmap is enabled or not.
|
|
||||||
bool RefreshMipSetting(bool enableMip);
|
|
||||||
|
|
||||||
//Propagate non platform specific settings from the first setting to all the settings stored in m_settingsMap
|
|
||||||
void PropagateCommonSettings();
|
|
||||||
|
|
||||||
//Returns a list of calculated final resolution info based on different base reduce levels
|
|
||||||
AZStd::list<ResolutionInfo> GetResolutionInfo(AZStd::string platform, AZ::u32& minReduce, AZ::u32& maxReduce);
|
|
||||||
|
|
||||||
//Returns a list of calculated final resolution info based on different mipmap levels
|
|
||||||
AZStd::list<ResolutionInfo> GetResolutionInfoForMipmap(AZStd::string platform);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ImageProcessingEditorInteralNotifications
|
|
||||||
: public AZ::EBusTraits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// EBusTraits overrides
|
|
||||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
|
||||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//! Used to inform the settings changed across widgets
|
|
||||||
virtual void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using EditorInternalNotificationBus = AZ::EBus<ImageProcessingEditorInteralNotifications>;
|
|
||||||
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "ImagePopup.h"
|
|
||||||
#include <Source/Editor/ui_ImagePopup.h>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPixmap>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
ImagePopup::ImagePopup(QImage previewImage, QWidget* parent /*= nullptr*/)
|
|
||||||
: QDialog(parent, Qt::Dialog | Qt::FramelessWindowHint | Qt::Popup)
|
|
||||||
, m_ui(new Ui::ImagePopup)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
m_previewImage = previewImage;
|
|
||||||
|
|
||||||
if (!m_previewImage.isNull())
|
|
||||||
{
|
|
||||||
int height = previewImage.height();
|
|
||||||
int width = previewImage.width();
|
|
||||||
|
|
||||||
this->resize(width, height);
|
|
||||||
m_ui->imageLabel->resize(width, height);
|
|
||||||
QPixmap pixmap = QPixmap::fromImage(previewImage);
|
|
||||||
m_ui->imageLabel->setPixmap(pixmap);
|
|
||||||
|
|
||||||
this->setFocusPolicy(Qt::FocusPolicy::NoFocus);
|
|
||||||
this->setModal(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagePopup::~ImagePopup()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_ImagePopup.cpp>
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QDialog>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <AzQtComponents/Components/StyledDialog.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class ImagePopup;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class ImagePopup
|
|
||||||
: public QDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
AZ_CLASS_ALLOCATOR(ImagePopup, AZ::SystemAllocator, 0);
|
|
||||||
explicit ImagePopup(QImage previewImage, QWidget* parent = nullptr);
|
|
||||||
~ImagePopup();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<Ui::ImagePopup> m_ui;
|
|
||||||
QImage m_previewImage;
|
|
||||||
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>ImagePopup</class>
|
|
||||||
<widget class="QDialog" name="ImagePopup">
|
|
||||||
<property name="windowModality">
|
|
||||||
<enum>Qt::WindowModal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>300</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="imageLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "MipmapSettingWidget.h"
|
|
||||||
#include <Source/Editor/ui_MipmapSettingWidget.h>
|
|
||||||
|
|
||||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
|
||||||
#include <AzCore/Serialization/SerializeContext.h>
|
|
||||||
#include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx>
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QSizePolicy>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
MipmapSettingWidget::MipmapSettingWidget(EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_ui(new Ui::MipmapSettingWidget)
|
|
||||||
, m_textureSetting(&textureSetting)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
|
|
||||||
|
|
||||||
AZ::SerializeContext* serializeContext = nullptr;
|
|
||||||
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
|
||||||
AZ_Assert(serializeContext, "Serialization context not available");
|
|
||||||
|
|
||||||
m_ui->propertyEditor->SetAutoResizeLabels(true);
|
|
||||||
m_ui->propertyEditor->Setup(serializeContext, this, true, 250);
|
|
||||||
|
|
||||||
m_ui->propertyEditor->ClearInstances();
|
|
||||||
TextureSettings* instance = &m_textureSetting->GetMultiplatformTextureSetting();
|
|
||||||
const AZ::Uuid& classId = AZ::SerializeTypeInfo<TextureSettings>::GetUuid(instance);
|
|
||||||
m_ui->propertyEditor->AddInstance(instance, classId);
|
|
||||||
m_ui->propertyEditor->InvalidateAll();
|
|
||||||
m_ui->propertyEditor->ExpandAll();
|
|
||||||
|
|
||||||
RefreshUI();
|
|
||||||
|
|
||||||
EditorInternalNotificationBus::Handler::BusConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
MipmapSettingWidget::~MipmapSettingWidget()
|
|
||||||
{
|
|
||||||
EditorInternalNotificationBus::Handler::BusDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MipmapSettingWidget::RefreshUI()
|
|
||||||
{
|
|
||||||
TextureSettings& texSetting = m_textureSetting->GetMultiplatformTextureSetting();
|
|
||||||
const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(texSetting.m_preset);
|
|
||||||
if (preset == nullptr || preset->m_mipmapSetting == nullptr)
|
|
||||||
{
|
|
||||||
m_ui->enableCheckBox->setCheckState(Qt::CheckState::Unchecked);
|
|
||||||
m_ui->enableCheckBox->setEnabled(false);
|
|
||||||
m_ui->propertyEditor->hide();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool showMipMap = texSetting.m_enableMipmap;
|
|
||||||
m_ui->enableCheckBox->setEnabled(true);
|
|
||||||
m_ui->enableCheckBox->setCheckState(showMipMap ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
|
||||||
QObject::connect(m_ui->enableCheckBox, &QCheckBox::clicked, this, &MipmapSettingWidget::OnCheckBoxStateChanged);
|
|
||||||
if (showMipMap)
|
|
||||||
{
|
|
||||||
m_ui->propertyEditor->show();
|
|
||||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->propertyEditor->hide();
|
|
||||||
this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_ui->propertyEditor->InvalidateValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MipmapSettingWidget::OnCheckBoxStateChanged(bool checked)
|
|
||||||
{
|
|
||||||
bool finalChecked = m_textureSetting->RefreshMipSetting(checked);
|
|
||||||
|
|
||||||
if (finalChecked)
|
|
||||||
{
|
|
||||||
m_ui->propertyEditor->show();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->propertyEditor->hide();
|
|
||||||
}
|
|
||||||
EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, BuilderSettingManager::s_defaultPlatform);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MipmapSettingWidget::AfterPropertyModified(AzToolsFramework::InstanceDataNode* /*pNode*/)
|
|
||||||
{
|
|
||||||
//Only the first texture setting reflected is changed, we need to propagate the change to every texture settings.
|
|
||||||
m_textureSetting->PropagateCommonSettings();
|
|
||||||
m_ui->propertyEditor->InvalidateValues();
|
|
||||||
EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, BuilderSettingManager::s_defaultPlatform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MipmapSettingWidget::OnEditorSettingsChanged(bool needRefresh, const AZStd::string& /*platform*/)
|
|
||||||
{
|
|
||||||
if (needRefresh)
|
|
||||||
{
|
|
||||||
RefreshUI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_MipmapSettingWidget.cpp>
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QMainWindow>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
|
||||||
#include <Source/Editor/EditorCommon.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class MipmapSettingWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class MipmapSettingWidget
|
|
||||||
: public QWidget
|
|
||||||
, public AzToolsFramework::IPropertyEditorNotify
|
|
||||||
, protected EditorInternalNotificationBus::Handler
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
AZ_CLASS_ALLOCATOR(MipmapSettingWidget, AZ::SystemAllocator, 0);
|
|
||||||
explicit MipmapSettingWidget(EditorTextureSetting& textureSetting, QWidget* parent = nullptr);
|
|
||||||
~MipmapSettingWidget();
|
|
||||||
|
|
||||||
//IPropertyEditorNotify Interface
|
|
||||||
void BeforePropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
|
|
||||||
void AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) override;
|
|
||||||
void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
|
|
||||||
void SetPropertyEditingComplete([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
|
|
||||||
void SealUndoStack() override {}
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void OnCheckBoxStateChanged(bool checked);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
//EditorInternalNotificationBus
|
|
||||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RefreshUI();
|
|
||||||
QScopedPointer<Ui::MipmapSettingWidget> m_ui;
|
|
||||||
EditorTextureSetting* m_textureSetting;
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>MipmapSettingWidget</class>
|
|
||||||
<widget class="QWidget" name="MipmapSettingWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>583</width>
|
|
||||||
<height>489</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Mipmap Settings</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="enableCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="AzToolsFramework::ReflectedPropertyEditor" name="propertyEditor">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>1</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>AzToolsFramework::ReflectedPropertyEditor</class>
|
|
||||||
<extends>QFrame</extends>
|
|
||||||
<header location="global">AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "PresetInfoPopup.h"
|
|
||||||
#include <Source/Editor/ui_PresetInfoPopup.h>
|
|
||||||
#include <BuilderSettings/PresetSettings.h>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
// Help functions to convert enum to strings
|
|
||||||
static const char* RGBWeightToString(RGBWeight weight)
|
|
||||||
{
|
|
||||||
static const char* RGBWeightNames[] = { "uniform", "luminance", "ciexyz" };
|
|
||||||
AZ_Assert(weight <= RGBWeight::ciexyz, "Invalid RGBWeight!");
|
|
||||||
return RGBWeightNames[(int)weight];
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* ColorSpaceToString(ColorSpace colorSpace)
|
|
||||||
{
|
|
||||||
static const char* colorSpaceNames[] = { "linear", "sRGB", "auto" };
|
|
||||||
AZ_Assert(colorSpace <= ColorSpace::autoSelect, "Invalid ColorSpace!");
|
|
||||||
return colorSpaceNames[(int)colorSpace];
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* MipGenTypeToString(MipGenType mipGenType)
|
|
||||||
{
|
|
||||||
static const char* mipGenTypeNames[] = { "point", "average", "linear" , "bilinear" , "gaussian" , "blackmanHarris", "kaiserSinc" };
|
|
||||||
AZ_Assert(mipGenType <= MipGenType::kaiserSinc, "Invalid MipGenType!");
|
|
||||||
return mipGenTypeNames[(int)mipGenType];
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* CubemapFilterTypeToString(CubemapFilterType cubemapFilterType)
|
|
||||||
{
|
|
||||||
static const char* cubemapFilterTypeNames[] = { "disc", "cone", "cosine" , "gaussian" , "cosine power" , "ggx" };
|
|
||||||
AZ_Assert(cubemapFilterType <= CubemapFilterType::ggx, "Invalid CubemapFilterType!");
|
|
||||||
return cubemapFilterTypeNames[(int)cubemapFilterType];
|
|
||||||
}
|
|
||||||
|
|
||||||
PresetInfoPopup::PresetInfoPopup(const PresetSettings* presetSettings, QWidget* parent /*= nullptr*/)
|
|
||||||
: AzQtComponents::StyledDialog(parent, Qt::Dialog | Qt::Popup)
|
|
||||||
, m_ui(new Ui::PresetInfoPopup)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
RefreshPresetInfoLabel(presetSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
PresetInfoPopup::~PresetInfoPopup()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
void PresetInfoPopup::RefreshPresetInfoLabel(const PresetSettings* presetSettings)
|
|
||||||
{
|
|
||||||
|
|
||||||
QString presetInfoText = "";
|
|
||||||
if (!presetSettings)
|
|
||||||
{
|
|
||||||
presetInfoText = "Invalid Preset!";
|
|
||||||
m_ui->infoLabel->setText(presetInfoText);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
presetInfoText += QString("UUID: %1\n").arg(presetSettings->m_uuid.ToString<AZStd::string>().c_str());
|
|
||||||
presetInfoText += QString("Name: %1\n").arg(presetSettings->m_name.c_str());
|
|
||||||
presetInfoText += QString("RGB Weight: %1\n").arg(RGBWeightToString(presetSettings->m_rgbWeight));
|
|
||||||
presetInfoText += QString("Source ColorSpace: %1\n").arg(ColorSpaceToString(presetSettings->m_srcColorSpace));
|
|
||||||
presetInfoText += QString("Destination ColorSpace: %1\n").arg(ColorSpaceToString(presetSettings->m_destColorSpace));
|
|
||||||
presetInfoText += QString("FileMasks: ");
|
|
||||||
int i = 0;
|
|
||||||
for (auto& mask : presetSettings->m_fileMasks)
|
|
||||||
{
|
|
||||||
presetInfoText += i > 0 ? ", " : "";
|
|
||||||
presetInfoText += mask.c_str();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
presetInfoText += "\n";
|
|
||||||
presetInfoText += QString("Suppress Engine Reduce: %1\n").arg(presetSettings->m_suppressEngineReduce ? "True" : "False");
|
|
||||||
presetInfoText += QString("Discard Alpha: %1\n").arg(presetSettings->m_discardAlpha ? "True" : "False");
|
|
||||||
presetInfoText += QString("Is Power Of 2: %1\n").arg(presetSettings->m_isPowerOf2 ? "True" : "False");
|
|
||||||
presetInfoText += QString("Is Color Chart: %1\n").arg(presetSettings->m_isColorChart ? "True" : "False");
|
|
||||||
presetInfoText += QString("High Pass Mip: %1\n").arg(presetSettings->m_highPassMip);
|
|
||||||
presetInfoText += QString("Gloss From Normal: %1\n").arg(presetSettings->m_glossFromNormals);
|
|
||||||
presetInfoText += QString("Use Legacy Gloss: %1\n").arg(presetSettings->m_isLegacyGloss ? "True" : "False");
|
|
||||||
presetInfoText += QString("Mip Re-normalize: %1\n").arg(presetSettings->m_isMipRenormalize ? "True" : "False");
|
|
||||||
presetInfoText += QString("Streamable Mips Number: %1\n").arg(presetSettings->m_numStreamableMips);
|
|
||||||
presetInfoText += QString("Swizzle: %1\n").arg(presetSettings->m_swizzle.c_str());
|
|
||||||
if (presetSettings->m_cubemapSetting)
|
|
||||||
{
|
|
||||||
presetInfoText += QString("[Cubemap Settings]\n");
|
|
||||||
presetInfoText += QString("Filter: %1\n").arg(CubemapFilterTypeToString(presetSettings->m_cubemapSetting->m_filter));
|
|
||||||
presetInfoText += QString("Angle: %1\n").arg(presetSettings->m_cubemapSetting->m_angle);
|
|
||||||
presetInfoText += QString("Mip Angle: %1\n").arg(presetSettings->m_cubemapSetting->m_mipAngle);
|
|
||||||
presetInfoText += QString("Mip Slope: %1\n").arg(presetSettings->m_cubemapSetting->m_mipSlope);
|
|
||||||
presetInfoText += QString("Edge Fixup: %1\n").arg(presetSettings->m_cubemapSetting->m_edgeFixup);
|
|
||||||
presetInfoText += QString("Generate Diff: %1\n").arg(presetSettings->m_cubemapSetting->m_generateDiff ? "True" : "False");
|
|
||||||
presetInfoText += QString("Diffuse Probe Preset: %1\n").arg(presetSettings->m_cubemapSetting->m_diffuseGenPreset.ToString<AZStd::string>().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presetSettings->m_mipmapSetting)
|
|
||||||
{
|
|
||||||
presetInfoText += QString("[MipMapSetting]\n");
|
|
||||||
presetInfoText += QString("Type: %1\n").arg(MipGenTypeToString(presetSettings->m_mipmapSetting->m_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->infoLabel->setText(presetInfoText);
|
|
||||||
}
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_PresetInfoPopup.cpp>
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QDialog>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <AzQtComponents/Components/StyledDialog.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class PresetSettings;
|
|
||||||
}
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class PresetInfoPopup;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class PresetInfoPopup
|
|
||||||
: public AzQtComponents::StyledDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
AZ_CLASS_ALLOCATOR(PresetInfoPopup, AZ::SystemAllocator, 0);
|
|
||||||
explicit PresetInfoPopup(const ImageProcessing::PresetSettings* preset, QWidget* parent = nullptr);
|
|
||||||
~PresetInfoPopup();
|
|
||||||
void RefreshPresetInfoLabel(const ImageProcessing::PresetSettings* presetSettings);
|
|
||||||
private:
|
|
||||||
QScopedPointer<Ui::PresetInfoPopup> m_ui;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>PresetInfoPopup</class>
|
|
||||||
<widget class="QDialog" name="PresetInfoPopup">
|
|
||||||
<property name="windowModality">
|
|
||||||
<enum>Qt::NonModal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>300</width>
|
|
||||||
<height>400</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Preset Info</string>
|
|
||||||
</property>
|
|
||||||
<property name="sizeGripEnabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="modal">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QVBoxLayout" name="layout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="infoLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::NoFrame</enum>
|
|
||||||
</property>
|
|
||||||
<property name="frameShadow">
|
|
||||||
<enum>QFrame::Plain</enum>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "ResolutionSettingItemWidget.h"
|
|
||||||
#include <Source/Editor/ui_ResolutionSettingItemWidget.h>
|
|
||||||
#include <BuilderSettings/PresetSettings.h>
|
|
||||||
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QSpinBox>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
|
|
||||||
ResolutionSettingItemWidget::ResolutionSettingItemWidget(ResoultionWidgetType type, QWidget* parent /*= nullptr*/)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_ui(new Ui::ResolutionSettingItemWidget)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
m_type = type;
|
|
||||||
|
|
||||||
EditorInternalNotificationBus::Handler::BusConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolutionSettingItemWidget::~ResolutionSettingItemWidget()
|
|
||||||
{
|
|
||||||
EditorInternalNotificationBus::Handler::BusDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::Init(AZStd::string platform, EditorTextureSetting* editorTextureSetting)
|
|
||||||
{
|
|
||||||
m_platform = platform;
|
|
||||||
m_editorTextureSetting = editorTextureSetting;
|
|
||||||
m_textureSetting = &m_editorTextureSetting->m_settingsMap[m_platform];
|
|
||||||
m_preset = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->m_preset, platform);
|
|
||||||
SetupResolutionInfo();
|
|
||||||
RefreshUI();
|
|
||||||
if (m_type == ResoultionWidgetType::TexturePropety)
|
|
||||||
{
|
|
||||||
m_ui->formatLabel->show();
|
|
||||||
m_ui->formatComboBox->hide();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->formatLabel->hide();
|
|
||||||
m_ui->formatComboBox->show();
|
|
||||||
QObject::connect(m_ui->formatComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ResolutionSettingItemWidget::OnChangeFormat);
|
|
||||||
}
|
|
||||||
QObject::connect(m_ui->downResSpinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &ResolutionSettingItemWidget::OnChangeDownRes);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::RefreshUI()
|
|
||||||
{
|
|
||||||
m_ui->platformLabel->setText(EditorHelper::ToReadablePlatformString(m_platform).c_str());
|
|
||||||
|
|
||||||
m_ui->downResSpinBox->setRange(m_minReduce, m_maxReduce);
|
|
||||||
int clampedReduce = AZStd::min<int>(AZStd::max<int>(m_textureSetting->m_sizeReduceLevel, s_MinReduceLevel), s_MaxReduceLevel);
|
|
||||||
auto it = m_resolutionInfos.begin();
|
|
||||||
it = AZStd::next(it, clampedReduce);
|
|
||||||
m_ui->downResSpinBox->setValue(it->reduce);
|
|
||||||
|
|
||||||
QString finalResolution;
|
|
||||||
|
|
||||||
if (it->arrayCount > 1)
|
|
||||||
{
|
|
||||||
finalResolution = QString("%1 x %2 x %3").arg(QString::number(it->width), QString::number(it->height), QString::number(it->arrayCount));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
finalResolution = QString("%1 x %2").arg(QString::number(it->width), QString::number(it->height));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->sizeLabel->setText(finalResolution);
|
|
||||||
|
|
||||||
QString finalFormat = GetFinalFormat(m_textureSetting->m_preset);
|
|
||||||
if (m_type == ResoultionWidgetType::TexturePropety)
|
|
||||||
{
|
|
||||||
m_ui->formatLabel->setText(finalFormat);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetupFormatComboBox();
|
|
||||||
m_ui->formatComboBox->setCurrentText(finalFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::SetupResolutionInfo()
|
|
||||||
{
|
|
||||||
m_resolutionInfos = m_editorTextureSetting->GetResolutionInfo(m_platform, m_minReduce, m_maxReduce);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::OnChangeDownRes(int downRes)
|
|
||||||
{
|
|
||||||
if ((unsigned int)downRes >= m_minReduce && (unsigned int)downRes <= m_maxReduce)
|
|
||||||
{
|
|
||||||
m_textureSetting->m_sizeReduceLevel = downRes;
|
|
||||||
RefreshUI();
|
|
||||||
EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, m_platform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ResolutionSettingItemWidget::GetFinalFormat([[maybe_unused]] const AZ::Uuid& presetId)
|
|
||||||
{
|
|
||||||
if (m_preset && m_preset->m_pixelFormat >=0 && m_preset->m_pixelFormat < ePixelFormat_Count)
|
|
||||||
{
|
|
||||||
return EditorHelper::s_PixelFormatString[m_preset->m_pixelFormat];
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::SetupFormatComboBox()
|
|
||||||
{
|
|
||||||
m_ui->formatComboBox->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::OnChangeFormat([[maybe_unused]] int index)
|
|
||||||
{
|
|
||||||
bool oldState = m_ui->formatComboBox->blockSignals(true);
|
|
||||||
m_ui->formatComboBox->blockSignals(oldState);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolutionSettingItemWidget::OnEditorSettingsChanged(bool needRefresh, const AZStd::string& /*platform*/)
|
|
||||||
{
|
|
||||||
if (needRefresh)
|
|
||||||
{
|
|
||||||
m_preset = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->m_preset, m_platform);
|
|
||||||
SetupResolutionInfo();
|
|
||||||
RefreshUI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_ResolutionSettingItemWidget.cpp>
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QWidget>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <Editor/EditorCommon.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
class PresetSettings;
|
|
||||||
}
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class ResolutionSettingItemWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
enum class ResoultionWidgetType
|
|
||||||
{
|
|
||||||
TexturePipeline, //Fully editable
|
|
||||||
TexturePropety, //Only DownRes is editable
|
|
||||||
};
|
|
||||||
|
|
||||||
class ResolutionSettingItemWidget
|
|
||||||
: public QWidget
|
|
||||||
, EditorInternalNotificationBus::Handler
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
AZ_CLASS_ALLOCATOR(ResolutionSettingItemWidget, AZ::SystemAllocator, 0);
|
|
||||||
explicit ResolutionSettingItemWidget(ResoultionWidgetType type, QWidget* parent = nullptr);
|
|
||||||
~ResolutionSettingItemWidget();
|
|
||||||
void Init(AZStd::string platform, EditorTextureSetting* editorTextureSetting);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
void OnChangeDownRes(int downRes);
|
|
||||||
void OnChangeFormat(int index);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
//EditorInternalNotificationBus
|
|
||||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void SetupFormatComboBox();
|
|
||||||
void SetupResolutionInfo();
|
|
||||||
void RefreshUI();
|
|
||||||
QString GetFinalFormat(const AZ::Uuid& presetId);
|
|
||||||
|
|
||||||
QScopedPointer<Ui::ResolutionSettingItemWidget> m_ui;
|
|
||||||
ResoultionWidgetType m_type;
|
|
||||||
AZStd::string m_platform;
|
|
||||||
ImageProcessing::TextureSettings* m_textureSetting;
|
|
||||||
EditorTextureSetting* m_editorTextureSetting;
|
|
||||||
const ImageProcessing::PresetSettings* m_preset;
|
|
||||||
//Cached list of calculated final resolution info based on different reduce levels
|
|
||||||
AZStd::list<ResolutionInfo> m_resolutionInfos;
|
|
||||||
//Final reduce level range
|
|
||||||
unsigned int m_maxReduce;
|
|
||||||
unsigned int m_minReduce;
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>ResolutionSettingItemWidget</class>
|
|
||||||
<widget class="QWidget" name="ResolutionSettingItemWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>20</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>400</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>400</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<property name="layoutDirection">
|
|
||||||
<enum>Qt::LeftToRight</enum>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="sizeConstraint">
|
|
||||||
<enum>QLayout::SetDefaultConstraint</enum>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="platformLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Provo</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QSpinBox" name="downResSpinBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>50</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>50</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="sizeLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>100</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>100</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>TextLabel</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="formatLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>80</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>80</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>TextLabel</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="formatComboBox"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "ResolutionSettingWidget.h"
|
|
||||||
#include <Source/Editor/ui_ResolutionSettingWidget.h>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
ResolutionSettingWidget::ResolutionSettingWidget(ResoultionWidgetType type, EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_ui(new Ui::ResolutionSettingWidget)
|
|
||||||
, m_textureSetting(&textureSetting)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
m_type = type;
|
|
||||||
|
|
||||||
//Put default platform in the first row
|
|
||||||
ResolutionSettingItemWidget* item = new ResolutionSettingItemWidget(ResoultionWidgetType::TexturePropety, this);
|
|
||||||
item->Init(BuilderSettingManager::s_defaultPlatform, m_textureSetting);
|
|
||||||
m_ui->listLayout->addWidget(item);
|
|
||||||
|
|
||||||
//Add the other platforms in the list
|
|
||||||
for (auto& it : m_textureSetting->m_settingsMap)
|
|
||||||
{
|
|
||||||
AZStd::string platform = it.first;
|
|
||||||
if (platform != BuilderSettingManager::s_defaultPlatform)
|
|
||||||
{
|
|
||||||
ResolutionSettingItemWidget* item2 = new ResolutionSettingItemWidget(ResoultionWidgetType::TexturePropety, this);
|
|
||||||
item2->Init(platform, m_textureSetting);
|
|
||||||
m_ui->listLayout->addWidget(item2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tooltips
|
|
||||||
m_ui->downResLabel->setToolTip(QString("Adjust the resolution based on the target platform. \
|
|
||||||
Use this setting to preserve the resolution of a source file even though it appears smaller in the game. \
|
|
||||||
Select 0 to preserve the original size or 5 for the maximum reduction."));
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolutionSettingWidget::~ResolutionSettingWidget()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_ResolutionSettingWidget.cpp>
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QWidget>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <Source/Editor/ResolutionSettingItemWidget.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class ResolutionSettingWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class ResolutionSettingWidget
|
|
||||||
: public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
AZ_CLASS_ALLOCATOR(ResolutionSettingWidget, AZ::SystemAllocator, 0);
|
|
||||||
explicit ResolutionSettingWidget(ResoultionWidgetType type, EditorTextureSetting& texureSetting, QWidget* parent = nullptr);
|
|
||||||
~ResolutionSettingWidget();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<Ui::ResolutionSettingWidget> m_ui;
|
|
||||||
ResoultionWidgetType m_type;
|
|
||||||
EditorTextureSetting* m_textureSetting;
|
|
||||||
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>ResolutionSettingWidget</class>
|
|
||||||
<widget class="QWidget" name="ResolutionSettingWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>550</width>
|
|
||||||
<height>300</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="listLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="sizeConstraint">
|
|
||||||
<enum>QLayout::SetDefaultConstraint</enum>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Platform</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="downResLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>50</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>DownRes</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>100</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Size</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>80</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Format</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,199 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "TexturePresetSelectionWidget.h"
|
|
||||||
#include <Source/Editor/ui_TexturePresetSelectionWidget.h>
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <AzFramework/StringFunc/StringFunc.h>
|
|
||||||
#include <BuilderSettings/PresetSettings.h>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
TexturePresetSelectionWidget::TexturePresetSelectionWidget(EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_ui(new Ui::TexturePresetSelectionWidget)
|
|
||||||
, m_textureSetting(&textureSetting)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
|
|
||||||
// Add presets into combo box
|
|
||||||
m_presetList.clear();
|
|
||||||
auto& presetFilterMap = BuilderSettingManager::Instance()->GetPresetFilterMap();
|
|
||||||
|
|
||||||
AZStd::set<AZStd::string> noFilterPresetList;
|
|
||||||
|
|
||||||
// Check if there is any filtered preset list first
|
|
||||||
for(auto& presetFilter : presetFilterMap)
|
|
||||||
{
|
|
||||||
if (presetFilter.first.empty())
|
|
||||||
{
|
|
||||||
noFilterPresetList = presetFilter.second;
|
|
||||||
}
|
|
||||||
else if (IsMatchingWithFileMask(m_textureSetting->m_textureName, presetFilter.first))
|
|
||||||
{
|
|
||||||
for(const AZStd::string& presetName : presetFilter.second)
|
|
||||||
{
|
|
||||||
m_presetList.insert(presetName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If no filtered preset list available or should list all presets, use non-filter list
|
|
||||||
if (m_presetList.size() == 0 || m_listAllPresets)
|
|
||||||
{
|
|
||||||
m_presetList = noFilterPresetList;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const AZStd::string& presetName, m_presetList)
|
|
||||||
{
|
|
||||||
m_ui->presetComboBox->addItem(QString(presetName.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set current preset
|
|
||||||
const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset;
|
|
||||||
const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset);
|
|
||||||
|
|
||||||
if (presetSetting)
|
|
||||||
{
|
|
||||||
m_ui->presetComboBox->setCurrentText(presetSetting->m_name.c_str());
|
|
||||||
QObject::connect(m_ui->presetComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TexturePresetSelectionWidget::OnChangePreset);
|
|
||||||
|
|
||||||
// Suppress engine reduction checkbox
|
|
||||||
m_ui->serCheckBox->setCheckState(m_textureSetting->GetMultiplatformTextureSetting().m_suppressEngineReduce ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
|
||||||
|
|
||||||
SetCheckBoxReadOnly(m_ui->serCheckBox, presetSetting->m_suppressEngineReduce);
|
|
||||||
QObject::connect(m_ui->serCheckBox, &QCheckBox::clicked, this, &TexturePresetSelectionWidget::OnCheckBoxStateChanged);
|
|
||||||
|
|
||||||
// Set convention label
|
|
||||||
SetPresetConvention(presetSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset btn
|
|
||||||
QObject::connect(m_ui->resetBtn, &QPushButton::clicked, this, &TexturePresetSelectionWidget::OnRestButton);
|
|
||||||
|
|
||||||
// PresetInfo btn
|
|
||||||
QObject::connect(m_ui->infoBtn, &QPushButton::clicked, this, &TexturePresetSelectionWidget::OnPresetInfoButton);
|
|
||||||
|
|
||||||
// Tooltips
|
|
||||||
m_ui->activeFileConventionLabel->setToolTip(QString("Displays the supported naming convention for the selected preset."));
|
|
||||||
m_ui->presetComboBox->setToolTip(QString("Choose a preset to update the preview and other properties."));
|
|
||||||
m_ui->resetBtn->setToolTip(QString("Reset values to current preset defaults."));
|
|
||||||
m_ui->serCheckBox->setToolTip(QString("Preserves the original size. Use this setting for textures that include text."));
|
|
||||||
m_ui->infoBtn->setToolTip(QString("Show detail properties of the current preset"));
|
|
||||||
|
|
||||||
EditorInternalNotificationBus::Handler::BusConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
TexturePresetSelectionWidget::~TexturePresetSelectionWidget()
|
|
||||||
{
|
|
||||||
EditorInternalNotificationBus::Handler::BusDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePresetSelectionWidget::OnCheckBoxStateChanged(bool checked)
|
|
||||||
{
|
|
||||||
for (auto& it : m_textureSetting->m_settingsMap)
|
|
||||||
{
|
|
||||||
it.second.m_suppressEngineReduce = checked;
|
|
||||||
}
|
|
||||||
m_textureSetting->SetIsOverrided();
|
|
||||||
EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, BuilderSettingManager::s_defaultPlatform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePresetSelectionWidget::OnRestButton()
|
|
||||||
{
|
|
||||||
m_textureSetting->SetToPreset(AZStd::string(m_ui->presetComboBox->currentText().toUtf8().data()));
|
|
||||||
EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, true, BuilderSettingManager::s_defaultPlatform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePresetSelectionWidget::OnChangePreset(int index)
|
|
||||||
{
|
|
||||||
QString text = m_ui->presetComboBox->itemText(index);
|
|
||||||
m_textureSetting->SetToPreset(AZStd::string(text.toUtf8().data()));
|
|
||||||
EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, true, BuilderSettingManager::s_defaultPlatform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageProcessingEditor::TexturePresetSelectionWidget::OnPresetInfoButton()
|
|
||||||
{
|
|
||||||
const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset;
|
|
||||||
const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset);
|
|
||||||
m_presetPopup.reset(new PresetInfoPopup(presetSetting, this));
|
|
||||||
m_presetPopup->installEventFilter(this);
|
|
||||||
m_presetPopup->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePresetSelectionWidget::OnEditorSettingsChanged(bool needRefresh, const AZStd::string& /*platform*/)
|
|
||||||
{
|
|
||||||
if (needRefresh)
|
|
||||||
{
|
|
||||||
bool oldState = m_ui->serCheckBox->blockSignals(true);
|
|
||||||
m_ui->serCheckBox->setChecked(m_textureSetting->GetMultiplatformTextureSetting().m_suppressEngineReduce);
|
|
||||||
// If the preset's SER is true, texture setting should not override
|
|
||||||
const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset;
|
|
||||||
const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset);
|
|
||||||
if (presetSetting)
|
|
||||||
{
|
|
||||||
SetCheckBoxReadOnly(m_ui->serCheckBox, presetSetting->m_suppressEngineReduce);
|
|
||||||
SetPresetConvention(presetSetting);
|
|
||||||
// If there is preset info dialog open, update the text
|
|
||||||
if (m_presetPopup && m_presetPopup->isVisible())
|
|
||||||
{
|
|
||||||
m_presetPopup->RefreshPresetInfoLabel(presetSetting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_ui->serCheckBox->blockSignals(oldState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TexturePresetSelectionWidget::IsMatchingWithFileMask(const AZStd::string& filename, const AZStd::string& fileMask)
|
|
||||||
{
|
|
||||||
if (fileMask.empty())
|
|
||||||
{
|
|
||||||
// Will not match with empty string
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Extract the file name and compare if it ends with file mask or not
|
|
||||||
AZStd::string filenameNoExt;
|
|
||||||
AzFramework::StringFunc::Path::GetFileName(filename.c_str(), filenameNoExt);
|
|
||||||
return filenameNoExt.length() >= fileMask.length() && filenameNoExt.compare(filenameNoExt.length() - fileMask.length(), fileMask.length(), fileMask) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageProcessingEditor::TexturePresetSelectionWidget::SetPresetConvention(const PresetSettings* presetSettings)
|
|
||||||
{
|
|
||||||
AZStd::string conventionText = "";
|
|
||||||
if (presetSettings)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
for (const PlatformName& filemask : presetSettings->m_fileMasks)
|
|
||||||
{
|
|
||||||
conventionText += i > 0 ? " " + filemask : filemask;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_ui->conventionLabel->setText(QString(conventionText.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageProcessingEditor::TexturePresetSelectionWidget::SetCheckBoxReadOnly(QCheckBox* checkBox, bool readOnly)
|
|
||||||
{
|
|
||||||
checkBox->setAttribute(Qt::WA_TransparentForMouseEvents, readOnly);
|
|
||||||
checkBox->setFocusPolicy(readOnly ? Qt::NoFocus : Qt::StrongFocus);
|
|
||||||
checkBox->setEnabled(!readOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_TexturePresetSelectionWidget.cpp>
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QWidget>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <Source/BuilderSettings/BuilderSettingManager.h>
|
|
||||||
#include <Source/Editor/EditorCommon.h>
|
|
||||||
#include <Editor/PresetInfoPopup.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class QCheckBox;
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class TexturePresetSelectionWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class TexturePresetSelectionWidget
|
|
||||||
: public QWidget
|
|
||||||
, protected EditorInternalNotificationBus::Handler
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
AZ_CLASS_ALLOCATOR(TexturePresetSelectionWidget, AZ::SystemAllocator, 0);
|
|
||||||
explicit TexturePresetSelectionWidget(EditorTextureSetting& texureSetting, QWidget* parent = nullptr);
|
|
||||||
~TexturePresetSelectionWidget();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void OnCheckBoxStateChanged(bool checked);
|
|
||||||
void OnRestButton();
|
|
||||||
void OnChangePreset(int index);
|
|
||||||
void OnPresetInfoButton();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
//EditorInternalNotificationBus
|
|
||||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<Ui::TexturePresetSelectionWidget> m_ui;
|
|
||||||
AZStd::set<AZStd::string> m_presetList;
|
|
||||||
EditorTextureSetting* m_textureSetting;
|
|
||||||
QScopedPointer<PresetInfoPopup> m_presetPopup;
|
|
||||||
bool IsMatchingWithFileMask(const AZStd::string& filename, const AZStd::string& fileMask);
|
|
||||||
void SetPresetConvention(const ImageProcessing::PresetSettings* presetSettings);
|
|
||||||
void SetCheckBoxReadOnly(QCheckBox* checkBox, bool readOnly);
|
|
||||||
|
|
||||||
bool m_listAllPresets = true;
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>TexturePresetSelectionWidget</class>
|
|
||||||
<widget class="QWidget" name="TexturePresetSelectionWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>624</width>
|
|
||||||
<height>118</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLabel" name="conventionLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="activeFileConventionLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Active file conventions</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="titleLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Texture presets</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QComboBox" name="presetComboBox"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="activePresetLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Active preset</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QToolButton" name="resetBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normalon>:/Reset.png</normalon>
|
|
||||||
</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QCheckBox" name="serCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Suppress spec reduction</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="3">
|
|
||||||
<widget class="QToolButton" name="infoBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normalon>:/info.png</normalon>
|
|
||||||
</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>16</width>
|
|
||||||
<height>16</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources>
|
|
||||||
<include location="../../../Assets/Editor/Resources.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,639 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "TexturePreviewWidget.h"
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <ImageProcessing/ImageObject.h>
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QSize>
|
|
||||||
#include <QPoint>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QPainter>
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QColor>
|
|
||||||
#include <QEvent>
|
|
||||||
#include <QKeyEvent>
|
|
||||||
#include <QApplicationStateChangeEvent>
|
|
||||||
#include <QString>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QWidgetAction>
|
|
||||||
#include <AzQtComponents/Components/Widgets/PushButton.h>
|
|
||||||
#include <Source/Editor/ui_TexturePreviewWidget.h>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
using namespace ImageProcessing;
|
|
||||||
|
|
||||||
TexturePreviewWidget::TexturePreviewWidget(EditorTextureSetting& texureSetting, QWidget* parent /*= nullptr*/)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_ui(new Ui::TexturePreviewWidget)
|
|
||||||
, m_textureSetting(&texureSetting)
|
|
||||||
{
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
|
|
||||||
m_platform = BuilderSettingManager::s_defaultPlatform;
|
|
||||||
// For now, only provide preview for default platform
|
|
||||||
m_previewConverter = AZStd::make_unique<ImageProcessing::ImagePreview>(m_textureSetting->m_fullPath, &m_textureSetting->GetMultiplatformTextureSetting());
|
|
||||||
|
|
||||||
m_updateTimer = new QTimer(this);
|
|
||||||
connect(m_updateTimer, &QTimer::timeout, this, &TexturePreviewWidget::UpdatePreview);
|
|
||||||
m_updateTimer->setSingleShot(false);
|
|
||||||
|
|
||||||
m_ui->infoLayer->setAttribute(Qt::WA_NoSystemBackground);
|
|
||||||
m_ui->mipLevelLabel->setAttribute(Qt::WA_NoSystemBackground);
|
|
||||||
m_ui->imageSizeLabel->setAttribute(Qt::WA_NoSystemBackground);
|
|
||||||
m_ui->fileSizeLabel->setAttribute(Qt::WA_NoSystemBackground);
|
|
||||||
|
|
||||||
// Setup preview mode combo box
|
|
||||||
static const QString previewModeString[] = { "RGB",
|
|
||||||
"R",
|
|
||||||
"G",
|
|
||||||
"B",
|
|
||||||
"Alpha",
|
|
||||||
"RGBA" };
|
|
||||||
|
|
||||||
for (int i = 0; i < (int)PreviewMode::Count; i ++)
|
|
||||||
{
|
|
||||||
m_ui->previewComboBox->addItem(previewModeString[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSize size = m_ui->imageLabel->size();
|
|
||||||
m_imageLabelSize = aznumeric_cast<float>(size.width());
|
|
||||||
|
|
||||||
SetUpResolutionInfo();
|
|
||||||
RefreshUI(true);
|
|
||||||
|
|
||||||
QObject::connect(m_ui->previewCheckBox, &QCheckBox::clicked, this, &TexturePreviewWidget::OnTiledChanged);
|
|
||||||
QObject::connect(m_ui->nextMipBtn, &QPushButton::clicked, this, &TexturePreviewWidget::OnNextMip);
|
|
||||||
QObject::connect(m_ui->prevMipBtn, &QPushButton::clicked, this, &TexturePreviewWidget::OnPrevMip);
|
|
||||||
QObject::connect(m_ui->previewComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TexturePreviewWidget::OnChangePreviewMode);
|
|
||||||
|
|
||||||
// Set up Refresh button
|
|
||||||
m_alwaysRefreshAction = new QAction("Always refresh preview", this);
|
|
||||||
m_alwaysRefreshAction->setCheckable(true);
|
|
||||||
m_alwaysRefreshAction->setChecked(m_alwaysRefreshPreview);
|
|
||||||
QObject::connect(m_alwaysRefreshAction, &QAction::triggered, this, &TexturePreviewWidget::OnAlwaysRefresh);
|
|
||||||
|
|
||||||
m_refreshPerClickAction = new QAction("Press to refresh preview", this);
|
|
||||||
m_refreshPerClickAction->setCheckable(true);
|
|
||||||
m_refreshPerClickAction->setChecked(!m_alwaysRefreshPreview);
|
|
||||||
QObject::connect(m_refreshPerClickAction, &QAction::triggered, this, &TexturePreviewWidget::OnRefreshPerClick);
|
|
||||||
|
|
||||||
QMenu* menu = new QMenu(this);
|
|
||||||
menu->addAction(m_alwaysRefreshAction);
|
|
||||||
menu->addAction(m_refreshPerClickAction);
|
|
||||||
|
|
||||||
m_ui->refreshBtn->setMenu(menu);
|
|
||||||
AzQtComponents::PushButton::applySmallIconStyle(m_ui->refreshBtn);
|
|
||||||
|
|
||||||
QObject::connect(m_ui->refreshBtn, &QPushButton::clicked, this, &TexturePreviewWidget::OnRefreshClicked);
|
|
||||||
m_alwaysRefreshIcon.addFile(QStringLiteral(":/refresh.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
||||||
m_refreshPerClickIcon.addFile(QStringLiteral(":/refresh-active.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
||||||
m_ui->refreshBtn->setIcon(m_alwaysRefreshIcon);
|
|
||||||
|
|
||||||
m_ui->busyLabel->SetBusyIconSize(16);
|
|
||||||
SetImageLabelText(QString(), false);
|
|
||||||
|
|
||||||
// Tooltips
|
|
||||||
m_ui->previewComboBox->setToolTip(QString("Preview the texture in different channels."));
|
|
||||||
m_ui->previewCheckBox->setToolTip(QString("Show or hide a 2x2 tiling of the texture."));
|
|
||||||
m_ui->hotkeyLabel->setToolTip(QString("Preview different texture states with keyboard shortcuts."));
|
|
||||||
m_ui->refreshBtn->setToolTip(QString("Provide different ways to refresh the preview. Click on the button to refresh manually."));
|
|
||||||
|
|
||||||
EditorInternalNotificationBus::Handler::BusConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
TexturePreviewWidget::~TexturePreviewWidget()
|
|
||||||
{
|
|
||||||
EditorInternalNotificationBus::Handler::BusDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
|
|
||||||
QSize size = m_ui->mainWidget->size();
|
|
||||||
m_ui->infoLayer->resize(size);
|
|
||||||
|
|
||||||
QSize imageSize = m_ui->imageLabel->size();
|
|
||||||
QPoint center = m_ui->mainWidget->rect().center();
|
|
||||||
m_ui->imageLabel->move(center - QPoint(imageSize.width() / 2, imageSize.height() / 2));
|
|
||||||
QSize busyLabelSize = m_ui->busyLabel->size();
|
|
||||||
m_ui->busyLabel->move(center - QPoint(busyLabelSize.width() + m_ui->imageLabel->sizeHint().width() / 2, busyLabelSize.width() / 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::SetUpResolutionInfo()
|
|
||||||
{
|
|
||||||
m_resolutionInfos = m_textureSetting->GetResolutionInfoForMipmap(m_platform);
|
|
||||||
m_mipCount = (unsigned int)m_resolutionInfos.size();
|
|
||||||
if (m_currentMipIndex > (int)m_mipCount)
|
|
||||||
{
|
|
||||||
m_currentMipIndex = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnEditorSettingsChanged([[maybe_unused]] bool needRefresh, const AZStd::string& platform)
|
|
||||||
{
|
|
||||||
// Only update the preview if there is any change in current platform
|
|
||||||
if (platform == m_platform)
|
|
||||||
{
|
|
||||||
SetUpResolutionInfo();
|
|
||||||
RefreshUI(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::RefreshUI(bool fullRefresh)
|
|
||||||
{
|
|
||||||
m_ui->mipLevelLabel->setText(QString("Mip %1").arg(QString::number(m_currentMipIndex)));
|
|
||||||
m_ui->previewCheckBox->setCheckState(m_previewTiled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
|
||||||
|
|
||||||
bool hasNextMip = m_currentMipIndex < (int)m_mipCount - 1;
|
|
||||||
m_ui->nextMipBtn->setVisible(hasNextMip);
|
|
||||||
|
|
||||||
bool hasPrevMip = m_currentMipIndex > 0;
|
|
||||||
m_ui->prevMipBtn->setVisible(hasPrevMip);
|
|
||||||
|
|
||||||
RefreshWarning();
|
|
||||||
|
|
||||||
if (m_currentMipIndex < m_resolutionInfos.size())
|
|
||||||
{
|
|
||||||
auto it = AZStd::next(m_resolutionInfos.begin(), m_currentMipIndex);
|
|
||||||
QString finalResolution;
|
|
||||||
if (it->arrayCount > 1)
|
|
||||||
{
|
|
||||||
finalResolution = QString("Image Size: %1 x %2 x %3").arg(QString::number(it->width), QString::number(it->height), QString::number(it->arrayCount));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
finalResolution = QString("Image Size: %1 x %2").arg(QString::number(it->width), QString::number(it->height));
|
|
||||||
}
|
|
||||||
m_ui->imageSizeLabel->setText(finalResolution);
|
|
||||||
|
|
||||||
CPixelFormats& pixelFormats = CPixelFormats::GetInstance();
|
|
||||||
const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->GetMultiplatformTextureSetting().m_preset);
|
|
||||||
if (preset)
|
|
||||||
{
|
|
||||||
uint32 size = pixelFormats.EvaluateImageDataSize(preset->m_pixelFormat, it->width, it->height) * it->arrayCount;
|
|
||||||
AZStd::string fileSizeString = EditorHelper::GetFileSizeString(size);
|
|
||||||
QString finalFileSize = QString("File Size: %1").arg(fileSizeString.c_str());
|
|
||||||
m_ui->fileSizeLabel->setText(finalFileSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_alwaysRefreshPreview)
|
|
||||||
{
|
|
||||||
RefreshPreviewImage(fullRefresh ? RefreshMode::Convert : RefreshMode::Mip);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Setting", false, "Cannot find mip reduce level for mip %d", m_currentMipIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnNextMip()
|
|
||||||
{
|
|
||||||
if (m_currentMipIndex >= (int)m_mipCount - 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_currentMipIndex ++;
|
|
||||||
RefreshUI(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnPrevMip()
|
|
||||||
{
|
|
||||||
if (m_currentMipIndex <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_currentMipIndex--;
|
|
||||||
RefreshUI(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::UpdatePreview()
|
|
||||||
{
|
|
||||||
if (!m_previewConverter->IsDone())
|
|
||||||
{
|
|
||||||
float progress = m_previewConverter->GetProgress();
|
|
||||||
SetImageLabelText(QString("Converting for preview...Progress %1%").arg(QString::number(progress * 100, 'f', 2)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_updateTimer->stop();
|
|
||||||
m_previewImageRaw = m_previewConverter->GetOutputImage();
|
|
||||||
|
|
||||||
GenerateMipmap(m_currentMipIndex);
|
|
||||||
GenerateChannelImage(m_previewMode);
|
|
||||||
PaintPreviewImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnAlwaysRefresh()
|
|
||||||
{
|
|
||||||
m_alwaysRefreshPreview = true;
|
|
||||||
m_alwaysRefreshAction->setChecked(true);
|
|
||||||
m_refreshPerClickAction->setChecked(false);
|
|
||||||
|
|
||||||
m_ui->refreshBtn->setIcon(m_alwaysRefreshIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnRefreshPerClick()
|
|
||||||
{
|
|
||||||
m_alwaysRefreshPreview = false;
|
|
||||||
m_alwaysRefreshAction->setChecked(false);
|
|
||||||
m_refreshPerClickAction->setChecked(true);
|
|
||||||
|
|
||||||
m_ui->refreshBtn->setIcon(m_refreshPerClickIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnRefreshClicked()
|
|
||||||
{
|
|
||||||
RefreshPreviewImage(RefreshMode::Convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::GenerateMipmap(int mip)
|
|
||||||
{
|
|
||||||
// Clear all cached preview images
|
|
||||||
for (int i = 0; i < (int)PreviewMode::Count; i++)
|
|
||||||
{
|
|
||||||
m_previewImages[i] = QImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_previewImageRaw && (AZ::u32)mip < m_previewImageRaw->GetMipCount() )
|
|
||||||
{
|
|
||||||
uint8* imageBuf;
|
|
||||||
uint32 pitch;
|
|
||||||
m_previewImageRaw->GetImagePointer(mip, imageBuf, pitch);
|
|
||||||
const uint32 width = m_previewImageRaw->GetWidth(mip);
|
|
||||||
const uint32 height = m_previewImageRaw->GetHeight(mip);
|
|
||||||
m_previewImages[PreviewMode::RGBA] = QImage(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Cannot generate mip preview from an invalid image.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::GenerateChannelImage(PreviewMode channel)
|
|
||||||
{
|
|
||||||
// If there is no preview image generated, ignore this function
|
|
||||||
if (m_previewImages[PreviewMode::RGBA].isNull())
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Cannot generate channel image from an invalid image.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_previewImages[channel].isNull())
|
|
||||||
{
|
|
||||||
// Copy the RGBA image before changing the color
|
|
||||||
QImage previewImg = m_previewImages[PreviewMode::RGBA].copy();
|
|
||||||
for (int x = 0; x < previewImg.width(); x++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < previewImg.height(); y++)
|
|
||||||
{
|
|
||||||
QRgb pixel = previewImg.pixel(x, y);
|
|
||||||
int r = qRed(pixel);
|
|
||||||
int g = qGreen(pixel);
|
|
||||||
int b = qBlue(pixel);
|
|
||||||
int a = qAlpha(pixel);
|
|
||||||
|
|
||||||
switch (channel)
|
|
||||||
{
|
|
||||||
case ImageProcessingEditor::RGB:
|
|
||||||
pixel = qRgba(r, g, b, 255);
|
|
||||||
break;
|
|
||||||
case ImageProcessingEditor::RRR:
|
|
||||||
pixel = qRgba(r, r, r, 255);
|
|
||||||
break;
|
|
||||||
case ImageProcessingEditor::GGG:
|
|
||||||
pixel = qRgba(g, g, g, 255);
|
|
||||||
break;
|
|
||||||
case ImageProcessingEditor::BBB:
|
|
||||||
pixel = qRgba(b, b, b, 255);
|
|
||||||
break;
|
|
||||||
case ImageProcessingEditor::Alpha:
|
|
||||||
pixel = qRgba(a, a, a, 255);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
previewImg.setPixel(x, y, pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Cache the image in current preview mode
|
|
||||||
m_previewImages[channel] = previewImg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::RefreshPreviewImage(RefreshMode mode)
|
|
||||||
{
|
|
||||||
// Ignore any none-conversion refresh request when the image is being converted
|
|
||||||
if (m_updateTimer->isActive() && mode != RefreshMode::Convert)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case RefreshMode::Convert:
|
|
||||||
{
|
|
||||||
// Start conversion in a AZ::Job
|
|
||||||
m_previewConverter->StartConvert();
|
|
||||||
// Start the timer to trigger the update function
|
|
||||||
m_updateTimer->start(s_updateInterval);
|
|
||||||
SetImageLabelText(QString("Converting for preview...Progress 0.01%"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RefreshMode::Mip:
|
|
||||||
{
|
|
||||||
GenerateMipmap(m_currentMipIndex);
|
|
||||||
GenerateChannelImage(m_previewMode);
|
|
||||||
PaintPreviewImage();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RefreshMode::Channel:
|
|
||||||
{
|
|
||||||
GenerateChannelImage(m_previewMode);
|
|
||||||
PaintPreviewImage();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PaintPreviewImage();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::PaintPreviewImage()
|
|
||||||
{
|
|
||||||
if (m_previewImages[m_previewMode].isNull())
|
|
||||||
{
|
|
||||||
SetImageLabelText(QString("Conversion failed, please check console for more information."), false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SetImageLabelText(QString(), false);
|
|
||||||
|
|
||||||
// Paint the image on to the image label
|
|
||||||
QPixmap pixMap = QPixmap::fromImage(m_previewImages[m_previewMode]);
|
|
||||||
QSize size = m_ui->imageLabel->size();
|
|
||||||
QPixmap finalPix = pixMap.copy();
|
|
||||||
finalPix.fill(Qt::transparent);
|
|
||||||
finalPix = finalPix.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
||||||
QPainter painter(&finalPix);
|
|
||||||
painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
|
|
||||||
QRect rect = finalPix.rect();
|
|
||||||
if (m_previewTiled)
|
|
||||||
{
|
|
||||||
pixMap = pixMap.scaled(size / 2, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
||||||
painter.drawTiledPixmap(rect, pixMap);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
painter.drawPixmap(rect, pixMap);
|
|
||||||
}
|
|
||||||
// Recenter the image label
|
|
||||||
float aspectRatio = static_cast<float>(finalPix.width()) / static_cast<float>(finalPix.height());
|
|
||||||
QSize preferredSize;
|
|
||||||
if (aspectRatio >= 1.0f)
|
|
||||||
{
|
|
||||||
preferredSize = QSize(aznumeric_cast<int>(m_imageLabelSize), aznumeric_cast<int>(m_imageLabelSize / aspectRatio));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
preferredSize = QSize(aznumeric_cast<int>(m_imageLabelSize * aspectRatio), aznumeric_cast<int>(m_imageLabelSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->imageLabel->resize(preferredSize);
|
|
||||||
m_ui->imageLabel->setPixmap(finalPix);
|
|
||||||
|
|
||||||
QPoint center = m_ui->mainWidget->rect().center();
|
|
||||||
m_ui->imageLabel->move(center - QPoint(preferredSize.width() / 2, preferredSize.height() / 2));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::SetImageLabelText(const QString& text, bool busyStatus /*= true*/)
|
|
||||||
{
|
|
||||||
// Since setting pixmap will change the label size
|
|
||||||
// Need to set back to initial size and recenter before displaying text
|
|
||||||
m_ui->imageLabel->resize(QSize(aznumeric_cast<int>(m_imageLabelSize), aznumeric_cast<int>(m_imageLabelSize)));
|
|
||||||
QPoint center = m_ui->mainWidget->rect().center();
|
|
||||||
m_ui->imageLabel->move(center - QPoint(aznumeric_cast<int>(m_imageLabelSize / 2), aznumeric_cast<int>(m_imageLabelSize / 2)));
|
|
||||||
m_ui->imageLabel->setText(text);
|
|
||||||
|
|
||||||
// Set busy label status and position to align with the text
|
|
||||||
m_ui->busyLabel->SetIsBusy(busyStatus);
|
|
||||||
QSize size = m_ui->busyLabel->size();
|
|
||||||
m_ui->busyLabel->move(center - QPoint(size.width() + m_ui->imageLabel->sizeHint().width() / 2, size.width() / 2));
|
|
||||||
m_ui->busyLabel->setVisible(busyStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::RefreshWarning()
|
|
||||||
{
|
|
||||||
int imageWidth = m_textureSetting->m_img->GetWidth(0);
|
|
||||||
int imageHeight = m_textureSetting->m_img->GetHeight(0);
|
|
||||||
AZStd::list<PlatformName> stretchedPlatform;
|
|
||||||
|
|
||||||
for (auto& iter: m_textureSetting->m_settingsMap)
|
|
||||||
{
|
|
||||||
PlatformName platform = iter.first;
|
|
||||||
const PresetSettings* presetSettings = BuilderSettingManager::Instance()->GetPreset(iter.second.m_preset, platform);
|
|
||||||
if (presetSettings)
|
|
||||||
{
|
|
||||||
EPixelFormat dstFmt = presetSettings->m_pixelFormat;
|
|
||||||
if (!CPixelFormats::GetInstance().IsImageSizeValid(dstFmt, imageWidth, imageHeight, false))
|
|
||||||
{
|
|
||||||
stretchedPlatform.push_back(EditorHelper::ToReadablePlatformString(platform).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stretchedPlatform.size() > 0)
|
|
||||||
{
|
|
||||||
QString warningText = QString("The output image will be stretched on Platform:");
|
|
||||||
int i = 0;
|
|
||||||
for (AZStd::string platform: stretchedPlatform)
|
|
||||||
{
|
|
||||||
warningText += i > 0 ? ", " : " ";
|
|
||||||
warningText += platform.c_str();
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
m_ui->warningLabel->setText(warningText);
|
|
||||||
m_ui->warningLabel->setVisible(true);
|
|
||||||
m_ui->warningIcon->setVisible(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->warningLabel->setVisible(false);
|
|
||||||
m_ui->warningIcon->setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnChangePreviewMode(int index)
|
|
||||||
{
|
|
||||||
if (index < (int)PreviewMode::Count)
|
|
||||||
{
|
|
||||||
m_previewMode = (PreviewMode)index;
|
|
||||||
|
|
||||||
RefreshPreviewImage(RefreshMode::Channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePreviewWidget::OnTiledChanged(bool checked)
|
|
||||||
{
|
|
||||||
m_previewTiled = checked;
|
|
||||||
RefreshPreviewImage(RefreshMode::Repaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TexturePreviewWidget::OnQtEvent(QEvent * event)
|
|
||||||
{
|
|
||||||
if (event->type() == QEvent::KeyPress)
|
|
||||||
{
|
|
||||||
const QKeyEvent* ke = static_cast<QKeyEvent*>(event);
|
|
||||||
if (ke->isAutoRepeat())
|
|
||||||
{
|
|
||||||
return false; //ignore repeat key event
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ke->key() == Qt::Key_Space)
|
|
||||||
{
|
|
||||||
if (!m_updateTimer->isActive()) // Only popup when image is not converting
|
|
||||||
{
|
|
||||||
m_previewPopup.reset(new ImagePopup(m_previewImages[m_previewMode], this));
|
|
||||||
m_previewPopup->installEventFilter(this);
|
|
||||||
m_previewPopup->show();
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ke->key() == Qt::Key_Alt)
|
|
||||||
{
|
|
||||||
m_previewMode = PreviewMode::Alpha;
|
|
||||||
RefreshPreviewImage(RefreshMode::Channel);
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ke->key() == Qt::Key_Shift)
|
|
||||||
{
|
|
||||||
m_previewMode = PreviewMode::RGBA;
|
|
||||||
RefreshPreviewImage(RefreshMode::Channel);
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event->type() == QEvent::KeyRelease)
|
|
||||||
{
|
|
||||||
const QKeyEvent* ke = static_cast<QKeyEvent*>(event);
|
|
||||||
if (ke->isAutoRepeat())
|
|
||||||
{
|
|
||||||
return false; //ignore repeat key event
|
|
||||||
}
|
|
||||||
if (ke->key() == Qt::Key_Space)
|
|
||||||
{
|
|
||||||
if (m_previewPopup)
|
|
||||||
{
|
|
||||||
m_previewPopup->hide();
|
|
||||||
}
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ke->key() == Qt::Key_Alt)
|
|
||||||
{
|
|
||||||
m_previewMode = (PreviewMode)m_ui->previewComboBox->currentIndex();
|
|
||||||
RefreshPreviewImage(RefreshMode::Channel);
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ke->key() == Qt::Key_Shift)
|
|
||||||
{
|
|
||||||
m_previewMode = (PreviewMode)m_ui->previewComboBox->currentIndex();
|
|
||||||
RefreshPreviewImage(RefreshMode::Channel);
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event->type() == QEvent::ApplicationStateChange)
|
|
||||||
{
|
|
||||||
const QApplicationStateChangeEvent* appEvent = static_cast<QApplicationStateChangeEvent*>(event);
|
|
||||||
AZ_Warning("Texture Editor", false, "app status change %d", appEvent->applicationState());
|
|
||||||
if (appEvent->applicationState() != Qt::ApplicationState::ApplicationActive)
|
|
||||||
{
|
|
||||||
PreviewMode currPreviewMode = (PreviewMode)m_ui->previewComboBox->currentIndex();
|
|
||||||
if (m_previewMode != currPreviewMode)
|
|
||||||
{
|
|
||||||
m_previewMode = currPreviewMode;
|
|
||||||
RefreshPreviewImage(RefreshMode::Channel);
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event->type() == QEvent::ShortcutOverride)
|
|
||||||
{
|
|
||||||
// since we respond to the following things, let Qt know so that shortcuts don't override us
|
|
||||||
|
|
||||||
QKeyEvent* kev = static_cast<QKeyEvent*>(event);
|
|
||||||
int key = kev->key() | kev->modifiers();
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Qt::Key_Space:
|
|
||||||
case Qt::Key_Alt:
|
|
||||||
case Qt::Key_Shift:
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TexturePreviewWidget::eventFilter(QObject* obj, QEvent* event)
|
|
||||||
{
|
|
||||||
if (event->type() == QEvent::KeyRelease)
|
|
||||||
{
|
|
||||||
const QKeyEvent* ke = static_cast<QKeyEvent*>(event);
|
|
||||||
if (ke->key() == Qt::Key_Space && !ke->isAutoRepeat())
|
|
||||||
{
|
|
||||||
if (m_previewPopup)
|
|
||||||
{
|
|
||||||
m_previewPopup->hide();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event->type() == QEvent::ApplicationStateChange)
|
|
||||||
{
|
|
||||||
const QApplicationStateChangeEvent* appEvent = static_cast<QApplicationStateChangeEvent*>(event);
|
|
||||||
if (appEvent->applicationState() != Qt::ApplicationState::ApplicationActive)
|
|
||||||
{
|
|
||||||
if (m_previewPopup)
|
|
||||||
{
|
|
||||||
m_previewPopup->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QWidget::eventFilter(obj, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_TexturePreviewWidget.cpp>
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QWidget>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <Editor/EditorCommon.h>
|
|
||||||
#include <Editor/ImagePopup.h>
|
|
||||||
#include <QEvent>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include <Processing/ImagePreview.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class TexturePreviewWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
enum PreviewMode
|
|
||||||
{
|
|
||||||
RGB = 0,
|
|
||||||
RRR,
|
|
||||||
GGG,
|
|
||||||
BBB,
|
|
||||||
Alpha,
|
|
||||||
RGBA,
|
|
||||||
Count
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class RefreshMode
|
|
||||||
{
|
|
||||||
Convert, // Convert the whole image from beginning, takes longest time
|
|
||||||
Mip, // Generate a new mip from from converted image
|
|
||||||
Channel, // Generate a new channel image from converted image
|
|
||||||
Repaint,
|
|
||||||
};
|
|
||||||
|
|
||||||
class TexturePreviewWidget
|
|
||||||
: public QWidget
|
|
||||||
, protected EditorInternalNotificationBus::Handler
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
AZ_CLASS_ALLOCATOR(TexturePreviewWidget, AZ::SystemAllocator, 0);
|
|
||||||
explicit TexturePreviewWidget(EditorTextureSetting& texureSetting, QWidget* parent = 0);
|
|
||||||
~TexturePreviewWidget();
|
|
||||||
bool OnQtEvent(QEvent* event);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void OnTiledChanged(bool checked);
|
|
||||||
void OnPrevMip();
|
|
||||||
void OnNextMip();
|
|
||||||
void OnChangePreviewMode(int index);
|
|
||||||
void UpdatePreview();
|
|
||||||
void OnAlwaysRefresh();
|
|
||||||
void OnRefreshPerClick();
|
|
||||||
void OnRefreshClicked();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
//EditorInternalNotificationBus
|
|
||||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
|
||||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void SetUpResolutionInfo();
|
|
||||||
void RefreshUI(bool fullRefresh = false);
|
|
||||||
void RefreshPreviewImage(RefreshMode mode);
|
|
||||||
void GenerateMipmap(int mip);
|
|
||||||
void GenerateChannelImage(PreviewMode channel);
|
|
||||||
void PaintPreviewImage();
|
|
||||||
void SetImageLabelText(const QString& text, bool busyStatus = true);
|
|
||||||
void RefreshWarning();
|
|
||||||
|
|
||||||
AZStd::list<ResolutionInfo> m_resolutionInfos;
|
|
||||||
QScopedPointer<Ui::TexturePreviewWidget> m_ui;
|
|
||||||
EditorTextureSetting* m_textureSetting;
|
|
||||||
int m_currentMipIndex = 0;
|
|
||||||
bool m_previewTiled = false;
|
|
||||||
float m_imageLabelSize = 0;
|
|
||||||
AZStd::string m_platform;
|
|
||||||
unsigned int m_mipCount = 1;
|
|
||||||
|
|
||||||
///////////////////////////////////////////
|
|
||||||
// Preview window
|
|
||||||
PreviewMode m_previewMode = PreviewMode::RGB;
|
|
||||||
QScopedPointer<ImagePopup> m_previewPopup;
|
|
||||||
AZStd::unique_ptr<ImageProcessing::ImagePreview> m_previewConverter;
|
|
||||||
ImageProcessing::IImageObjectPtr m_previewImageRaw;
|
|
||||||
QImage m_previewImages[PreviewMode::Count];
|
|
||||||
QTimer* m_updateTimer;
|
|
||||||
static const int s_updateInterval = 200;
|
|
||||||
////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////
|
|
||||||
// Refresh button
|
|
||||||
bool m_alwaysRefreshPreview = true;
|
|
||||||
QAction* m_alwaysRefreshAction = nullptr;
|
|
||||||
QAction* m_refreshPerClickAction = nullptr;
|
|
||||||
QIcon m_refreshPerClickIcon;
|
|
||||||
QIcon m_alwaysRefreshIcon;
|
|
||||||
////////////////////////////////////////////
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,371 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>TexturePreviewWidget</class>
|
|
||||||
<widget class="QWidget" name="TexturePreviewWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>672</width>
|
|
||||||
<height>579</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="previewComboBox"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="previewCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Preview tiled</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="hotkeyLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Shift: RGBA | Alt:Alpha | Space: Full-size</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QWidget" name="mainWidget" native="true">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>500</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<widget class="QFrame" name="infoLayer">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>171</width>
|
|
||||||
<height>185</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="layoutDirection">
|
|
||||||
<enum>Qt::RightToLeft</enum>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="warningLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="warningLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="warningIcon">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>16</width>
|
|
||||||
<height>16</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>26</width>
|
|
||||||
<height>25</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="pixmap">
|
|
||||||
<pixmap resource="../../../Assets/Editor/Resources.qrc">:/warning.png</pixmap>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>115</width>
|
|
||||||
<height>32</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="nextMipBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normalon>:/Forward.png</normalon>
|
|
||||||
</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="prevMipBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normalon>:/Backward.png</normalon>
|
|
||||||
</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>115</width>
|
|
||||||
<height>32</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="mipLevelLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Mip 1</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="imageSizeLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Image size: 2048 x 2048</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="fileSizeLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>File Size: 4,096 KB</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="refreshBtn">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>16777215</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="layoutDirection">
|
|
||||||
<enum>Qt::LeftToRight</enum>
|
|
||||||
</property>
|
|
||||||
<property name="autoFillBackground">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>24</width>
|
|
||||||
<height>24</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="popupMode">
|
|
||||||
<enum>QToolButton::MenuButtonPopup</enum>
|
|
||||||
</property>
|
|
||||||
<property name="toolButtonStyle">
|
|
||||||
<enum>Qt::ToolButtonIconOnly</enum>
|
|
||||||
</property>
|
|
||||||
<property name="autoRaise">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QLabel" name="imageLabel">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>400</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>2048</width>
|
|
||||||
<height>2048</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>image</string>
|
|
||||||
</property>
|
|
||||||
<property name="scaledContents">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="AzQtComponents::StyledBusyLabel" name="busyLabel" native="true">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>510</x>
|
|
||||||
<y>80</y>
|
|
||||||
<width>30</width>
|
|
||||||
<height>30</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>10</width>
|
|
||||||
<height>10</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="sizeIncrement">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>24</width>
|
|
||||||
<height>24</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<zorder>imageLabel</zorder>
|
|
||||||
<zorder>infoLayer</zorder>
|
|
||||||
<zorder>busyLabel</zorder>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>AzQtComponents::StyledBusyLabel</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header location="global">AzQtComponents/Components/StyledBusyLabel.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources>
|
|
||||||
<include location="../../../Assets/Editor/Resources.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,217 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ImageProcessing_precompiled.h>
|
|
||||||
#include "TexturePropertyEditor.h"
|
|
||||||
#include <Source/Editor/ui_TexturePropertyEditor.h>
|
|
||||||
|
|
||||||
#include <Source/BuilderSettings/BuilderSettingManager.h>
|
|
||||||
#include <AzFramework/StringFunc/StringFunc.h>
|
|
||||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
|
||||||
#include <AzCore/IO/FileIO.h>
|
|
||||||
|
|
||||||
#include <QBoxLayout>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QDesktopServices>
|
|
||||||
#include <QKeyEvent>
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QComboBox>
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
TexturePropertyEditor::TexturePropertyEditor(const AZ::Uuid& sourceTextureId, QWidget* parent /*= nullptr*/)
|
|
||||||
: AzQtComponents::StyledDialog(parent, Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::WindowTitleHint)
|
|
||||||
, m_ui(new Ui::TexturePropertyEditor)
|
|
||||||
, m_textureSetting(sourceTextureId)
|
|
||||||
, m_validImage(true)
|
|
||||||
{
|
|
||||||
if (m_textureSetting.m_img == nullptr)
|
|
||||||
{
|
|
||||||
m_validImage = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->setupUi(this);
|
|
||||||
|
|
||||||
//Initialize all the format string here
|
|
||||||
EditorHelper::InitPixelFormatString();
|
|
||||||
|
|
||||||
//TexturePreviewWidget will be the widget to preview mipmaps
|
|
||||||
m_previewWidget.reset(aznew TexturePreviewWidget(m_textureSetting, this));
|
|
||||||
m_ui->mainLayout->layout()->addWidget(m_previewWidget.data());
|
|
||||||
|
|
||||||
//TexturePresetSelectionWidget will be the widget to select the preset for the texture
|
|
||||||
m_presetSelectionWidget.reset(aznew TexturePresetSelectionWidget(m_textureSetting, this));
|
|
||||||
m_ui->mainLayout->layout()->addWidget(m_presetSelectionWidget.data());
|
|
||||||
|
|
||||||
//ResolutionSettingWidget will be the table section to display mipmap resolution for each platform
|
|
||||||
m_resolutionSettingWidget.reset(aznew ResolutionSettingWidget(ResoultionWidgetType::TexturePropety, m_textureSetting, this));
|
|
||||||
m_ui->mainLayout->layout()->addWidget(m_resolutionSettingWidget.data());
|
|
||||||
|
|
||||||
//MipmapSettingWidget will be simple ReflectedProperty editor to reflect mipmap settings section
|
|
||||||
m_mipmapSettingWidget.reset(aznew MipmapSettingWidget(m_textureSetting, this));
|
|
||||||
m_ui->mainLayout->layout()->addWidget(m_mipmapSettingWidget.data());
|
|
||||||
|
|
||||||
// Disable horizontal scroll
|
|
||||||
m_ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
|
|
||||||
QObject::connect(m_ui->saveBtn, &QPushButton::clicked, this, &TexturePropertyEditor::OnSave);
|
|
||||||
QObject::connect(m_ui->helpBtn, &QPushButton::clicked, this, &TexturePropertyEditor::OnHelp);
|
|
||||||
QObject::connect(m_ui->cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
|
|
||||||
|
|
||||||
EditorInternalNotificationBus::Handler::BusConnect();
|
|
||||||
|
|
||||||
// When checkbox and combobox is focused, they will intercept the space shortcut, need to disable focus on them first
|
|
||||||
// to get space shortcut pass through
|
|
||||||
QList<QCheckBox*> checkBoxWidgets = QObject::findChildren<QCheckBox*>();
|
|
||||||
for (QCheckBox* widget: checkBoxWidgets)
|
|
||||||
{
|
|
||||||
widget->setFocusPolicy(Qt::NoFocus);
|
|
||||||
}
|
|
||||||
QList<QComboBox*> comboBoxWidgets = QObject::findChildren<QComboBox*>();
|
|
||||||
for (QComboBox* widget : comboBoxWidgets)
|
|
||||||
{
|
|
||||||
widget->setFocusPolicy(Qt::NoFocus);
|
|
||||||
}
|
|
||||||
this->setFocusPolicy(Qt::StrongFocus);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TexturePropertyEditor::~TexturePropertyEditor()
|
|
||||||
{
|
|
||||||
EditorInternalNotificationBus::Handler::BusDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TexturePropertyEditor::HasValidImage()
|
|
||||||
{
|
|
||||||
return m_validImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePropertyEditor::OnEditorSettingsChanged([[maybe_unused]] bool needRefresh, const AZStd::string& /*platform*/)
|
|
||||||
{
|
|
||||||
m_textureSetting.m_modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePropertyEditor::OnSave()
|
|
||||||
{
|
|
||||||
if (!m_validImage)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sourceControlActive = false;
|
|
||||||
AzToolsFramework::SourceControlConnectionRequestBus::BroadcastResult(sourceControlActive, &AzToolsFramework::SourceControlConnectionRequests::IsActive);
|
|
||||||
AZStd::string outputPath = m_textureSetting.m_fullPath + ImageProcessing::TextureSettings::modernExtensionName;
|
|
||||||
|
|
||||||
if (sourceControlActive)
|
|
||||||
{
|
|
||||||
using ApplicationBus = AzToolsFramework::ToolsApplicationRequestBus;
|
|
||||||
bool checkoutResult = false;
|
|
||||||
ApplicationBus::BroadcastResult(checkoutResult, &ApplicationBus::Events::RequestEditForFileBlocking, outputPath.c_str(), "Checking out .imagesetting file", []([[maybe_unused]] int& current, [[maybe_unused]] int& max) {});
|
|
||||||
|
|
||||||
if (checkoutResult)
|
|
||||||
{
|
|
||||||
SaveTextureSetting(outputPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Cannot checkout file '%s' from source control.", outputPath.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const bool fileExisted = AZ::IO::FileIOBase::GetInstance()->Exists(outputPath.c_str());
|
|
||||||
const bool fileReadOnly = AZ::IO::FileIOBase::GetInstance()->IsReadOnly(outputPath.c_str());
|
|
||||||
|
|
||||||
if (!fileExisted || !fileReadOnly)
|
|
||||||
{
|
|
||||||
SaveTextureSetting(outputPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePropertyEditor::SaveTextureSetting(AZStd::string outputPath)
|
|
||||||
{
|
|
||||||
if (!m_validImage)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageProcessing::TextureSettings& baseSetting = m_textureSetting.GetMultiplatformTextureSetting();
|
|
||||||
for (auto& it : m_textureSetting.m_settingsMap)
|
|
||||||
{
|
|
||||||
baseSetting.ApplySettings(it.second, it.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageProcessing::StringOutcome outcome = ImageProcessing::TextureSettings::WriteTextureSetting(outputPath, baseSetting);
|
|
||||||
|
|
||||||
if (outcome.IsSuccess())
|
|
||||||
{
|
|
||||||
// Since setting is successfully saved, we can safely delete the legacy setting now
|
|
||||||
DeleteLegacySetting();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error("Texture Editor", false, "Cannot save texture settings!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TexturePropertyEditor::DeleteLegacySetting()
|
|
||||||
{
|
|
||||||
AZStd::string legacyFile = m_textureSetting.m_fullPath + ImageProcessing::TextureSettings::legacyExtensionName;
|
|
||||||
const bool fileExisted = AZ::IO::FileIOBase::GetInstance()->Exists(legacyFile.c_str());
|
|
||||||
if (fileExisted)
|
|
||||||
{
|
|
||||||
bool sourceControlActive = false;
|
|
||||||
AzToolsFramework::SourceControlConnectionRequestBus::BroadcastResult(sourceControlActive, &AzToolsFramework::SourceControlConnectionRequests::IsActive);
|
|
||||||
|
|
||||||
if (sourceControlActive)
|
|
||||||
{
|
|
||||||
AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestDelete, legacyFile.c_str(),
|
|
||||||
[](bool success, const AzToolsFramework::SourceControlFileInfo& info)
|
|
||||||
{
|
|
||||||
//Deletes the file locally if it's not tracked by source control
|
|
||||||
if (!success && !info.IsManaged())
|
|
||||||
{
|
|
||||||
AZ::IO::FileIOBase::GetInstance()->Remove(info.m_filePath.c_str());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ::IO::FileIOBase::GetInstance()->Remove(legacyFile.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TexturePropertyEditor::OnHelp()
|
|
||||||
{
|
|
||||||
QString webLink = tr("https://docs.aws.amazon.com/console/lumberyard/texturepipeline");
|
|
||||||
QDesktopServices::openUrl(QUrl(webLink));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TexturePropertyEditor::event(QEvent* event)
|
|
||||||
{
|
|
||||||
bool needsBlocking = false;
|
|
||||||
if (m_previewWidget)
|
|
||||||
{
|
|
||||||
needsBlocking = m_previewWidget->OnQtEvent(event);
|
|
||||||
}
|
|
||||||
return needsBlocking ? true : QWidget::event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
}//namespace ImageProcessingEditor
|
|
||||||
#include <Source/Editor/moc_TexturePropertyEditor.cpp>
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if !defined(Q_MOC_RUN)
|
|
||||||
#include <QDialog>
|
|
||||||
#include <AzCore/Memory/SystemAllocator.h>
|
|
||||||
#include <AzQtComponents/Components/StyledDialog.h>
|
|
||||||
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
|
|
||||||
|
|
||||||
#include <Source/Editor/EditorCommon.h>
|
|
||||||
#include <Source/Editor/TexturePresetSelectionWidget.h>
|
|
||||||
#include <Source/Editor/TexturePreviewWidget.h>
|
|
||||||
#include <Source/Editor/ResolutionSettingWidget.h>
|
|
||||||
#include <Source/Editor/MipmapSettingWidget.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class TexturePropertyEditor;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ImageProcessingEditor
|
|
||||||
{
|
|
||||||
class TexturePropertyEditor
|
|
||||||
: public AzQtComponents::StyledDialog
|
|
||||||
, protected EditorInternalNotificationBus::Handler
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
AZ_CLASS_ALLOCATOR(TexturePropertyEditor, AZ::SystemAllocator, 0);
|
|
||||||
explicit TexturePropertyEditor(const AZ::Uuid& sourceTextureId, QWidget* parent = nullptr);
|
|
||||||
~TexturePropertyEditor();
|
|
||||||
|
|
||||||
bool HasValidImage();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void OnSave();
|
|
||||||
void OnHelp();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
//EditorInternalNotificationBus
|
|
||||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool event(QEvent* event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<Ui::TexturePropertyEditor> m_ui;
|
|
||||||
QScopedPointer<TexturePreviewWidget> m_previewWidget;
|
|
||||||
QScopedPointer<TexturePresetSelectionWidget> m_presetSelectionWidget;
|
|
||||||
QScopedPointer<ResolutionSettingWidget> m_resolutionSettingWidget;
|
|
||||||
QScopedPointer<MipmapSettingWidget> m_mipmapSettingWidget;
|
|
||||||
|
|
||||||
EditorTextureSetting m_textureSetting;
|
|
||||||
bool m_validImage = true;
|
|
||||||
|
|
||||||
void SaveTextureSetting(AZStd::string outputPath);
|
|
||||||
void DeleteLegacySetting();
|
|
||||||
|
|
||||||
};
|
|
||||||
} //namespace ImageProcessingEditor
|
|
||||||
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>TexturePropertyEditor</class>
|
|
||||||
<widget class="QDialog" name="TexturePropertyEditor">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>580</width>
|
|
||||||
<height>1100</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>580</width>
|
|
||||||
<height>800</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>580</width>
|
|
||||||
<height>1200</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Texture Settings Editor</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QScrollArea" name="scrollArea">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="widgetResizable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>560</width>
|
|
||||||
<height>1049</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="mainLayout"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="buttonLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="helpBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>?</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="saveBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Apply</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="cancelBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Close</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License").All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file.Do not
|
|
||||||
* remove or modify any license notices.This file is distributed on an "AS IS" BASIS,
|
|
||||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <AzCore/base.h>
|
|
||||||
|
|
||||||
typedef AZ::s8 int8;
|
|
||||||
typedef AZ::s8 sint8;
|
|
||||||
typedef AZ::u8 uint8;
|
|
||||||
|
|
||||||
typedef AZ::s16 int16;
|
|
||||||
typedef AZ::s16 sint16;
|
|
||||||
typedef AZ::u16 uint16;
|
|
||||||
|
|
||||||
typedef AZ::s32 int32;
|
|
||||||
typedef AZ::s32 sint32;
|
|
||||||
typedef AZ::u32 uint32;
|
|
||||||
|
|
||||||
typedef float f32;
|
|
||||||
typedef double f64;
|
|
||||||
@ -1,346 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
*or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ImageProcessing_precompiled.h"
|
|
||||||
#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 <Processing/ImageConvert.h>
|
|
||||||
#include <Processing/PixelFormatInfo.h>
|
|
||||||
#include <AzFramework/API/ApplicationAPI.h>
|
|
||||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include <AzFramework/StringFunc/StringFunc.h>
|
|
||||||
|
|
||||||
#include <ImageLoader/ImageLoaders.h>
|
|
||||||
#include <Processing/ImageConvert.h>
|
|
||||||
#include <Processing/ImageToProcess.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
// create and initialize BuilderSettingManager once since it's will be used for image conversion
|
|
||||||
BuilderSettingManager::CreateInstance();
|
|
||||||
|
|
||||||
auto outcome = ImageProcessing::BuilderSettingManager::Instance()->LoadBuilderSettings();
|
|
||||||
AZ_Error("Image Processing", outcome.IsSuccess(), "Failed to load default preset settings!");
|
|
||||||
|
|
||||||
// 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 = "Image Worker Builder";
|
|
||||||
builderDescriptor.m_version = 2;
|
|
||||||
builderDescriptor.m_analysisFingerprint = AZStd::string::format("%d", ImageProcessing::BuilderSettingManager::Instance()->BuilderSettingsVersion());
|
|
||||||
|
|
||||||
for (int i = 0; i < s_TotalSupportedImageExtensions; i++)
|
|
||||||
{
|
|
||||||
builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(s_SupportedImageExtensions[i], AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
|
||||||
}
|
|
||||||
|
|
||||||
//add ".dds" here separately since we only apply copy operation for this type of file. and there won't be export option for dds files.
|
|
||||||
builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.dds", 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);
|
|
||||||
m_imageBuilder.BusConnect(builderDescriptor.m_busId);
|
|
||||||
ImageProcessingRequestBus::Handler::BusConnect();
|
|
||||||
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuilderPluginComponent::Deactivate()
|
|
||||||
{
|
|
||||||
ImageProcessingRequestBus::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);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (ImageProcessing::BuilderSettingManager::Instance()->DoesSupportPlatform(platformInfo.m_identifier))
|
|
||||||
{
|
|
||||||
AssetBuilderSDK::JobDescriptor descriptor;
|
|
||||||
descriptor.m_jobKey = ext + " Compile";
|
|
||||||
descriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str());
|
|
||||||
descriptor.m_critical = false;
|
|
||||||
descriptor.m_additionalFingerprintInfo = AZStd::string::format("%d", ImageProcessing::BuilderSettingManager::Instance()->BuilderSettingsVersion());
|
|
||||||
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;
|
|
||||||
|
|
||||||
//if the original file is a dds file then skip conversion
|
|
||||||
if (AzFramework::StringFunc::Path::IsExtension(request.m_fullPath.c_str(), "dds", false))
|
|
||||||
{
|
|
||||||
productFilepaths.push_back(request.m_fullPath);
|
|
||||||
imageProcessingSuccessful = true;
|
|
||||||
needConversion = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
|
|
||||||
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();
|
|
||||||
process->GetAppendOutputFilePaths(productFilepaths);
|
|
||||||
|
|
||||||
delete process;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
imageProcessingSuccessful = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageProcessingSuccessful)
|
|
||||||
{
|
|
||||||
AZ::Outcome<void, AZStd::string> result = PopulateProducts(request, productFilepaths, response.m_outputProducts);
|
|
||||||
if (result.IsSuccess())
|
|
||||||
{
|
|
||||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AZ_Error(AssetBuilderSDK::ErrorWindow, false, result.GetError().c_str());
|
|
||||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AZ::Outcome<void, AZStd::string> ImageBuilderWorker::PopulateProducts(const AssetBuilderSDK::ProcessJobRequest& request, const AZStd::vector<AZStd::string>& productFilepaths, AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts)
|
|
||||||
{
|
|
||||||
AssetBuilderSDK::JobProduct* rgbBaseJobProduct = nullptr;
|
|
||||||
AssetBuilderSDK::JobProduct* diffBaseJobProduct = nullptr;
|
|
||||||
AssetBuilderSDK::JobProduct* baseJobProduct = nullptr;
|
|
||||||
AssetBuilderSDK::JobProduct* alphaBaseJobProduct = nullptr;
|
|
||||||
// Report the image-import result (filepath to one or many '.dds')
|
|
||||||
|
|
||||||
// This reserve is critically important to prevent resizing the vector and invalidating the pointers we need to save off
|
|
||||||
jobProducts.reserve(productFilepaths.size());
|
|
||||||
|
|
||||||
for (const auto& product : productFilepaths)
|
|
||||||
{
|
|
||||||
AssetBuilderSDK::JobProduct jobProduct(product);
|
|
||||||
jobProduct.m_dependenciesHandled = true; // Dependencies are handled down below. The base products will have dependencies, lod products won't
|
|
||||||
jobProducts.push_back(jobProduct);
|
|
||||||
|
|
||||||
AZ::u32 lodLevel = AssetBuilderSDK::GetSubID_LOD(jobProduct.m_productSubID);
|
|
||||||
|
|
||||||
if(jobProduct.m_productSubID == 0)
|
|
||||||
{
|
|
||||||
rgbBaseJobProduct = &jobProducts.back();
|
|
||||||
}
|
|
||||||
else if((jobProduct.m_productSubID & AssetBuilderSDK::SUBID_FLAG_DIFF) && lodLevel == 0)
|
|
||||||
{
|
|
||||||
diffBaseJobProduct = &jobProducts.back();
|
|
||||||
}
|
|
||||||
else if((jobProduct.m_productSubID & AssetBuilderSDK::SUBID_FLAG_ALPHA) && lodLevel == 0)
|
|
||||||
{
|
|
||||||
alphaBaseJobProduct = &jobProducts.back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//We can have a diff and/or a rgb base. The rgb base always takes precedence when present
|
|
||||||
baseJobProduct = rgbBaseJobProduct;
|
|
||||||
|
|
||||||
if(!baseJobProduct)
|
|
||||||
{
|
|
||||||
baseJobProduct = diffBaseJobProduct;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (AssetBuilderSDK::JobProduct& jobProduct : jobProducts)
|
|
||||||
{
|
|
||||||
AssetBuilderSDK::ProductDependency productDependency(AZ::Data::AssetId(request.m_sourceFileUUID, jobProduct.m_productSubID), 0);
|
|
||||||
|
|
||||||
AZ::u32 lodLevel = AssetBuilderSDK::GetSubID_LOD(jobProduct.m_productSubID);
|
|
||||||
bool isAlpha = jobProduct.m_productSubID & AssetBuilderSDK::SUBID_FLAG_ALPHA;
|
|
||||||
|
|
||||||
if (lodLevel > 0)
|
|
||||||
{
|
|
||||||
if (isAlpha)
|
|
||||||
{
|
|
||||||
if (alphaBaseJobProduct)
|
|
||||||
{
|
|
||||||
// add all alpha mips to the base alpha texture as product dependency
|
|
||||||
alphaBaseJobProduct->m_dependencies.push_back(productDependency);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return AZ::Failure(AZStd::string::format("Unable to add (%s) file as a product dependency of the base alpha texture file. Base alpha texture file is missing from the products list.\n", jobProduct.m_productFileName.c_str()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (baseJobProduct)
|
|
||||||
{
|
|
||||||
// add all rgb mips to the base rgb texture as product dependency
|
|
||||||
baseJobProduct->m_dependencies.push_back(productDependency);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return AZ::Failure(AZStd::string::format("Unable to add (%s) file as a product dependency of the base rgb texture file. Base rgb texture file is missing from the products list.\n", jobProduct.m_productFileName.c_str()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Diffuse (_diff) is required by the base (typically for cubemaps)
|
|
||||||
if (rgbBaseJobProduct && diffBaseJobProduct)
|
|
||||||
{
|
|
||||||
AssetBuilderSDK::ProductDependency productDependency(AZ::Data::AssetId(request.m_sourceFileUUID, diffBaseJobProduct->m_productSubID), 0);
|
|
||||||
rgbBaseJobProduct->m_dependencies.push_back(productDependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alphaBaseJobProduct && baseJobProduct)
|
|
||||||
{
|
|
||||||
// Add the alphaBaseTexture as a product dependency for baseTexture
|
|
||||||
AssetBuilderSDK::ProductDependency productDependency(AZ::Data::AssetId(request.m_sourceFileUUID, alphaBaseJobProduct->m_productSubID), 0);
|
|
||||||
baseJobProduct->m_dependencies.push_back(productDependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AZ::Success();
|
|
||||||
}
|
|
||||||
} // namespace ImageProcessing
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
|
|
||||||
* its licensors.
|
|
||||||
*
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
||||||
* distribution (the "License"). All use of this software is governed by the License,
|
|
||||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
||||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
||||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/Component/Component.h>
|
|
||||||
#include <AssetBuilderSDK/AssetBuilderBusses.h>
|
|
||||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
|
||||||
#include <AzCore/Outcome/Outcome.h>
|
|
||||||
#include <ImageProcessing/ImageProcessingBus.h>
|
|
||||||
|
|
||||||
namespace ImageProcessing
|
|
||||||
{
|
|
||||||
//! Builder to process images
|
|
||||||
class ImageBuilderWorker
|
|
||||||
: public AssetBuilderSDK::AssetBuilderCommandBus::Handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_RTTI(ImageBuilderWorker, "{525422DE-05B3-4095-966F-90CD7657A7E1}");
|
|
||||||
|
|
||||||
ImageBuilderWorker() = default;
|
|
||||||
~ImageBuilderWorker() = default;
|
|
||||||
|
|
||||||
//! Asset Builder Callback Functions
|
|
||||||
void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response);
|
|
||||||
void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//!AssetBuilderSDK::AssetBuilderCommandBus interface
|
|
||||||
void ShutDown() override; // if you get this you must fail all existing jobs and return.
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//! Populates the jobProduct vector with all the entries including their product dependencies
|
|
||||||
AZ::Outcome<void, AZStd::string> PopulateProducts(const AssetBuilderSDK::ProcessJobRequest& request, const AZStd::vector<AZStd::string>& productFilepaths, AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_isShuttingDown = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! BuilderPluginComponent is to handle the lifecycle of ImageBuilder module.
|
|
||||||
class BuilderPluginComponent
|
|
||||||
: public AZ::Component
|
|
||||||
, protected ImageProcessingRequestBus::Handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AZ_COMPONENT(BuilderPluginComponent, "{2F12E1BE-D8F6-47A4-AC3E-6C5527C55840}")
|
|
||||||
static void Reflect(AZ::ReflectContext* context);
|
|
||||||
|
|
||||||
BuilderPluginComponent(); // avoid initialization here.
|
|
||||||
~BuilderPluginComponent() override; // free memory an uninitialize yourself.
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// AZ::Component
|
|
||||||
void Init() override; // create objects, allocate memory and initialize yourself without reaching out to the outside world
|
|
||||||
void Activate() override; // reach out to the outside world and connect up to what you need to, register things, etc.
|
|
||||||
void Deactivate() override; // unregister things, disconnect from the outside world
|
|
||||||
|
|
||||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
|
||||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// ImageProcessingRequestBus interface implementation
|
|
||||||
IImageObjectPtr LoadImage(const AZStd::string& filePath) override;
|
|
||||||
IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override;
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
|
||||||
ImageBuilderWorker m_imageBuilder;
|
|
||||||
};
|
|
||||||
}// namespace ImageProcessing
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue