Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,390 @@
/*
* 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 == "xenia")
{
readableString = "Xenia";
}
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
@@ -0,0 +1,105 @@
/*
* 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
@@ -0,0 +1,49 @@
/*
* 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>
@@ -0,0 +1,44 @@
/*
* 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
@@ -0,0 +1,43 @@
<?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>
@@ -0,0 +1,122 @@
/*
* 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>
@@ -0,0 +1,62 @@
/*
* 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
@@ -0,0 +1,89 @@
<?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>
@@ -0,0 +1,120 @@
/*
* 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>
@@ -0,0 +1,49 @@
/*
* 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
@@ -0,0 +1,83 @@
<?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>
@@ -0,0 +1,145 @@
/*
* 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>
@@ -0,0 +1,81 @@
/*
* 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
@@ -0,0 +1,205 @@
<?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>
@@ -0,0 +1,58 @@
/*
* 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>
@@ -0,0 +1,44 @@
/*
* 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
@@ -0,0 +1,177 @@
<?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>
@@ -0,0 +1,199 @@
/*
* 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>
@@ -0,0 +1,65 @@
/*
* 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
@@ -0,0 +1,91 @@
<?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>
@@ -0,0 +1,639 @@
/*
* 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>
@@ -0,0 +1,121 @@
/*
* 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
@@ -0,0 +1,371 @@
<?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>
@@ -0,0 +1,219 @@
/*
* 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)
{
bool checkoutResult = false;
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>
@@ -0,0 +1,74 @@
/*
* 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
@@ -0,0 +1,120 @@
<?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>