ATOM-16854 Texture Settings dialog box crashes in the Editor (#5777)

Changes include:
-Fixed image preview issue which was trying to convert a compressed texture directly to QImage.
-Fixed texture resolution display for cubemap in texture setting editor.
-Sort the preset names in preset combo box
-Fixed a crash when showing IBLSkybox preset info in texture setting editor

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>
monroegm-disable-blank-issue-2
Qing Tao 4 years ago committed by GitHub
parent ebb24d2285
commit 8fd9cbfb64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -146,6 +146,25 @@ namespace ImageProcessingAtom
return nullptr; return nullptr;
} }
AZStd::vector<AZStd::string> BuilderSettingManager::GetFileMasksForPreset(const PresetName& presetName) const
{
AZStd::vector<AZStd::string> fileMasks;
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
for (const auto& mapping:m_presetFilterMap)
{
for (const auto& preset : mapping.second)
{
if (preset == presetName)
{
fileMasks.push_back(mapping.first);
break;
}
}
}
return fileMasks;
}
const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) const const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) const
{ {
auto itr = m_builderSettings.find(platform); auto itr = m_builderSettings.find(platform);
@ -177,6 +196,13 @@ namespace ImageProcessingAtom
return m_presetFilterMap; return m_presetFilterMap;
} }
const AZStd::unordered_set<PresetName>& BuilderSettingManager::GetFullPresetList() const
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
AZStd::string noFilter = AZStd::string();
return m_presetFilterMap.find(noFilter)->second;
}
const PresetName BuilderSettingManager::GetPresetNameFromId(const AZ::Uuid& presetId) const PresetName BuilderSettingManager::GetPresetNameFromId(const AZ::Uuid& presetId)
{ {
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock); AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);

@ -57,6 +57,8 @@ namespace ImageProcessingAtom
const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr) const; const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr) const;
AZStd::vector<AZStd::string> GetFileMasksForPreset(const PresetName& presetName) const;
const BuilderSettings* GetBuilderSetting(const PlatformName& platform) const; const BuilderSettings* GetBuilderSetting(const PlatformName& platform) const;
//! Return A list of platform supported //! Return A list of platform supported
@ -67,6 +69,8 @@ namespace ImageProcessingAtom
//! @value set of preset setting names supporting the specified filemask //! @value set of preset setting names supporting the specified filemask
const AZStd::map<FileMask, AZStd::unordered_set<PresetName>>& GetPresetFilterMap() const; const AZStd::map<FileMask, AZStd::unordered_set<PresetName>>& GetPresetFilterMap() const;
const AZStd::unordered_set<PresetName>& GetFullPresetList() const;
//! Find preset name based on the preset id. //! Find preset name based on the preset id.
const PresetName GetPresetNameFromId(const AZ::Uuid& presetId); const PresetName GetPresetNameFromId(const AZ::Uuid& presetId);

@ -26,19 +26,19 @@ namespace ImageProcessingAtom
static void Reflect(AZ::ReflectContext* context); static void Reflect(AZ::ReflectContext* context);
// "cm_ftype", cubemap angular filter type: gaussian, cone, disc, cosine, cosine_power, ggx // "cm_ftype", cubemap angular filter type: gaussian, cone, disc, cosine, cosine_power, ggx
CubemapFilterType m_filter; CubemapFilterType m_filter = CubemapFilterType::ggx;
// "cm_fangle", base filter angle for cubemap filtering(degrees), 0 - disabled // "cm_fangle", base filter angle for cubemap filtering(degrees), 0 - disabled
float m_angle; float m_angle = 0;
// "cm_fmipangle", initial mip filter angle for cubemap filtering(degrees), 0 - disabled // "cm_fmipangle", initial mip filter angle for cubemap filtering(degrees), 0 - disabled
float m_mipAngle; float m_mipAngle = 0;
// "cm_fmipslope", mip filter angle multiplier for cubemap filtering, 1 - default" // "cm_fmipslope", mip filter angle multiplier for cubemap filtering, 1 - default"
float m_mipSlope; float m_mipSlope = 1;
// "cm_edgefixup", cubemap edge fix-up width, 0 - disabled // "cm_edgefixup", cubemap edge fix-up width, 0 - disabled
float m_edgeFixup; float m_edgeFixup = 0;
// generate an IBL specular cubemap // generate an IBL specular cubemap
bool m_generateIBLSpecular = false; bool m_generateIBLSpecular = false;

