Merge pull request #7590 from aws-lumberyard-dev/cgalvan/AllowOnlySupportedFormatsForImageGradientStreamingAsset

Only allow streaming image assets with supported pixel formats to be selected for an image gradient
monroegm-disable-blank-issue-2
Chris Galvan 4 years ago committed by GitHub
commit b334b1ad98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -82,7 +82,7 @@ namespace AzToolsFramework
});
connect(m_ui->m_assetBrowserTreeViewWidget, &QAbstractItemView::doubleClicked, this, &AssetPickerDialog::DoubleClickedSlot);
connect(m_ui->m_assetBrowserTreeViewWidget, &AssetBrowserTreeView::selectionChangedSignal, this,
[this](const QItemSelection&, const QItemSelection&){ AssetPickerDialog::SelectionChangedSlot(); });
[this](const QItemSelection&, const QItemSelection&){ SelectionChangedSlot(); });
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
@ -153,7 +153,7 @@ namespace AzToolsFramework
m_ui->m_assetBrowserTableViewWidget, &AssetBrowserTableView::selectionChangedSignal, this,
[this](const QItemSelection&, const QItemSelection&)
{
AssetPickerDialog::SelectionChangedSlot();
SelectionChangedSlot();
});
connect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AssetPickerDialog::DoubleClickedSlot);
@ -174,8 +174,15 @@ namespace AzToolsFramework
m_tableModel->UpdateTableModelMaps();
}
QTimer::singleShot(0, this, &AssetPickerDialog::RestoreState);
QTimer::singleShot(0, this, [this]() {
RestoreState();
// The selection doesn't propagate immediately, so we need to delay
// it as well so that the OK button can be updated appropriately.
// Otherwise, it will always be disabled when you first launch
// the asset picker dialog.
SelectionChangedSlot();
});
}
AssetPickerDialog::~AssetPickerDialog() = default;

@ -58,16 +58,16 @@ namespace AzToolsFramework
void keyPressEvent(QKeyEvent* e) override;
void resizeEvent(QResizeEvent* resizeEvent) override;
private Q_SLOTS:
protected Q_SLOTS:
void DoubleClickedSlot(const QModelIndex& index);
void SelectionChangedSlot();
void RestoreState();
void OnFilterUpdated();
private:
protected:
//! Evaluate whether current selection is valid.
//! Valid selection requires exactly one item to be selected, must be source or product type, and must match the wildcard filter
bool EvaluateSelection() const;
virtual bool EvaluateSelection() const;
void UpdatePreview() const;
void SaveState();

@ -813,7 +813,7 @@ namespace AzToolsFramework
selection.SetDisplayFilter(FilterConstType(compFilter));
}
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget());
PickAssetSelectionFromDialog(selection, parentWidget());
if (selection.IsValid())
{
const auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
@ -831,6 +831,11 @@ namespace AzToolsFramework
}
}
void PropertyAssetCtrl::PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent)
{
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parent);
}
void PropertyAssetCtrl::OnClearButtonClicked()
{
ClearAssetInternal();
@ -1524,7 +1529,7 @@ namespace AzToolsFramework
ConsumeAttributeInternal(GUI, attrib, attrValue, debugName);
}
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
void AssetPropertyHandlerDefault::WriteGUIValuesIntoPropertyInternal(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
{
(void)index;
(void)node;
@ -1539,7 +1544,12 @@ namespace AzToolsFramework
}
}
bool AssetPropertyHandlerDefault::ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
{
WriteGUIValuesIntoPropertyInternal(index, GUI, instance, node);
}
bool AssetPropertyHandlerDefault::ReadValuesIntoGUIInternal(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
{
(void)index;
(void)node;
@ -1559,6 +1569,11 @@ namespace AzToolsFramework
return false;
}
bool AssetPropertyHandlerDefault::ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
{
return ReadValuesIntoGUIInternal(index, GUI, instance, node);
}
QWidget* SimpleAssetPropertyHandlerDefault::CreateGUI(QWidget* pParent)
{
PropertyAssetCtrl* newCtrl = aznew PropertyAssetCtrl(pParent);

@ -244,6 +244,7 @@ namespace AzToolsFramework
void SetCurrentAssetHint(const AZStd::string& hint);
void SetDefaultAssetID(const AZ::Data::AssetId& defaultID);
virtual void PopupAssetPicker();
virtual void PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent);
void OnClearButtonClicked();
void UpdateAssetDisplay();
void OnLineEditFocus(bool focus);
@ -280,7 +281,9 @@ namespace AzToolsFramework
virtual QWidget* CreateGUI(QWidget* pParent) override;
static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName);
void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
static void WriteGUIValuesIntoPropertyInternal(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node);
virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override;
static bool ReadValuesIntoGUIInternal(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node);
virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override;
};

