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

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

334 lines
15 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <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 ImageProcessingAtom
{
const char* TextureSettings::ExtensionName = ".assetinfo";
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;
}
MultiplatformTextureSettings TextureSettings::GenerateDefaultMultiplatformTextureSettings(const AZStd::string& imageFilepath)
{
MultiplatformTextureSettings settings;
PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList();
AZ::Uuid suggestedPreset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilepath);
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 file path from image path.
AZStd::string metadataFilepath = imageFilepath + TextureSettings::ExtensionName;
bool hasMetafile = AZ::IO::SystemFile::Exists(metadataFilepath.c_str());
canOverridePreset = true;
// If the image has an accompanying metadata...
if(hasMetafile)
{
// Parse the metadata file.
if (LoadTextureSetting(metadataFilepath, loadedTextureSetting, serializeContext).IsSuccess())
{
canOverridePreset = false;
return GetMultiplatformTextureSetting(loadedTextureSetting, serializeContext);
}
else
{
AZ_Error("Image processing", false, "Failed to load the image's meta file %s", metadataFilepath.c_str());
}
}
return GenerateDefaultMultiplatformTextureSettings(imageFilepath);
}
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;
}
}