@ -39,7 +39,8 @@ namespace ImageProcessingAtom
#define STRING_OUTCOME_ERROR(error) AZ::Failure(AZStd::string(error)) #define STRING_OUTCOME_ERROR(error) AZ::Failure(AZStd::string(error))
// Common typedefs (with dependent forward-declarations) // Common typedefs (with dependent forward-declarations)
typedef AZStd::string PlatformName, FileMask; typedef AZStd::string PlatformName;
typedef AZStd::string FileMask;
typedef AZ::Name PresetName; typedef AZ::Name PresetName;
typedef AZStd::vector<PlatformName> PlatformNameVector; typedef AZStd::vector<PlatformName> PlatformNameVector;
typedef AZStd::list<PlatformName> PlatformNameList; typedef AZStd::list<PlatformName> PlatformNameList;

@ -257,15 +257,22 @@ namespace ImageProcessingAtomEditor
// Update input width and height if it's a cubemap // Update input width and height if it's a cubemap
if (presetSetting->m_cubemapSetting != nullptr) if (presetSetting->m_cubemapSetting != nullptr)
{ {
CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_img); if (IsValidLatLongMap(m_img))
if (srcCubemap == nullptr)
{ {
return false; inputWidth = inputWidth/4;
}
else
{
CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_img);
if (srcCubemap == nullptr)
{
return false;
}
inputWidth = srcCubemap->GetFaceSize();
delete srcCubemap;
} }
inputWidth = srcCubemap->GetFaceSize();
inputHeight = inputWidth; inputHeight = inputWidth;
outResolutionInfo.arrayCount = 6; outResolutionInfo.arrayCount = 6;
delete srcCubemap;
} }
GetOutputExtent(inputWidth, inputHeight, outResolutionInfo.width, outResolutionInfo.height, outResolutionInfo.reduce, &textureSetting, presetSetting); GetOutputExtent(inputWidth, inputHeight, outResolutionInfo.width, outResolutionInfo.height, outResolutionInfo.reduce, &textureSetting, presetSetting);