@ -60,6 +60,10 @@ namespace AZ
//! Same as above. Provided as a convenience when all arguments of the 'numthreads' attributes should be assigned to RHI::DispatchDirect::m_threadsPerGroup* variables.
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, RHI::DispatchDirect& dispatchDirect);
//! Returns true/false if the specified format is supported by the image data pixel retrieval APIs
//! GetImageDataPixelValue, GetSubImagePixelValue, and GetSubImagePixelValues
bool IsImageDataPixelAPISupported(AZ::RHI::Format format);
//! Get single image pixel value from raw image data
//! This assumes the imageData is not empty
template<typename T>

@ -443,6 +443,61 @@ namespace AZ
return GetComputeShaderNumThreads(shaderAsset, &dispatchDirect.m_threadsPerGroupX, &dispatchDirect.m_threadsPerGroupY, &dispatchDirect.m_threadsPerGroupZ);
}
bool IsImageDataPixelAPISupported(AZ::RHI::Format format)
{
switch (format)
{
// Float types
case AZ::RHI::Format::R8_UNORM:
case AZ::RHI::Format::A8_UNORM:
case AZ::RHI::Format::R8G8_UNORM:
case AZ::RHI::Format::R8G8B8A8_UNORM:
case AZ::RHI::Format::R8_SNORM:
case AZ::RHI::Format::R8G8_SNORM:
case AZ::RHI::Format::R8G8B8A8_SNORM:
case AZ::RHI::Format::D16_UNORM:
case AZ::RHI::Format::R16_UNORM:
case AZ::RHI::Format::R16G16_UNORM:
case AZ::RHI::Format::R16G16B16A16_UNORM:
case AZ::RHI::Format::R16_SNORM:
case AZ::RHI::Format::R16G16_SNORM:
case AZ::RHI::Format::R16G16B16A16_SNORM:
case AZ::RHI::Format::R16_FLOAT:
case AZ::RHI::Format::R16G16_FLOAT:
case AZ::RHI::Format::R16G16B16A16_FLOAT:
case AZ::RHI::Format::D32_FLOAT:
case AZ::RHI::Format::R32_FLOAT:
case AZ::RHI::Format::R32G32_FLOAT:
case AZ::RHI::Format::R32G32B32_FLOAT:
case AZ::RHI::Format::R32G32B32A32_FLOAT:
// Unsigned integer types
case AZ::RHI::Format::R8_UINT:
case AZ::RHI::Format::R8G8_UINT:
case AZ::RHI::Format::R8G8B8A8_UINT:
case AZ::RHI::Format::R16_UINT:
case AZ::RHI::Format::R16G16_UINT:
case AZ::RHI::Format::R16G16B16A16_UINT:
case AZ::RHI::Format::R32_UINT:
case AZ::RHI::Format::R32G32_UINT:
case AZ::RHI::Format::R32G32B32_UINT:
case AZ::RHI::Format::R32G32B32A32_UINT:
// Signed integer types
case AZ::RHI::Format::R8_SINT:
case AZ::RHI::Format::R8G8_SINT:
case AZ::RHI::Format::R8G8B8A8_SINT:
case AZ::RHI::Format::R16_SINT:
case AZ::RHI::Format::R16G16_SINT:
case AZ::RHI::Format::R16G16B16A16_SINT:
case AZ::RHI::Format::R32_SINT:
case AZ::RHI::Format::R32G32_SINT:
case AZ::RHI::Format::R32G32B32_SINT:
case AZ::RHI::Format::R32G32B32A32_SINT:
return true;
}
return false;
}
template<>
float GetImageDataPixelValue<float>(AZStd::span<const uint8_t> imageData, const AZ::RHI::ImageDescriptor& imageDescriptor, uint32_t x, uint32_t y, uint32_t componentIndex)
{

@ -58,6 +58,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME GradientSignal.Editor.Static STATIC
NAMESPACE Gem
AUTOMOC
FILES_CMAKE
gradientsignal_editor_files.cmake
INCLUDE_DIRECTORIES

@ -127,6 +127,7 @@ namespace GradientSignal
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(0, &ImageGradientConfig::m_imageAsset, "Image Asset", "Image asset whose values will be mapped as gradient output.")
->Attribute(AZ::Edit::Attributes::Handler, AZ_CRC_CE("GradientSignalStreamingImageAsset"))
->DataElement(AZ::Edit::UIHandlers::Slider, &ImageGradientConfig::m_tilingX, "Tiling X", "Number of times to tile horizontally.")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->Attribute(AZ::Edit::Attributes::SoftMin, 1.0f)

@ -0,0 +1,150 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RPI.Public/RPIUtils.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <Editor/EditorStreamingImageAssetCtrl.h>
namespace GradientSignal
{
namespace Internal
{
bool IsImageDataPixelAPISupportedForAsset(const AZ::Data::AssetId& assetId)
{
auto streamingImageAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::StreamingImageAsset>(assetId, AZ::Data::AssetLoadBehavior::PreLoad);
streamingImageAsset.BlockUntilLoadComplete();
// Verify if the streaming image asset has a pixel format that is supported
// for the image data pixel retrieval API
AZ::RHI::Format format = streamingImageAsset->GetImageDescriptor().m_format;
return AZ::RPI::IsImageDataPixelAPISupported(format);
}
}
SupportedImageAssetPickerDialog::SupportedImageAssetPickerDialog(AssetSelectionModel& selection, QWidget* parent)
: AzToolsFramework::AssetBrowser::AssetPickerDialog(selection, parent)
{
}
bool SupportedImageAssetPickerDialog::EvaluateSelection() const
{
bool isValid = AzToolsFramework::AssetBrowser::AssetPickerDialog::EvaluateSelection();
// If we have a valid selection (a streaming image asset), we need to also verify
// that its pixel format is supported by the image data retrieval API
if (isValid)
{
const auto productEntry = azrtti_cast<const ProductAssetBrowserEntry*>(m_selection.GetResult());
isValid = Internal::IsImageDataPixelAPISupportedForAsset(productEntry->GetAssetId());
}
return isValid;
}
StreamingImagePropertyAssetCtrl::StreamingImagePropertyAssetCtrl(QWidget* parent)
: AzToolsFramework::PropertyAssetCtrl(parent)
{
}
void StreamingImagePropertyAssetCtrl::PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent)
{
// We need to override and use our own picker dialog so that we can
// disable the OK button if a streaming image asset with an unsupported
// format has been selected
SupportedImageAssetPickerDialog dialog(selection, parent);
dialog.exec();
}
void StreamingImagePropertyAssetCtrl::OnAutocomplete(const QModelIndex& index)
{
auto assetId = m_model->GetAssetIdFromIndex(GetSourceIndex(index));
// Only allow the autocompleter to select an asset if it has
// a supported pixel format
if (Internal::IsImageDataPixelAPISupportedForAsset(assetId))
{
SetSelectedAssetID(assetId);
}
}
AZ::u32 StreamingImagePropertyHandler::GetHandlerName() const
{
return AZ_CRC_CE("GradientSignalStreamingImageAsset");
}
bool StreamingImagePropertyHandler::IsDefaultHandler() const
{
// We don't this to be registered as a default handler, because we don't want
// any other AZ::RPI::StreamingImageAsset fields using this handler.
// We only want this handler to be used if it was explicitly requested by name,
// which in this case is for the image gradient asset since it needs to validate
// the format is supported by the pixel retrieval API.
return false;
}
QWidget* StreamingImagePropertyHandler::GetFirstInTabOrder(StreamingImagePropertyAssetCtrl* widget)
{
return widget->GetFirstInTabOrder();
}
QWidget* StreamingImagePropertyHandler::GetLastInTabOrder(StreamingImagePropertyAssetCtrl* widget)
{
return widget->GetLastInTabOrder();
}
void StreamingImagePropertyHandler::UpdateWidgetInternalTabbing(StreamingImagePropertyAssetCtrl* widget)
{
widget->UpdateTabOrder();
}
QWidget* StreamingImagePropertyHandler::CreateGUI(QWidget* parent)
{
// This is the same logic as the AssetPropertyHandlerDefault, only we create our own
// StreamingImagePropertyAssetCtrl instead for the GUI widget
StreamingImagePropertyAssetCtrl* newCtrl = aznew StreamingImagePropertyAssetCtrl(parent);
QObject::connect(newCtrl, &StreamingImagePropertyAssetCtrl::OnAssetIDChanged, this, [newCtrl](AZ::Data::AssetId newAssetID)
{
(void)newAssetID;
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, newCtrl);
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::OnEditingFinished, newCtrl);
});
return newCtrl;
}
void StreamingImagePropertyHandler::ConsumeAttribute(StreamingImagePropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
// Let the AssetPropertyHandlerDefault handle all of the attributes
AzToolsFramework::AssetPropertyHandlerDefault::ConsumeAttributeInternal(GUI, attrib, attrValue, debugName);
}
void StreamingImagePropertyHandler::WriteGUIValuesIntoProperty(size_t index, StreamingImagePropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
// Let the AssetPropertyHandlerDefault handle writing the GUI value into the property
AzToolsFramework::AssetPropertyHandlerDefault::WriteGUIValuesIntoPropertyInternal(index, GUI, instance, node);
}
bool StreamingImagePropertyHandler::ReadValuesIntoGUI(size_t index, StreamingImagePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
// Let the AssetPropertyHandlerDefault handle reading values into the GUI
return AzToolsFramework::AssetPropertyHandlerDefault::ReadValuesIntoGUIInternal(index, GUI, instance, node);
}
void StreamingImagePropertyHandler::Register()
{
using namespace AzToolsFramework;
PropertyTypeRegistrationMessages::Bus::Broadcast(
&PropertyTypeRegistrationMessages::Bus::Events::RegisterPropertyType, aznew StreamingImagePropertyHandler());
}
}

@ -0,0 +1,75 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx>
#endif
namespace GradientSignal
{
class SupportedImageAssetPickerDialog
: public AzToolsFramework::AssetBrowser::AssetPickerDialog
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(SupportedImageAssetPickerDialog, AZ::SystemAllocator, 0);
explicit SupportedImageAssetPickerDialog(AssetSelectionModel& selection, QWidget* parent = nullptr);
protected:
bool EvaluateSelection() const override;
};
class StreamingImagePropertyAssetCtrl
: public AzToolsFramework::PropertyAssetCtrl
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(StreamingImagePropertyAssetCtrl, AZ::SystemAllocator, 0);
StreamingImagePropertyAssetCtrl(QWidget* parent = nullptr);
void PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent) override;
public Q_SLOTS:
void OnAutocomplete(const QModelIndex& index) override;
};
//! We need a custom asset property handler for the AZ::RPI::StreamingImageAsset on our
//! Image Gradient component because only a subset of the streaming image asset pixel formats
//! are currently supported by the image data pixel retrieval API that the Image Gradient
//! relies on
class StreamingImagePropertyHandler
: QObject
, public AzToolsFramework::PropertyHandler<AZ::Data::Asset<AZ::Data::AssetData>, StreamingImagePropertyAssetCtrl>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(StreamingImagePropertyHandler, AZ::SystemAllocator, 0);
AZ::u32 GetHandlerName() const override;
bool IsDefaultHandler() const override;
QWidget* GetFirstInTabOrder(StreamingImagePropertyAssetCtrl* widget) override;
QWidget* GetLastInTabOrder(StreamingImagePropertyAssetCtrl* widget) override;
void UpdateWidgetInternalTabbing(StreamingImagePropertyAssetCtrl* widget);
QWidget* CreateGUI(QWidget* parent) override;
void ConsumeAttribute(StreamingImagePropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, StreamingImagePropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, StreamingImagePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
static void Register();
};
}