@ -18,6 +18,27 @@
namespace ImageProcessingAtomEditor namespace ImageProcessingAtomEditor
{ {
using namespace ImageProcessingAtom; using namespace ImageProcessingAtom;
AZStd::string GetImageFileMask(const AZStd::string& imageFilePath)
{
const char FileMaskDelimiter = '_';
//get file name
AZStd::string fileName;
QString lowerFileName = imageFilePath.data();
lowerFileName = lowerFileName.toLower();
AzFramework::StringFunc::Path::GetFileName(lowerFileName.toUtf8().constData(), fileName);
//get the substring from last '_'
size_t lastUnderScore = fileName.find_last_of(FileMaskDelimiter);
if (lastUnderScore != AZStd::string::npos)
{
return fileName.substr(lastUnderScore);
}
return AZStd::string();
}
TexturePresetSelectionWidget::TexturePresetSelectionWidget(EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/) TexturePresetSelectionWidget::TexturePresetSelectionWidget(EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/)
: QWidget(parent) : QWidget(parent)
, m_ui(new Ui::TexturePresetSelectionWidget) , m_ui(new Ui::TexturePresetSelectionWidget)
@ -29,33 +50,31 @@ namespace ImageProcessingAtomEditor
m_presetList.clear(); m_presetList.clear();
auto& presetFilterMap = BuilderSettingManager::Instance()->GetPresetFilterMap(); auto& presetFilterMap = BuilderSettingManager::Instance()->GetPresetFilterMap();
AZStd::unordered_set<ImageProcessingAtom::PresetName> noFilterPresetList; if (m_listAllPresets)
{
// Check if there is any filtered preset list first m_presetList = BuilderSettingManager::Instance()->GetFullPresetList();
for(auto& presetFilter : presetFilterMap) }
else
{ {
if (presetFilter.first.empty()) auto fileMask = GetImageFileMask(m_textureSetting->m_textureName);
auto itr = presetFilterMap.find(fileMask);
if (itr != presetFilterMap.end())
{ {
noFilterPresetList = presetFilter.second; m_presetList = itr->second;
} }
else if (IsMatchingWithFileMask(m_textureSetting->m_textureName, presetFilter.first)) else
{ {
for(const auto& presetName : presetFilter.second) m_presetList = BuilderSettingManager::Instance()->GetFullPresetList();
{
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;
}
QStringList stringList;
foreach (const auto& presetName, m_presetList) foreach (const auto& presetName, m_presetList)
{ {
m_ui->presetComboBox->addItem(QString(presetName.GetCStr())); stringList.append(QString(presetName.GetCStr()));
} }
stringList.sort();
m_ui->presetComboBox->addItems(stringList);
// Set current preset // Set current preset
const auto& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; const auto& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset;
@ -173,8 +192,9 @@ namespace ImageProcessingAtomEditor
AZStd::string conventionText = ""; AZStd::string conventionText = "";
if (presetSettings) if (presetSettings)
{ {
auto fileMasks = BuilderSettingManager::Instance()->GetFileMasksForPreset(presetSettings->m_name);
int i = 0; int i = 0;
for (const PlatformName& filemask : presetSettings->m_fileMasks) for (const auto& filemask : fileMasks)
{ {
conventionText += i > 0 ? " " + filemask : filemask; conventionText += i > 0 ? " " + filemask : filemask;
i++; i++;

@ -905,68 +905,6 @@ namespace ImageProcessingAtom
return result; return result;
} }
IImageObjectPtr MergeOutputImageForPreview(IImageObjectPtr image, IImageObjectPtr alphaImage)
{
if (!image)
{
return IImageObjectPtr();
}
ImageToProcess imageToProcess(image);
imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
IImageObjectPtr previewImage = imageToProcess.Get();
// If there is separate Alpha image, combine it with output
if (alphaImage)
{
// Create pixel operation function for rgb and alpha images
IPixelOperationPtr imageOp = CreatePixelOperation(ePixelFormat_R8G8B8A8);
IPixelOperationPtr alphaOp = CreatePixelOperation(ePixelFormat_A8);
// Convert the alpha image to A8 first
ImageToProcess imageToProcess2(alphaImage);
imageToProcess2.ConvertFormat(ePixelFormat_A8);
IImageObjectPtr previewImageAlpha = imageToProcess2.Get();
const uint32 imageMips = previewImage->GetMipCount();
[[maybe_unused]] const uint32 alphaMips = previewImageAlpha->GetMipCount();
// Get count of bytes per pixel for both rgb and alpha images
uint32 imagePixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat_R8G8B8A8)->bitsPerBlock / 8;
uint32 alphaPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat_A8)->bitsPerBlock / 8;
AZ_Assert(imageMips <= alphaMips, "Mip level of alpha image is less than origin image!");
// For each mip level, set the alpha value to the image
for (uint32 mipLevel = 0; mipLevel < imageMips; ++mipLevel)
{
const uint32 pixelCount = previewImage->GetPixelCount(mipLevel);
[[maybe_unused]] const uint32 alphaPixelCount = previewImageAlpha->GetPixelCount(mipLevel);
AZ_Assert(pixelCount == alphaPixelCount, "Pixel count for image and alpha image at mip level %d is not equal!", mipLevel);
uint8* imageBuf;
uint32 pitch;
previewImage->GetImagePointer(mipLevel, imageBuf, pitch);
uint8* alphaBuf;
uint32 alphaPitch;
previewImageAlpha->GetImagePointer(mipLevel, alphaBuf, alphaPitch);
float rAlpha, gAlpha, bAlpha, aAlpha, rImage, gImage, bImage, aImage;
for (uint32 i = 0; i < pixelCount; ++i, imageBuf += imagePixelBytes, alphaBuf += alphaPixelBytes)
{
alphaOp->GetRGBA(alphaBuf, rAlpha, gAlpha, bAlpha, aAlpha);
imageOp->GetRGBA(imageBuf, rImage, gImage, bImage, aImage);
imageOp->SetRGBA(imageBuf, rImage, gImage, bImage, aAlpha);
}
}
}
return previewImage;
}
IImageObjectPtr ConvertImageForPreview(IImageObjectPtr image) IImageObjectPtr ConvertImageForPreview(IImageObjectPtr image)
{ {
if (!image) if (!image)

@ -51,9 +51,6 @@ namespace ImageProcessingAtom
//Converts the image to a RGBA8 format that can be displayed in a preview UI. //Converts the image to a RGBA8 format that can be displayed in a preview UI.
IImageObjectPtr ConvertImageForPreview(IImageObjectPtr image); IImageObjectPtr ConvertImageForPreview(IImageObjectPtr image);
//Combine image with alpha image if any and output as RGBA8
IImageObjectPtr MergeOutputImageForPreview(IImageObjectPtr image, IImageObjectPtr alphaImage);
//get output image size and mip count based on the texture setting and preset setting //get output image size and mip count based on the texture setting and preset setting
//other helper functions //other helper functions

@ -16,28 +16,14 @@
namespace ImageProcessingAtom namespace ImageProcessingAtom
{ {
IImageObjectPtr ImageConvertOutput::GetOutputImage(OutputImageType type) const IImageObjectPtr ImageConvertOutput::GetOutputImage() const
{ {
if (type < OutputImageType::Count) return m_outputImage;
{
return m_outputImage[static_cast<int>(type)];
}
else
{
return IImageObjectPtr();
}
} }
void ImageConvertOutput::SetOutputImage(IImageObjectPtr image, OutputImageType type) void ImageConvertOutput::SetOutputImage(IImageObjectPtr image)
{ {
if (type < OutputImageType::Count) m_outputImage = image;
{
m_outputImage[static_cast<int>(type)] = image;
}
else
{
AZ_Error("ImageProcess", false, "Cannot set output image to %d", type);
}
} }
void ImageConvertOutput::SetReady(bool ready) void ImageConvertOutput::SetReady(bool ready)
@ -62,10 +48,7 @@ namespace ImageProcessingAtom
void ImageConvertOutput::Reset() void ImageConvertOutput::Reset()
{ {
for (int i = 0; i < static_cast<int>(OutputImageType::Count); i++) m_outputImage = nullptr;
{
m_outputImage[i] = nullptr;
}
m_outputReady = false; m_outputReady = false;
m_progress = 0.0f; m_progress = 0.0f;
} }
@ -109,13 +92,12 @@ namespace ImageProcessingAtom
IImageObjectPtr outputImage = m_process->GetOutputImage(); IImageObjectPtr outputImage = m_process->GetOutputImage();
m_output->SetOutputImage(outputImage, ImageConvertOutput::Base);
if (!IsJobCancelled()) if (!IsJobCancelled())
{ {
// For preview, combine image output with alpha if any // convert the output image to RGBA format for preview
m_output->SetProgress(1.0f / static_cast<float>(m_previewProcessStep)); m_output->SetProgress(1.0f / static_cast<float>(m_previewProcessStep));
m_output->SetOutputImage(outputImage, ImageConvertOutput::Preview); IImageObjectPtr uncompressedImage = ConvertImageForPreview(outputImage);
m_output->SetOutputImage(uncompressedImage);
} }
m_output->SetReady(true); m_output->SetReady(true);

@ -21,16 +21,8 @@ namespace ImageProcessingAtom
class ImageConvertOutput class ImageConvertOutput
{ {
public: public:
enum OutputImageType IImageObjectPtr GetOutputImage() const;
{ void SetOutputImage(IImageObjectPtr image);
Base = 0, // Might contains alpha or not
Alpha, // Separate alpha image
Preview, // Combine base image with alpha if any, format RGBA8
Count
};
IImageObjectPtr GetOutputImage(OutputImageType type) const;
void SetOutputImage(IImageObjectPtr image, OutputImageType type);
void SetReady(bool ready); void SetReady(bool ready);
bool IsReady() const; bool IsReady() const;
float GetProgress() const; float GetProgress() const;
@ -38,7 +30,7 @@ namespace ImageProcessingAtom
void Reset(); void Reset();
private: private:
IImageObjectPtr m_outputImage[OutputImageType::Count]; IImageObjectPtr m_outputImage;
bool m_outputReady = false; bool m_outputReady = false;
float m_progress = 0.0f; float m_progress = 0.0f;
}; };

@ -86,7 +86,7 @@ namespace ImageProcessingAtom
IImageObjectPtr ImagePreview::GetOutputImage() IImageObjectPtr ImagePreview::GetOutputImage()
{ {
return m_output.GetOutputImage(ImageConvertOutput::Preview); return m_output.GetOutputImage();
} }
ImagePreview::~ImagePreview() ImagePreview::~ImagePreview()

Loading…
Cancel
Save