@ -24,6 +24,7 @@
#include <Editor/EditorPerlinGradientComponent.h>
#include <Editor/EditorRandomGradientComponent.h>
#include <Editor/EditorGradientTransformComponent.h>
#include <Editor/EditorStreamingImageAssetCtrl.h>
#include <Editor/EditorSurfaceMaskGradientComponent.h>
#include <Editor/EditorGradientSurfaceDataComponent.h>
#include <GradientSignal/Editor/EditorGradientComponentBase.h>
@ -112,11 +113,14 @@ namespace GradientSignal
void GradientSignalEditorSystemComponent::Activate()
{
GradientPreviewDataWidgetHandler::Register();
StreamingImagePropertyHandler::Register();
}
void GradientSignalEditorSystemComponent::Deactivate()
{
GradientPreviewDataWidgetHandler::Unregister();
// We don't need to unregister the StreamingImagePropertyHandler
// because its set to auto-delete (default)
}
}

@ -47,6 +47,8 @@ set(FILES
Source/Editor/EditorShapeAreaFalloffGradientComponent.h
Source/Editor/EditorSmoothStepGradientComponent.cpp
Source/Editor/EditorSmoothStepGradientComponent.h
Source/Editor/EditorStreamingImageAssetCtrl.cpp
Source/Editor/EditorStreamingImageAssetCtrl.h
Source/Editor/EditorSurfaceAltitudeGradientComponent.cpp
Source/Editor/EditorSurfaceAltitudeGradientComponent.h
Source/Editor/EditorSurfaceMaskGradientComponent.cpp

Loading…
Cancel
Save