Merge branch 'stabilization/2110' of https://github.com/aws-lumberyard-dev/o3de into scripting/4060

monroegm-disable-blank-issue-2
lsemp3d 4 years ago
commit 6c25e08d3f

@ -31,7 +31,7 @@ def Terrain_SupportsPhysics():
Test Steps:
1) Load the base level
2) Create 2 test entities, one parent at 512.0, 512.0, 50.0 and one child at the default position and add the required components
2a) Create a ball at 600.0, 600.0, 46.0 - This position is bot too high over the heighfield so will collide in a reasonable time
2a) Create a ball at 600.0, 600.0, 46.0 - This position is not too high over the heightfield so will collide in a reasonable time
3) Start the Tracer to catch any errors and warnings
4) Change the Axis Aligned Box Shape dimensions
5) Set the Vegetation Shape reference to TestEntity1
@ -80,7 +80,7 @@ def Terrain_SupportsPhysics():
height_provider_entity = hydra.Entity("TestEntity2")
height_provider_entity.create_entity(azmath.Vector3(0.0, 0.0, 0.0), entity2_components_to_add,terrain_spawner_entity.id)
Report.result(Tests.create_height_provider_entity, height_provider_entity.id.IsValid())
# 2a) Create a ball at 600.0, 600.0, 46.0 - This position is bot too high over the heighfield so will collide in a reasonable time
# 2a) Create a ball at 600.0, 600.0, 46.0 - This position is not too high over the heightfield so will collide in a reasonable time
ball = hydra.Entity("Ball")
ball.create_entity(azmath.Vector3(600.0, 600.0, 46.0), ball_components_to_add)
Report.result(Tests.create_test_ball, ball.id.IsValid())
@ -107,9 +107,9 @@ def Terrain_SupportsPhysics():
Report.result(Tests.frequency_changed, math.isclose(Frequency, FrequencyVal, abs_tol = 0.00001))
# 7) Set the Gradient List to TestEntity2
pte = hydra.get_property_tree(terrain_spawner_entity.components[2])
pte.add_container_item("Configuration|Gradient Entities", 0, height_provider_entity.id)
checkID = pte.get_container_item("Configuration|Gradient Entities", 0)
propertyTree = hydra.get_property_tree(terrain_spawner_entity.components[2])
propertyTree.add_container_item("Configuration|Gradient Entities", 0, height_provider_entity.id)
checkID = propertyTree.get_container_item("Configuration|Gradient Entities", 0)
Report.result(Tests.entity_added, checkID.GetValue() == height_provider_entity.id)
# 8) Set the PhysX Collider to Sphere mode

@ -13,15 +13,15 @@ import os
import sys
from ly_test_tools import LAUNCHERS
from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest
from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSharedTest
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(EditorTestSuite):
class test_AxisAlignedBoxShape_ConfigurationWorks(EditorSingleTest):
class test_AxisAlignedBoxShape_ConfigurationWorks(EditorSharedTest):
from .EditorScripts import TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges as test_module
class test_Terrain_SupportsPhysics(EditorSingleTest):
class test_Terrain_SupportsPhysics(EditorSharedTest):
from .EditorScripts import Terrain_SupportsPhysics as test_module

@ -234,7 +234,7 @@ void Q2DViewport::UpdateContent(int flags)
}
//////////////////////////////////////////////////////////////////////////
void Q2DViewport::OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
void Q2DViewport::OnRButtonDown([[maybe_unused]] Qt::KeyboardModifiers modifiers, const QPoint& point)
{
if (GetIEditor()->IsInGameMode())
{
@ -246,9 +246,6 @@ void Q2DViewport::OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& p
setFocus();
}
// Check Edit Tool.
MouseCallback(eMouseRDown, point, modifiers);
SetCurrentCursor(STD_CURSOR_MOVE, QString());
// Save the mouse down position
@ -273,17 +270,8 @@ void Q2DViewport::OnRButtonUp([[maybe_unused]] Qt::KeyboardModifiers modifiers,
}
//////////////////////////////////////////////////////////////////////////
void Q2DViewport::OnMButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
void Q2DViewport::OnMButtonDown([[maybe_unused]] Qt::KeyboardModifiers modifiers, const QPoint& point)
{
////////////////////////////////////////////////////////////////////////
// User pressed the middle mouse button
////////////////////////////////////////////////////////////////////////
// Check Edit Tool.
if (MouseCallback(eMouseMDown, point, modifiers))
{
return;
}
// Save the mouse down position
m_RMouseDownPos = point;
@ -300,14 +288,8 @@ void Q2DViewport::OnMButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& p
}
//////////////////////////////////////////////////////////////////////////
void Q2DViewport::OnMButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
void Q2DViewport::OnMButtonUp([[maybe_unused]] Qt::KeyboardModifiers modifiers, [[maybe_unused]] const QPoint& point)
{
// Check Edit Tool.
if (MouseCallback(eMouseMUp, point, modifiers))
{
return;
}
SetViewMode(NothingMode);
ReleaseMouse();

@ -2307,10 +2307,10 @@ void* EditorViewportWidget::GetSystemCursorConstraintWindow() const
return systemCursorConstrained ? renderOverlayHWND() : nullptr;
}
void EditorViewportWidget::BuildDragDropContext(AzQtComponents::ViewportDragContext& context, const QPoint& pt)
void EditorViewportWidget::BuildDragDropContext(
AzQtComponents::ViewportDragContext& context, const AzFramework::ViewportId viewportId, const QPoint& point)
{
const auto scaledPoint = WidgetToViewport(pt);
QtViewport::BuildDragDropContext(context, scaledPoint);
QtViewport::BuildDragDropContext(context, viewportId, point);
}
void EditorViewportWidget::RestoreViewportAfterGameMode()

@ -273,7 +273,8 @@ private:
bool CheckRespondToInput() const;
void BuildDragDropContext(AzQtComponents::ViewportDragContext& context, const QPoint& pt) override;
void BuildDragDropContext(
AzQtComponents::ViewportDragContext& context, AzFramework::ViewportId viewportId, const QPoint& point) override;
void SetAsActiveViewport();
void PushDisableRendering();

@ -10,7 +10,6 @@
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/RTTI/AttributeReader.h>
@ -57,6 +56,7 @@
#include <AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx>
#include <AzToolsFramework/UI/Layer/NameConflictWarning.hxx>
#include <AzToolsFramework/ViewportSelection/EditorHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <MathConversion.h>
#include <Atom/RPI.Public/ViewportContext.h>
@ -1394,13 +1394,13 @@ void SandboxIntegrationManager::ContextMenu_NewEntity()
{
AZ::Vector3 worldPosition = AZ::Vector3::CreateZero();
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
// If we don't have a viewport active to aid in placement, the object
// will be created at the origin.
if (view)
if (CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport())
{
const QPoint viewPoint(static_cast<int>(m_contextMenuViewPoint.GetX()), static_cast<int>(m_contextMenuViewPoint.GetY()));
worldPosition = view->GetHitLocation(viewPoint);
worldPosition = AzToolsFramework::FindClosestPickIntersection(
view->GetViewportId(), AzFramework::ScreenPointFromVector2(m_contextMenuViewPoint), AzToolsFramework::EditorPickRayLength,
GetDefaultEntityPlacementDistance());
}
CreateNewEntityAtPosition(worldPosition);

@ -14,14 +14,19 @@
// Qt
#include <QPainter>
// AzCore
#include <AzCore/Console/IConsole.h>
// AzQtComponents
#include <AzQtComponents/DragAndDrop/ViewportDragAndDrop.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
// Editor
#include "Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h"
#include "ViewManager.h"
#include "Include/ITransformManipulator.h"
#include "Include/HitContext.h"
@ -32,22 +37,35 @@
#include "GameEngine.h"
#include "Settings.h"
#ifdef LoadCursor
#undef LoadCursor
#endif
AZ_CVAR(
float,
ed_defaultEntityPlacementDistance,
10.0f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"The default distance to place an entity from the camera if no intersection is found");
float GetDefaultEntityPlacementDistance()
{
return ed_defaultEntityPlacementDistance;
}
//////////////////////////////////////////////////////////////////////
// Viewport drag and drop support
//////////////////////////////////////////////////////////////////////
void QtViewport::BuildDragDropContext(AzQtComponents::ViewportDragContext& context, const QPoint& pt)
void QtViewport::BuildDragDropContext(
AzQtComponents::ViewportDragContext& context, const AzFramework::ViewportId viewportId, const QPoint& point)
{
context.m_hitLocation = AZ::Vector3::CreateZero();
context.m_hitLocation = GetHitLocation(pt);
context.m_hitLocation = AzToolsFramework::FindClosestPickIntersection(
viewportId, AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(point), AzToolsFramework::EditorPickRayLength,
GetDefaultEntityPlacementDistance());
}
void QtViewport::dragEnterEvent(QDragEnterEvent* event)
{
if (!GetIEditor()->GetGameEngine()->IsLevelLoaded())
@ -66,7 +84,7 @@ void QtViewport::dragEnterEvent(QDragEnterEvent* event)
// new bus-based way of doing it (install a listener!)
using namespace AzQtComponents;
ViewportDragContext context;
BuildDragDropContext(context, event->pos());
BuildDragDropContext(context, GetViewportId(), event->pos());
DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragEnter, event, context);
}
}
@ -89,7 +107,7 @@ void QtViewport::dragMoveEvent(QDragMoveEvent* event)
// new bus-based way of doing it (install a listener!)
using namespace AzQtComponents;
ViewportDragContext context;
BuildDragDropContext(context, event->pos());
BuildDragDropContext(context, GetViewportId(), event->pos());
DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragMove, event, context);
}
}
@ -112,7 +130,7 @@ void QtViewport::dropEvent(QDropEvent* event)
{
// new bus-based way of doing it (install a listener!)
ViewportDragContext context;
BuildDragDropContext(context, event->pos());
BuildDragDropContext(context, GetViewportId(), event->pos());
DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::Drop, event, context);
}
}
@ -340,13 +358,6 @@ void QtViewport::resizeEvent(QResizeEvent* event)
Update();
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::leaveEvent(QEvent* event)
{
QWidget::leaveEvent(event);
MouseCallback(eMouseLeave, QPoint(), Qt::KeyboardModifiers(), Qt::MouseButtons());
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::paintEvent([[maybe_unused]] QPaintEvent* event)
{
@ -581,63 +592,7 @@ void QtViewport::keyReleaseEvent(QKeyEvent* event)
OnKeyUp(nativeKey, 1, event->nativeModifiers());
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnLButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Save the mouse down position
m_cMouseDownPos = point;
if (MouseCallback(eMouseLDown, point, modifiers))
{
return;
}
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnLButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Check Edit Tool.
MouseCallback(eMouseLUp, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseRDown, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnRButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseRUp, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Check Edit Tool.
MouseCallback(eMouseMDown, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Move the viewer to the mouse location.
// Check Edit Tool.
MouseCallback(eMouseMUp, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseMDblClick, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMouseMove(Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint& point)
{
MouseCallback(eMouseMove, point, modifiers, buttons);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnSetCursor()
@ -696,44 +651,6 @@ void QtViewport::OnDragSelectRectangle(const QRect& rect, bool bNormalizeRect)
GetIEditor()->SetStatusText(szNewStatusText);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnLButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
if (GetIEditor()->IsInGameMode())
{
// Ignore double clicks while in game.
return;
}
MouseCallback(eMouseLDblClick, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnRButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseRDblClick, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnKeyDown([[maybe_unused]] UINT nChar, [[maybe_unused]] UINT nRepCnt, [[maybe_unused]] UINT nFlags)
{
if (GetIEditor()->IsInGameMode())
{
// Ignore key downs while in game.
return;
}
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnKeyUp([[maybe_unused]] UINT nChar, [[maybe_unused]] UINT nRepCnt, [[maybe_unused]] UINT nFlags)
{
if (GetIEditor()->IsInGameMode())
{
// Ignore key downs while in game.
return;
}
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::SetCurrentCursor(const QCursor& hCursor, const QString& cursorString)
{
@ -1119,29 +1036,6 @@ bool QtViewport::HitTest(const QPoint& point, HitContext& hitInfo)
return false;
}
AZ::Vector3 QtViewport::GetHitLocation(const QPoint& point)
{
Vec3 pos = Vec3(ZERO);
HitContext hit;
if (HitTest(point, hit))
{
pos = hit.raySrc + hit.rayDir * hit.dist;
pos = SnapToGrid(pos);
}
else
{
bool hitTerrain;
pos = ViewToWorld(point, &hitTerrain);
if (hitTerrain)
{
pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
}
pos = SnapToGrid(pos);
}
return AZ::Vector3(pos.x, pos.y, pos.z);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::SetZoomFactor(float fZoomFactor)
{
@ -1315,84 +1209,6 @@ bool QtViewport::GetAdvancedSelectModeFlag()
return m_bAdvancedSelectMode;
}
//////////////////////////////////////////////////////////////////////////
bool QtViewport::MouseCallback(EMouseEvent event, const QPoint& point, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons)
{
AZ_PROFILE_FUNCTION(Editor);
// Ignore any mouse events in game mode.
if (GetIEditor()->IsInGameMode())
{
return true;
}
// We must ignore mouse events when we are in the middle of an assert.
// Reason: If we have an assert called from an engine module under the editor, if we call this function,
// it may call the engine again and cause a deadlock.
// Concrete example: CryPhysics called from Trackview causing an assert, and moving the cursor over the viewport
// would cause the editor to freeze as it calls CryPhysics again for a raycast while it didn't release the lock.
if (gEnv->pSystem->IsAssertDialogVisible())
{
return true;
}
//////////////////////////////////////////////////////////////////////////
// Hit test gizmo objects.
//////////////////////////////////////////////////////////////////////////
bool bAltClick = (modifiers & Qt::AltModifier);
bool bCtrlClick = (modifiers & Qt::ControlModifier);
bool bShiftClick = (modifiers & Qt::ShiftModifier);
int flags = (bCtrlClick ? MK_CONTROL : 0) |
(bShiftClick ? MK_SHIFT : 0) |
((buttons& Qt::LeftButton) ? MK_LBUTTON : 0) |
((buttons& Qt::MiddleButton) ? MK_MBUTTON : 0) |
((buttons& Qt::RightButton) ? MK_RBUTTON : 0);
switch (event)
{
case eMouseMove:
if (m_nLastUpdateFrame == m_nLastMouseMoveFrame)
{
// If mouse move event generated in the same frame, ignore it.
return false;
}
m_nLastMouseMoveFrame = m_nLastUpdateFrame;
// Skip the marker position update if anything is selected, since it is only used
// by the info bar which doesn't show the marker when there is an active selection.
// This helps a performance issue when calling ViewToWorld (which calls RayWorldIntersection)
// on every mouse movement becomes very expensive in scenes with large amounts of entities.
CSelectionGroup* selection = GetIEditor()->GetSelection();
if (!(buttons & Qt::RightButton) /* && m_nLastUpdateFrame != m_nLastMouseMoveFrame*/ && (selection && selection->IsEmpty()))
{
//m_nLastMouseMoveFrame = m_nLastUpdateFrame;
Vec3 pos = ViewToWorld(point);
GetIEditor()->SetMarkerPosition(pos);
}
break;
}
QPoint tempPoint(point.x(), point.y());
//////////////////////////////////////////////////////////////////////////
// Handle viewport manipulators.
//////////////////////////////////////////////////////////////////////////
if (!bAltClick)
{
ITransformManipulator* pManipulator = GetIEditor()->GetTransformManipulator();
if (pManipulator)
{
if (pManipulator->MouseCallback(this, event, tempPoint, flags))
{
return true;
}
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::ProcessRenderLisneters(DisplayContext& rstDisplayContext)
{

@ -6,13 +6,12 @@
*
*/
// Description : interface for the CViewport class.
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzFramework/Viewport/ViewportId.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <AzToolsFramework/ViewportUi/ViewportUiManager.h>
#include <Cry_Color.h>
@ -88,6 +87,9 @@ enum EStdCursor
STD_CURSOR_LAST,
};
//! The default distance an entity is placed from the camera if there is no intersection
SANDBOX_API float GetDefaultEntityPlacementDistance();
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
class SANDBOX_API CViewport
: public IDisplayViewport
@ -201,7 +203,6 @@ public:
//! Performs hit testing of 2d point in view to find which object hit.
virtual bool HitTest(const QPoint& point, HitContext& hitInfo) = 0;
virtual AZ::Vector3 GetHitLocation(const QPoint& point) = 0;
virtual void MakeConstructionPlane(int axis) = 0;
@ -432,7 +433,6 @@ public:
//! Performs hit testing of 2d point in view to find which object hit.
bool HitTest(const QPoint& point, HitContext& hitInfo) override;
AZ::Vector3 GetHitLocation(const QPoint& point) override;
//! Do 2D hit testing of line in world space.
// pToCameraDistance is an optional output parameter in which distance from the camera to the line is returned.
@ -522,9 +522,6 @@ protected:
void setRenderOverlayVisible(bool);
bool isRenderOverlayVisible() const;
// called to process mouse callback inside the viewport.
virtual bool MouseCallback(EMouseEvent event, const QPoint& point, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons = Qt::NoButton);
void ProcessRenderLisneters(DisplayContext& rstDisplayContext);
void mousePressEvent(QMouseEvent* event) override;
@ -535,29 +532,29 @@ protected:
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
void leaveEvent(QEvent* event) override;
void paintEvent(QPaintEvent* event) override;
virtual void OnMouseMove(Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint& point);
virtual void OnMouseWheel(Qt::KeyboardModifiers modifiers, short zDelta, const QPoint& pt);
virtual void OnLButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnLButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnRButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnMButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnMButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnMButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnLButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnRButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point);
virtual void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
virtual void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
virtual void OnMouseMove(Qt::KeyboardModifiers, Qt::MouseButtons, const QPoint&) {}
virtual void OnMouseWheel(Qt::KeyboardModifiers, short zDelta, const QPoint&);
virtual void OnLButtonDown(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnLButtonUp(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnRButtonDown(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnRButtonUp(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnMButtonDblClk(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnMButtonDown(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnMButtonUp(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnLButtonDblClk(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnRButtonDblClk(Qt::KeyboardModifiers, const QPoint&) {}
virtual void OnKeyDown([[maybe_unused]] UINT nChar, [[maybe_unused]] UINT nRepCnt, [[maybe_unused]] UINT nFlags) {}
virtual void OnKeyUp([[maybe_unused]] UINT nChar, [[maybe_unused]] UINT nRepCnt, [[maybe_unused]] UINT nFlags) {}
#if defined(AZ_PLATFORM_WINDOWS)
void OnRawInput(UINT wParam, HRAWINPUT lParam);
#endif
void OnSetCursor();
virtual void BuildDragDropContext(AzQtComponents::ViewportDragContext& context, const QPoint& pt);
virtual void BuildDragDropContext(
AzQtComponents::ViewportDragContext& context, AzFramework::ViewportId viewportId, const QPoint& point);
void dragEnterEvent(QDragEnterEvent* event) override;
void dragMoveEvent(QDragMoveEvent* event) override;
void dragLeaveEvent(QDragLeaveEvent* event) override;

@ -527,8 +527,8 @@ namespace AzToolsFramework
m_errorButton = nullptr;
}
}
void PropertyAssetCtrl::UpdateErrorButton(const AZStd::string& errorLog)
void PropertyAssetCtrl::UpdateErrorButton()
{
if (m_errorButton)
{
@ -543,12 +543,17 @@ namespace AzToolsFramework
m_errorButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_errorButton->setFixedSize(QSize(16, 16));
m_errorButton->setMouseTracking(true);
m_errorButton->setIcon(QIcon("Icons/PropertyEditor/error_icon.png"));
m_errorButton->setIcon(QIcon(":/PropertyEditor/Resources/error_icon.png"));
m_errorButton->setToolTip("Show Errors");
// Insert the error button after the asset label
qobject_cast<QHBoxLayout*>(layout())->insertWidget(1, m_errorButton);
}
}
void PropertyAssetCtrl::UpdateErrorButtonWithLog(const AZStd::string& errorLog)
{
UpdateErrorButton();
// Connect pressed to opening the error dialog
// Must capture this for call to QObject::connect
@ -587,6 +592,21 @@ namespace AzToolsFramework
logDialog->show();
});
}
void PropertyAssetCtrl::UpdateErrorButtonWithMessage(const AZStd::string& message)
{
UpdateErrorButton();
connect(m_errorButton, &QPushButton::clicked, this, [this, message]() {
QMessageBox::critical(nullptr, "Error", message.c_str());
// Without this, the error button would maintain focus after clicking, which left the red error icon in a blue-highlighted state
if (parentWidget())
{
parentWidget()->setFocus();
}
});
}
void PropertyAssetCtrl::ClearAssetInternal()
{
@ -960,7 +980,6 @@ namespace AzToolsFramework
else
{
const AZ::Data::AssetId assetID = GetCurrentAssetID();
m_currentAssetHint = "";
AZ::Outcome<AssetSystem::JobInfoContainer> jobOutcome = AZ::Failure();
AssetSystemJobRequestBus::BroadcastResult(jobOutcome, &AssetSystemJobRequestBus::Events::GetAssetJobsInfoByAssetID, assetID, false, false);
@ -1018,7 +1037,7 @@ namespace AzToolsFramework
// In case of failure, render failure icon
case AssetSystem::JobStatus::Failed:
{
UpdateErrorButton(errorLog);
UpdateErrorButtonWithLog(errorLog);
}
break;
@ -1043,6 +1062,10 @@ namespace AzToolsFramework
m_currentAssetHint = assetPath;
}
}
else
{
UpdateErrorButtonWithMessage(AZStd::string::format("Asset is missing.\n\nID: %s\nHint:%s", assetID.ToString<AZStd::string>().c_str(), GetCurrentAssetHint().c_str()));
}
}
// Get the asset file name

@ -168,7 +168,9 @@ namespace AzToolsFramework
bool IsCorrectMimeData(const QMimeData* pData, AZ::Data::AssetId* pAssetId = nullptr, AZ::Data::AssetType* pAssetType = nullptr) const;
void ClearErrorButton();
void UpdateErrorButton(const AZStd::string& errorLog);
void UpdateErrorButton();
void UpdateErrorButtonWithLog(const AZStd::string& errorLog);
void UpdateErrorButtonWithMessage(const AZStd::string& message);
virtual const AZStd::string GetFolderSelection() const { return AZStd::string(); }
virtual void SetFolderSelection(const AZStd::string& /* folderPath */) {}
virtual void ClearAssetInternal();

@ -6,6 +6,7 @@
*
*/
#include <AzFramework/Render/IntersectorInterface.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AzToolsFramework
@ -62,4 +63,33 @@ namespace AzToolsFramework
return circleBoundWidth;
}
AZ::Vector3 FindClosestPickIntersection(
AzFramework::ViewportId viewportId, const AzFramework::ScreenPoint& screenPoint, const float rayLength, const float defaultDistance)
{
using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus;
AzToolsFramework::ViewportInteraction::ProjectedViewportRay viewportRay{};
ViewportInteractionRequestBus::EventResult(
viewportRay, viewportId, &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint);
AzFramework::RenderGeometry::RayRequest ray;
ray.m_startWorldPosition = viewportRay.origin;
ray.m_endWorldPosition = viewportRay.origin + viewportRay.direction * rayLength;
ray.m_onlyVisible = true;
AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult;
AzFramework::RenderGeometry::IntersectorBus::EventResult(
renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(),
&AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, ray);
// attempt a ray intersection with any visible mesh and return the intersection position if successful
if (renderGeometryIntersectionResult)
{
return renderGeometryIntersectionResult.m_worldPosition;
}
else
{
return viewportRay.origin + viewportRay.direction * defaultDistance;
}
}
} // namespace AzToolsFramework

@ -334,6 +334,12 @@ namespace AzToolsFramework
return entityContextId;
}
//! Performs an intersection test against meshes in the scene, if there is a hit (the ray intersects
//! a mesh), that position is returned, otherwise a point projected defaultDistance from the
//! origin of the ray will be returned.
AZ::Vector3 FindClosestPickIntersection(
AzFramework::ViewportId viewportId, const AzFramework::ScreenPoint& screenPoint, float rayLength, float defaultDistance);
//! Maps a mouse interaction event to a ClickDetector event.
//! @note Function only cares about up or down events, all other events are mapped to Nil (ignored).
AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction(

@ -18,9 +18,6 @@
namespace AzToolsFramework
{
// default ray length for picking in the viewport
static const float EditorPickRayLength = 1000.0f;
AZ::Vector3 CalculateCenterOffset(const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot)
{
if (Centered(pivot))

@ -26,6 +26,9 @@ namespace AzFramework
namespace AzToolsFramework
{
//! Default ray length for picking in the viewport.
inline constexpr float EditorPickRayLength = 1000.0f;
//! Is the pivot at the center of the object (middle of extents) or at the
//! exported authored object root position.
inline bool Centered(const EditorTransformComponentSelectionRequests::Pivot pivot)

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:28c3cfd8958813b4b539738bfff589731da0aeec5b3376558f377da2ebe973ff
size 5455
oid sha256:7028c8db4f935f23aa4396668278a67691d92fe345cc9d417a9f47bd9a4af32b
size 8130

@ -0,0 +1,91 @@
<ObjectStream version="3">
<Class name="TextureSettings" version="2" type="{980132FF-C450-425D-8AE0-BD96A8486177}">
<Class name="AZ::Uuid" field="PresetID" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="Name" field="Preset" value="ReferenceImage" type="{3D2B920C-9EFD-40D5-AAE0-DF131C3D4931}"/>
<Class name="unsigned int" field="SizeReduceLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="EngineReduce" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="EnableMipmap" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="MaintainAlphaCoverage" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="MipMapAlphaAdjustments" type="{3349AACD-BE04-50BC-9478-528BF2ACFD55}">
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="MipMapGenEval" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="ImageProcessingAtom::MipGenType" field="MipMapGenType" value="1" type="{8524F650-1417-44DA-BBB0-C707A7A1A709}"/>
<Class name="AZStd::map" field="PlatformSpecificOverrides" type="{74E4843B-0924-583D-8C6E-A37B09BD51FE}">
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="android" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="ios" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="linux" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="mac" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="pc" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
</Class>
<Class name="AZStd::string" field="OverridingPlatform" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</ObjectStream>

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8a0935be7347d695ed1716d030b5bae68153a88239b0ff15f67f900ac90be442
size 5038
oid sha256:a7d94b9c0a77741736b93d8ed4d2b22bc9ae4cf649f3d8b3f10cbaf595a3ed31
size 8336

@ -0,0 +1,148 @@
<ObjectStream version="3">
<Class name="TextureSettings" version="2" type="{980132FF-C450-425D-8AE0-BD96A8486177}">
<Class name="AZ::Uuid" field="PresetID" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="Name" field="Preset" value="ReferenceImage" type="{3D2B920C-9EFD-40D5-AAE0-DF131C3D4931}"/>
<Class name="unsigned int" field="SizeReduceLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="EngineReduce" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="EnableMipmap" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="MaintainAlphaCoverage" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="MipMapAlphaAdjustments" type="{3349AACD-BE04-50BC-9478-528BF2ACFD55}">
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="MipMapGenEval" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="ImageProcessingAtom::MipGenType" field="MipMapGenType" value="1" type="{8524F650-1417-44DA-BBB0-C707A7A1A709}"/>
<Class name="AZStd::map" field="PlatformSpecificOverrides" type="{74E4843B-0924-583D-8C6E-A37B09BD51FE}">
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="android" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="ios" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="linux" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="mac" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="pc" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
</Class>
<Class name="AZStd::string" field="OverridingPlatform" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</ObjectStream>

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bb243cd6d6414b4e95eab919fa94193b57825902b8d09f40ce3f334d829e74e2
size 6286
oid sha256:3bbd45e3ef81850da81d1cc01775930a53c424e64e287b00990af3e7e6a682ba
size 9701

@ -0,0 +1,148 @@
<ObjectStream version="3">
<Class name="TextureSettings" version="2" type="{980132FF-C450-425D-8AE0-BD96A8486177}">
<Class name="AZ::Uuid" field="PresetID" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="Name" field="Preset" value="ReferenceImage" type="{3D2B920C-9EFD-40D5-AAE0-DF131C3D4931}"/>
<Class name="unsigned int" field="SizeReduceLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="EngineReduce" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="EnableMipmap" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="MaintainAlphaCoverage" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="MipMapAlphaAdjustments" type="{3349AACD-BE04-50BC-9478-528BF2ACFD55}">
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="MipMapGenEval" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="ImageProcessingAtom::MipGenType" field="MipMapGenType" value="1" type="{8524F650-1417-44DA-BBB0-C707A7A1A709}"/>
<Class name="AZStd::map" field="PlatformSpecificOverrides" type="{74E4843B-0924-583D-8C6E-A37B09BD51FE}">
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="android" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="ios" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="linux" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="mac" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="pc" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
</Class>
<Class name="AZStd::string" field="OverridingPlatform" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</ObjectStream>

@ -12,6 +12,7 @@
#include <AzCore/JSON/document.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
namespace AZ
{
@ -21,21 +22,24 @@ namespace AZ
{
// Declarations...
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId);
// Note that these functions default to TraceLevel::Error to preserve legacy behavior of these APIs. It would be nice to make the default match
// RPI.Reflect/Asset/AssetUtils.h which is TraceLevel::Warning, but we are close to a release so it isn't worth the risk at this time.
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId);
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId, TraceLevel reporting = TraceLevel::Error);
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId = 0);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId = 0, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId = 0);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId = 0, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, const char* sourcePathForDebug);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, const char* sourcePathForDebug, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, TraceLevel reporting = TraceLevel::Error);
//! Attempts to resolve the full path to a product asset given its ID
AZStd::string GetProductPathByAssetId(const AZ::Data::AssetId& assetId);
@ -65,12 +69,12 @@ namespace AZ
// Definitions...
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId, TraceLevel reporting)
{
auto assetId = MakeAssetId(sourcePath, productSubId);
auto assetId = MakeAssetId(sourcePath, productSubId, reporting);
if (assetId.IsSuccess())
{
return LoadAsset<AssetDataT>(assetId.GetValue(), sourcePath.c_str());
return LoadAsset<AssetDataT>(assetId.GetValue(), sourcePath.c_str(), reporting);
}
else
{
@ -79,20 +83,20 @@ namespace AZ
}
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId, TraceLevel reporting)
{
AZStd::string resolvedPath = ResolvePathReference(originatingSourcePath, referencedSourceFilePath);
return LoadAsset<AssetDataT>(resolvedPath, productSubId);
return LoadAsset<AssetDataT>(resolvedPath, productSubId, reporting);
}
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, TraceLevel reporting)
{
return LoadAsset<AssetDataT>(assetId, nullptr);
return LoadAsset<AssetDataT>(assetId, nullptr, reporting);
}
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug, TraceLevel reporting)
{
if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"))
{
@ -111,11 +115,11 @@ namespace AZ
}
else
{
AZ_Error("AssetUtils", false, "Could not load %s [Source='%s' Cache='%s' AssetID=%s] ",
AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not load %s [Source='%s' Cache='%s' AssetID=%s] ",
AzTypeInfo<AssetDataT>::Name(),
sourcePathForDebug ? sourcePathForDebug : "<unknown>",
asset.GetHint().empty() ? "<unknown>" : asset.GetHint().c_str(),
assetId.ToString<AZStd::string>().c_str());
assetId.ToString<AZStd::string>().c_str()).c_str());
return AZ::Failure();
}

@ -28,7 +28,18 @@ namespace AZ
namespace MaterialUtils
{
Outcome<Data::Asset<ImageAsset>> GetImageAssetReference(AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath);
enum class GetImageAssetResult
{
Empty, //! No image was actually requested, the path was empty
Found, //! The requested asset was found
Missing //! The requested asset was not found, and a placeholder asset was used instead
};
//! Finds an ImageAsset referenced by a material file (or a placeholder)
//! @param imageAsset the resulting ImageAsset
//! @param materialSourceFilePath the full path to a material source file that is referenfing an image file
//! @param imageFilePath the path to an image source file, which could be relative to the asset root or relative to the material file
GetImageAssetResult GetImageAssetReference(Data::Asset<ImageAsset>& imageAsset, AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath);
//! Resolve an enum to a uint32_t given its name and definition array (in MaterialPropertyDescriptor).
//! @param propertyDescriptor it contains the definition of all enum names in an array.

@ -29,6 +29,14 @@ namespace AZ
Count
};
namespace DefaultImageAssetPaths
{
static constexpr char DefaultFallback[] = "textures/defaults/defaultfallback.png.streamingimage";
static constexpr char Processing[] = "textures/defaults/processing.png.streamingimage";
static constexpr char ProcessingFailed[] = "textures/defaults/processingfailed.png.streamingimage";
static constexpr char Missing[] = "textures/defaults/missing.png.streamingimage";
}
class ImageSystemInterface
{
public:

@ -63,11 +63,21 @@ namespace AZ
{
BusDisconnect();
}
bool MaterialBuilder::ReportMaterialAssetWarningsAsErrors() const
{
bool warningsAsErrors = false;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
settingsRegistry->Get(warningsAsErrors, "/O3DE/Atom/RPI/MaterialBuilder/WarningsAsErrors");
}
return warningsAsErrors;
}
//! Adds all relevant dependencies for a referenced source file, considering that the path might be relative to the original file location or a full asset path.
//! This will usually include multiple source dependencies and a single job dependency, but will include only source dependencies if the file is not found.
//! Note the AssetBuilderSDK::JobDependency::m_platformIdentifier will not be set by this function. The calling code must set this value before passing back
//! to the AssetBuilderSDK::CreateJobsResponse. If isOrderedOnceForMaterialTypes is true and the dependency is a materialtype file, the job dependency type
//! to the AssetBuilderSDK::CreateJobsResponse. If isOrderedOnceForMaterialTypes is true and the dependency is a .materialtype file, the job dependency type
//! will be set to JobDependencyType::OrderOnce.
void AddPossibleDependencies(AZStd::string_view currentFilePath,
AZStd::string_view referencedParentPath,
@ -277,8 +287,8 @@ namespace AZ
return materialTypeAssetOutcome.GetValue();
}
AZ::Data::Asset<MaterialAsset> CreateMaterialAsset(AZStd::string_view materialSourceFilePath, const rapidjson::Value& json)
AZ::Data::Asset<MaterialAsset> MaterialBuilder::CreateMaterialAsset(AZStd::string_view materialSourceFilePath, const rapidjson::Value& json) const
{
auto material = LoadSourceData<MaterialSourceData>(json, materialSourceFilePath);
@ -292,7 +302,7 @@ namespace AZ
return {};
}
auto materialAssetOutcome = material.GetValue().CreateMaterialAsset(Uuid::CreateRandom(), materialSourceFilePath, true);
auto materialAssetOutcome = material.GetValue().CreateMaterialAsset(Uuid::CreateRandom(), materialSourceFilePath, ReportMaterialAssetWarningsAsErrors());
if (!materialAssetOutcome.IsSuccess())
{
return {};

@ -9,6 +9,8 @@
#pragma once
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <AzCore/JSON/document.h>
namespace AZ
{
@ -37,6 +39,9 @@ namespace AZ
private:
AZ::Data::Asset<MaterialAsset> CreateMaterialAsset(AZStd::string_view materialSourceFilePath, const rapidjson::Value& json) const;
bool ReportMaterialAssetWarningsAsErrors() const;
bool m_isShuttingDown = false;
};

@ -10,6 +10,7 @@
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/IO/IOUtils.h>
#include <AzCore/IO/Path/Path.h>
namespace AZ
{
@ -46,6 +47,12 @@ namespace AZ
AZStd::string ResolvePathReference(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath)
{
// The IsAbsolute part prevents "second join parameter is an absolute path" warnings in StringFunc::Path::Join below
if (referencedSourceFilePath.empty() || AZ::IO::PathView{referencedSourceFilePath}.IsAbsolute())
{
return referencedSourceFilePath;
}
AZStd::string normalizedReferencedPath = referencedSourceFilePath;
AzFramework::StringFunc::Path::Normalize(normalizedReferencedPath);
@ -113,7 +120,7 @@ namespace AZ
return results;
}
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId)
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId, TraceLevel reporting)
{
bool assetFound = false;
AZ::Data::AssetInfo sourceInfo;
@ -122,7 +129,7 @@ namespace AZ
if (!assetFound)
{
AZ_Error("AssetUtils", false, "Could not find asset [%s]", sourcePath.c_str());
AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not find asset [%s]", sourcePath.c_str()).c_str());
return AZ::Failure();
}
else
@ -131,10 +138,10 @@ namespace AZ
}
}
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId)
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId, TraceLevel reporting)
{
AZStd::string resolvedPath = ResolvePathReference(originatingSourcePath, referencedSourceFilePath);
return MakeAssetId(resolvedPath, productSubId);
return MakeAssetId(resolvedPath, productSubId, reporting);
}
} // namespace AssetUtils
} // namespace RPI

@ -303,7 +303,7 @@ namespace AZ
MaterialPropertyId propertyId{ group.first, property.first };
if (!property.second.m_value.IsValid())
{
AZ_Warning("Material source data", false, "Source data for material property value is invalid.");
materialAssetCreator.ReportWarning("Source data for material property value is invalid.");
}
else
{
@ -317,22 +317,20 @@ namespace AZ
{
case MaterialPropertyDataType::Image:
{
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(
materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
Data::Asset<ImageAsset> imageAsset;
if (imageAssetResult.IsSuccess())
MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference(
imageAsset, materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
if (result == MaterialUtils::GetImageAssetResult::Missing)
{
auto& imageAsset = imageAssetResult.GetValue();
// Load referenced images when load material
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
else
{
materialAssetCreator.ReportError(
materialAssetCreator.ReportWarning(
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
property.second.m_value.GetValue<AZStd::string>().data());
}
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
break;
case MaterialPropertyDataType::Enum:

@ -451,20 +451,21 @@ namespace AZ
{
case MaterialPropertyDataType::Image:
{
auto imageAssetResult = MaterialUtils::GetImageAssetReference(
materialTypeSourceFilePath, property.m_value.GetValue<AZStd::string>());
Data::Asset<ImageAsset> imageAsset;
if (imageAssetResult)
{
auto imageAsset = imageAssetResult.GetValue();
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
else
MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference(
imageAsset, materialTypeSourceFilePath, property.m_value.GetValue<AZStd::string>());
if (result == MaterialUtils::GetImageAssetResult::Missing)
{
materialTypeAssetCreator.ReportError(
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
property.m_value.GetValue<AZStd::string>().data());
}
else
{
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
}
break;
case MaterialPropertyDataType::Enum:

@ -28,25 +28,36 @@ namespace AZ
{
namespace MaterialUtils
{
Outcome<Data::Asset<ImageAsset>> GetImageAssetReference(AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath)
GetImageAssetResult GetImageAssetReference(Data::Asset<ImageAsset>& imageAsset, AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath)
{
imageAsset = {};
if (imageFilePath.empty())
{
// The image value was present but specified an empty string, meaning the texture asset should be explicitly cleared.
return AZ::Success(Data::Asset<ImageAsset>());
return GetImageAssetResult::Empty;
}
else
{
Outcome<Data::AssetId> imageAssetId = AssetUtils::MakeAssetId(materialSourceFilePath, imageFilePath, StreamingImageAsset::GetImageAssetSubId());
// We use TraceLevel::None because fallback textures are available and we'll return GetImageAssetResult::Missing below in that case.
// Callers of GetImageAssetReference will be responsible for logging warnings or errors as needed.
Outcome<Data::AssetId> imageAssetId = AssetUtils::MakeAssetId(materialSourceFilePath, imageFilePath, StreamingImageAsset::GetImageAssetSubId(), AssetUtils::TraceLevel::None);
if (!imageAssetId.IsSuccess())
{
return AZ::Failure();
}
else
{
Data::Asset<ImageAsset> unloadedImageAssetReference(imageAssetId.GetValue(), azrtti_typeid<StreamingImageAsset>(), imageFilePath);
return AZ::Success(unloadedImageAssetReference);
// When the AssetId cannot be found, we don't want to outright fail, because the runtime has mechanisms for displaying fallback textures which gives the
// user a better recovery workflow. On the other hand we can't just provide an empty/invalid Asset<ImageAsset> because that would be interpreted as simply
// no value was present and result in using no texture, and this would amount to a silent failure.
// So we use a randomly generated (well except for the "BADA55E7" bit ;) UUID which the runtime and tools will interpret as a missing asset and represent
// it as such.
static const Uuid InvalidAssetPlaceholderId = "{BADA55E7-1A1D-4940-B655-9D08679BD62F}";
imageAsset = Data::Asset<ImageAsset>{InvalidAssetPlaceholderId, azrtti_typeid<StreamingImageAsset>(), imageFilePath};
return GetImageAssetResult::Missing;
}
imageAsset = Data::Asset<ImageAsset>{imageAssetId.GetValue(), azrtti_typeid<StreamingImageAsset>(), imageFilePath};
return GetImageAssetResult::Found;
}
}

@ -7,6 +7,7 @@
*/
#include <Atom/RPI.Reflect/Image/StreamingImageAssetHandler.h>
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzFramework/Asset/AssetSystemBus.h>
@ -52,7 +53,7 @@ namespace AZ
missingAssetStatus, &AzFramework::AssetSystem::AssetSystemRequests::GetAssetStatusById, asset.GetId().m_guid);
// Determine which fallback image to use
const char* relativePath = "textures/defaults/defaultfallback.png.streamingimage";
const char* relativePath = DefaultImageAssetPaths::DefaultFallback;
bool useDebugFallbackImages = true;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
@ -66,15 +67,15 @@ namespace AZ
{
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Queued:
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Compiling:
relativePath = "textures/defaults/processing.png.streamingimage";
relativePath = DefaultImageAssetPaths::Processing;
break;
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Failed:
relativePath = "textures/defaults/processingfailed.png.streamingimage";
relativePath = DefaultImageAssetPaths::ProcessingFailed;
break;
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Missing:
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Unknown:
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Compiled:
relativePath = "textures/defaults/missing.png.streamingimage";
relativePath = DefaultImageAssetPaths::Missing;
break;
}
}

@ -118,12 +118,16 @@ namespace AZ
else if (value.is<Data::Asset<Data::AssetData>>())
{
result.m_value = Data::Asset<RPI::ImageAsset>(
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetId(), azrtti_typeid<RPI::StreamingImageAsset>());
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetId(),
azrtti_typeid<RPI::StreamingImageAsset>(),
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetHint());
}
else if (value.is<Data::Asset<StreamingImageAsset>>())
{
result.m_value = Data::Asset<RPI::ImageAsset>(
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetId(), azrtti_typeid<RPI::StreamingImageAsset>());
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetId(),
azrtti_typeid<RPI::StreamingImageAsset>(),
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetHint());
}
else if (value.is<Data::Asset<ImageAsset>>())
{

@ -625,23 +625,6 @@ namespace UnitTest
// We use local functions to easily start a new MaterialAssetCreator for each test case because
// the AssetCreator would just skip subsequent operations after the first failure is detected.
auto expectError = [](AZStd::function<void(MaterialSourceData& materialSourceData)> setOneBadInput, [[maybe_unused]] uint32_t expectedAsserts = 2)
{
MaterialSourceData sourceData;
sourceData.m_materialType = "@exefolder@/Temp/test.materialtype";
AddPropertyGroup(sourceData, "general");
setOneBadInput(sourceData);
AZ_TEST_START_ASSERTTEST;
auto materialAssetOutcome = sourceData.CreateMaterialAsset(Uuid::CreateRandom(), "", false);
AZ_TEST_STOP_ASSERTTEST(expectedAsserts); // Usually one for the initial error, and one for when End() is called
EXPECT_FALSE(materialAssetOutcome.IsSuccess());
};
auto expectWarning = [](AZStd::function<void(MaterialSourceData& materialSourceData)> setOneBadInput, [[maybe_unused]] uint32_t expectedAsserts = 1)
{
MaterialSourceData sourceData;
@ -692,10 +675,10 @@ namespace UnitTest
});
// Missing image reference
expectError([](MaterialSourceData& materialSourceData)
expectWarning([](MaterialSourceData& materialSourceData)
{
AddProperty(materialSourceData, "general", "MyImage", AZStd::string("doesNotExist.streamingimage"));
}, 3); // Expect a 3rd error because AssetUtils reports its own assertion failure
});
}

@ -888,4 +888,43 @@ namespace UnitTest
EXPECT_EQ(indexFromOldName, indexFromNewName);
}
template<typename T>
void CheckPropertyValueRoundTrip(const T& value)
{
AZ::RPI::MaterialPropertyValue materialPropertyValue{value};
AZStd::any anyValue{value};
AZ::RPI::MaterialPropertyValue materialPropertyValueFromAny = MaterialPropertyValue::FromAny(anyValue);
AZ::RPI::MaterialPropertyValue materialPropertyValueFromRoundTrip = MaterialPropertyValue::FromAny(MaterialPropertyValue::ToAny(materialPropertyValue));
EXPECT_EQ(materialPropertyValue, materialPropertyValueFromAny);
EXPECT_EQ(materialPropertyValue, materialPropertyValueFromRoundTrip);
if (materialPropertyValue.Is<Data::Asset<ImageAsset>>())
{
EXPECT_EQ(materialPropertyValue.GetValue<Data::Asset<ImageAsset>>().GetHint(), materialPropertyValueFromAny.GetValue<Data::Asset<ImageAsset>>().GetHint());
EXPECT_EQ(materialPropertyValue.GetValue<Data::Asset<ImageAsset>>().GetHint(), materialPropertyValueFromRoundTrip.GetValue<Data::Asset<ImageAsset>>().GetHint());
}
}
TEST_F(MaterialTests, TestMaterialPropertyValueAsAny)
{
CheckPropertyValueRoundTrip(true);
CheckPropertyValueRoundTrip(false);
CheckPropertyValueRoundTrip(7);
CheckPropertyValueRoundTrip(8u);
CheckPropertyValueRoundTrip(9.0f);
CheckPropertyValueRoundTrip(AZ::Vector2(1.0f, 2.0f));
CheckPropertyValueRoundTrip(AZ::Vector3(1.0f, 2.0f, 3.0f));
CheckPropertyValueRoundTrip(AZ::Vector4(1.0f, 2.0f, 3.0f, 4.0f));
CheckPropertyValueRoundTrip(AZ::Color(1.0f, 2.0f, 3.0f, 4.0f));
CheckPropertyValueRoundTrip(Data::Asset<Data::AssetData>{});
CheckPropertyValueRoundTrip(Data::Asset<ImageAsset>{});
CheckPropertyValueRoundTrip(Data::Asset<StreamingImageAsset>{});
CheckPropertyValueRoundTrip(Data::Asset<Data::AssetData>{Uuid::CreateRandom(), azrtti_typeid<AZ::RPI::StreamingImageAsset>(), "TestAssetPath.png"});
CheckPropertyValueRoundTrip(Data::Asset<ImageAsset>{Uuid::CreateRandom(), azrtti_typeid<AZ::RPI::StreamingImageAsset>(), "TestAssetPath.png"});
CheckPropertyValueRoundTrip(Data::Asset<StreamingImageAsset>{Uuid::CreateRandom(), azrtti_typeid<AZ::RPI::StreamingImageAsset>(), "TestAssetPath.png"});
CheckPropertyValueRoundTrip(m_testImageAsset);
CheckPropertyValueRoundTrip(Data::Instance<Image>{m_testImage});
CheckPropertyValueRoundTrip(AZStd::string{"hello"});
}
}

@ -26,6 +26,21 @@ namespace AtomToolsFramework
//! Get the combined output of all messages
AZStd::string GetDump() const;
//! Return the number of OnAssert calls
size_t GetAssertCount() const;
//! Return the number of OnException calls
size_t GetExceptionCount() const;
//! Return the number of OnError calls, and includes OnAssert and OnException if @includeHigher is true
size_t GetErrorCount(bool includeHigher = false) const;
//! Return the number of OnWarning calls, and includes higher categories if @includeHigher is true
size_t GetWarningCount(bool includeHigher = false) const;
//! Return the number of OnPrintf calls, and includes higher categories if @includeHigher is true
size_t GetPrintfCount(bool includeHigher = false) const;
private:
//////////////////////////////////////////////////////////////////////////
// AZ::Debug::TraceMessageBus::Handler overrides...
@ -38,5 +53,11 @@ namespace AtomToolsFramework
size_t m_maxMessageCount = std::numeric_limits<size_t>::max();
AZStd::list<AZStd::string> m_messages;
size_t m_assertCount = 0;
size_t m_exceptionCount = 0;
size_t m_errorCount = 0;
size_t m_warningCount = 0;
size_t m_printfCount = 0;
};
} // namespace AtomToolsFramework

@ -49,6 +49,7 @@ namespace AtomToolsFramework
//! @param propertyValue the value being converted before saving
bool ConvertToExportFormat(
const AZStd::string& exportPath,
[[maybe_unused]] const AZ::Name& propertyId,
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
AZ::RPI::MaterialPropertyValue& propertyValue);

@ -10,6 +10,7 @@
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AzFramework/Viewport/CameraState.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
@ -17,7 +18,9 @@ namespace AtomToolsFramework
{
//! A concrete implementation of the ViewportInteractionRequestBus.
//! Primarily concerned with picking (screen to world and world to screen transformations).
class ViewportInteractionImpl : public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
class ViewportInteractionImpl
: public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
, private AZ::RPI::ViewportContextIdNotificationBus::Handler
{
public:
explicit ViewportInteractionImpl(AZ::RPI::ViewPtr viewPtr);
@ -37,6 +40,9 @@ namespace AtomToolsFramework
AZStd::function<float()> m_deviceScalingFactorFn; //! Callback to determine the device scaling factor.
private:
// ViewportContextIdNotificationBus overrides ...
void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view) override;
AZ::RPI::ViewPtr m_viewPtr;
};
} // namespace AtomToolsFramework

@ -31,6 +31,7 @@ namespace AtomToolsFramework
bool TraceRecorder::OnAssert(const char* message)
{
++m_assertCount;
if (m_messages.size() < m_maxMessageCount)
{
m_messages.push_back(AZStd::string::format("Assert: %s", message));
@ -40,6 +41,7 @@ namespace AtomToolsFramework
bool TraceRecorder::OnException(const char* message)
{
++m_exceptionCount;
if (m_messages.size() < m_maxMessageCount)
{
m_messages.push_back(AZStd::string::format("Exception: %s", message));
@ -49,6 +51,7 @@ namespace AtomToolsFramework
bool TraceRecorder::OnError(const char* /*window*/, const char* message)
{
++m_errorCount;
if (m_messages.size() < m_maxMessageCount)
{
m_messages.push_back(AZStd::string::format("Error: %s", message));
@ -58,6 +61,7 @@ namespace AtomToolsFramework
bool TraceRecorder::OnWarning(const char* /*window*/, const char* message)
{
++m_warningCount;
if (m_messages.size() < m_maxMessageCount)
{
m_messages.push_back(AZStd::string::format("Warning: %s", message));
@ -67,11 +71,58 @@ namespace AtomToolsFramework
bool TraceRecorder::OnPrintf(const char* /*window*/, const char* message)
{
++m_printfCount;
if (m_messages.size() < m_maxMessageCount)
{
m_messages.push_back(AZStd::string::format("%s", message));
}
return false;
}
size_t TraceRecorder::GetAssertCount() const
{
return m_assertCount;
}
size_t TraceRecorder::GetExceptionCount() const
{
return m_exceptionCount;
}
size_t TraceRecorder::GetErrorCount(bool includeHigher) const
{
if (includeHigher)
{
return m_errorCount + GetAssertCount() + GetExceptionCount();
}
else
{
return m_errorCount;
}
}
size_t TraceRecorder::GetWarningCount(bool includeHigher) const
{
if (includeHigher)
{
return m_warningCount + GetErrorCount(true);
}
else
{
return m_warningCount;
}
}
size_t TraceRecorder::GetPrintfCount(bool includeHigher) const
{
if (includeHigher)
{
return m_printfCount + GetWarningCount(true);
}
else
{
return m_printfCount;
}
}
} // namespace AtomToolsFramework

@ -495,8 +495,6 @@ namespace AtomToolsFramework
return AZ::Uuid::CreateNull();
}
traceRecorder.GetDump().clear();
bool openResult = false;
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Open, requestedPath);
if (!openResult)
@ -507,6 +505,12 @@ namespace AtomToolsFramework
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
return AZ::Uuid::CreateNull();
}
else if (traceRecorder.GetWarningCount(true) > 0)
{
QMessageBox::warning(
QApplication::activeWindow(), QString("Document opened with warnings"),
QString("Warnings encountered: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
}
return documentId;
}

@ -167,6 +167,7 @@ namespace AtomToolsFramework
bool ConvertToExportFormat(
const AZStd::string& exportPath,
[[maybe_unused]] const AZ::Name& propertyId,
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
AZ::RPI::MaterialPropertyValue& propertyValue)
{
@ -175,7 +176,7 @@ namespace AtomToolsFramework
const uint32_t index = propertyValue.GetValue<uint32_t>();
if (index >= propertyDefinition.m_enumValues.size())
{
AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str());
AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyId.GetCStr());
return false;
}
@ -186,18 +187,33 @@ namespace AtomToolsFramework
// Image asset references must be converted from asset IDs to a relative source file path
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image)
{
AZStd::string imagePath;
AZ::Data::AssetId imageAssetId;
if (propertyValue.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
{
const auto& imageAsset = propertyValue.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId());
propertyValue = GetExteralReferencePath(exportPath, imagePath);
return true;
imageAssetId = imageAsset.GetId();
}
if (propertyValue.Is<AZ::Data::Instance<AZ::RPI::Image>>())
{
const auto& image = propertyValue.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
const auto& imagePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : "";
if (image)
{
imageAssetId = image->GetAssetId();
}
}
imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAssetId);
if (imageAssetId.IsValid() && imagePath.empty())
{
AZ_Error("AtomToolsFramework", false, "Image asset could not be found for property: '%s'.", propertyId.GetCStr());
return false;
}
else
{
propertyValue = GetExteralReferencePath(exportPath, imagePath);
return true;
}

@ -19,10 +19,12 @@ namespace AtomToolsFramework
void ViewportInteractionImpl::Connect(const AzFramework::ViewportId viewportId)
{
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(viewportId);
AZ::RPI::ViewportContextIdNotificationBus::Handler::BusConnect(viewportId);
}
void ViewportInteractionImpl::Disconnect()
{
AZ::RPI::ViewportContextIdNotificationBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
}
@ -58,4 +60,9 @@ namespace AtomToolsFramework
{
return m_deviceScalingFactorFn();
}
void ViewportInteractionImpl::OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view)
{
m_viewPtr = AZStd::move(view);
}
} // namespace AtomToolsFramework

@ -7,12 +7,14 @@
*/
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzCore/Math/IntersectSegment.h>
#include <AzCore/Math/MatrixUtils.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <Tests/Utils/Printers.h>
@ -169,4 +171,39 @@ namespace UnitTest
EXPECT_EQ(intersection, AZ::Intersect::SphereIsectTypes::ISECT_RAY_SPHERE_ISECT);
}
TEST_F(ViewportInteractionImplFixture, ViewportInteractionRequestsReturnsNewViewWhenItIsChanged)
{
// Given
const auto primaryViewTransform = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(90.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-45.0f)),
AZ::Vector3(-10.0f, -15.0f, 20.0f));
m_view->SetCameraTransform(primaryViewTransform);
AZ::RPI::ViewPtr secondaryView = AZ::RPI::View::CreateView(AZ::Name("SecondaryView"), AZ::RPI::View::UsageCamera);
const auto secondaryViewTransform = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(-90.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(30.0f)),
AZ::Vector3(-50.0f, -25.0f, 10.0f));
secondaryView->SetCameraTransform(secondaryViewTransform);
// When
AZ::RPI::ViewportContextIdNotificationBus::Event(
TestViewportId, &AZ::RPI::ViewportContextIdNotificationBus::Events::OnViewportDefaultViewChanged, secondaryView);
// retrieve updated camera transform
AzFramework::CameraState cameraState;
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
cameraState, TestViewportId, &AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::GetCameraState);
const auto cameraMatrix = AzFramework::CameraTransform(cameraState);
const auto cameraTransform = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateFromMatrix4x4(cameraMatrix), cameraMatrix.GetTranslation());
// Then
// camera transform matches that of the secondary view
EXPECT_THAT(cameraTransform, IsClose(secondaryViewTransform));
}
} // namespace UnitTest

@ -12,6 +12,7 @@
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
#include <Atom/RPI.Public/Material/Material.h>
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
#include <Atom/RPI.Reflect/Image/Image.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
@ -594,7 +595,7 @@ namespace MaterialEditor
MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue());
if (propertyValue.IsValid())
{
if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyDefinition, propertyValue))
if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue))
{
AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str());
result = false;
@ -708,6 +709,8 @@ namespace MaterialEditor
AZ_Error("MaterialDocument", false, "Material document extension not supported: '%s'.", m_absolutePath.c_str());
return false;
}
const bool elevateWarnings = false;
// In order to support automation, general usability, and 'save as' functionality, the user must not have to wait
// for their JSON file to be cooked by the asset processor before opening or editing it.
@ -716,7 +719,7 @@ namespace MaterialEditor
// Long term, the material document should not be concerned with assets at all. The viewport window should be the
// only thing concerned with assets or instances.
auto materialAssetResult =
m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true, true, &m_sourceDependencies);
m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, elevateWarnings, true, &m_sourceDependencies);
if (!materialAssetResult)
{
AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str());
@ -754,7 +757,7 @@ namespace MaterialEditor
AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", m_materialSourceData.m_parentMaterial.c_str());
return false;
}
auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData(
parentMaterialAssetIdResult.GetValue(), m_materialSourceData.m_parentMaterial, true, true);
if (!parentMaterialAssetResult)

@ -1353,9 +1353,8 @@ namespace AZ::AtomBridge
// if 2d draw need to project pos to screen first
AzFramework::TextDrawParameters params;
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor();
params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works
params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f);
params.m_position = AZ::Vector3(x, y, 1.0f);
params.m_color = m_rendState.m_color;
params.m_scale = AZ::Vector2(size);
params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment

@ -134,7 +134,7 @@ namespace AZ
propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second);
}
if (!AtomToolsFramework::ConvertToExportFormat(path, propertyDefinition, propertyValue))
if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId.GetFullName(), propertyDefinition, propertyValue))
{
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str());
result = false;

@ -11,6 +11,7 @@
#include <Editor/EditorJointConfiguration.h>
#include <Source/EditorColliderComponent.h>
#include <Source/EditorRigidBodyComponent.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
namespace
{
@ -213,7 +214,7 @@ namespace PhysX
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorJointConfig>()
->Version(4, &EditorJointConfig::VersionConverter)
->Version(5, &EditorJointConfig::VersionConverter)
->Field("Local Position", &EditorJointConfig::m_localPosition)
->Field("Local Rotation", &EditorJointConfig::m_localRotation)
->Field("Parent Entity", &EditorJointConfig::m_leadEntity)
@ -228,6 +229,12 @@ namespace PhysX
if (auto* editContext = serializeContext->GetEditContext())
{
editContext->Enum<EditorJointConfig::DisplaySetupState>("Joint Display Setup State", "Options for displaying joint setup.")
->Value("Never", EditorJointConfig::DisplaySetupState::Never)
->Value("Selected", EditorJointConfig::DisplaySetupState::Selected)
->Value("Always", EditorJointConfig::DisplaySetupState::Always)
;
editContext->Class<PhysX::EditorJointConfig>(
"PhysX Joint Configuration", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
@ -244,8 +251,11 @@ namespace PhysX
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorJointConfig::ValidateLeadEntityId)
->DataElement(0, &PhysX::EditorJointConfig::m_selfCollide, "Lead-Follower Collide"
, "When active, the lead and follower pair will collide with each other.")
->DataElement(0, &PhysX::EditorJointConfig::m_displayJointSetup, "Display Setup in Viewport"
, "Display joint setup in the viewport.")
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &PhysX::EditorJointConfig::m_displayJointSetup, "Display Setup in Viewport"
, "Never = Not shown."
"Select = Show setup display when entity is selected."
"Always = Always show setup display.")
->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode)
->DataElement(0, &PhysX::EditorJointConfig::m_selectLeadOnSnap, "Select Lead on Snap"
, "Select lead entity on snap to position in component mode.")
@ -306,6 +316,23 @@ namespace PhysX
m_followerEntity);
}
bool EditorJointConfig::ShowSetupDisplay() const
{
switch(m_displayJointSetup)
{
case DisplaySetupState::Always:
return true;
case DisplaySetupState::Selected:
{
bool showSetup = false;
AzToolsFramework::EditorEntityInfoRequestBus::EventResult(
showSetup, m_followerEntity, &AzToolsFramework::EditorEntityInfoRequests::IsSelected);
return showSetup;
}
}
return false;
}
bool EditorJointConfig::IsInComponentMode() const
{
return m_inComponentMode;
@ -343,6 +370,31 @@ namespace PhysX
}
}
// convert m_displayJointSetup from a bool to the enum with the option Never,Selected,Always show joint setup helpers.
if (classElement.GetVersion() <= 4)
{
// get the current bool setting and remove it.
bool oldSetting = false;
const int displayJointSetupIndex = classElement.FindElement(AZ_CRC_CE("Display Debug"));
if (displayJointSetupIndex >= 0)
{
AZ::SerializeContext::DataElementNode& elementNode = classElement.GetSubElement(displayJointSetupIndex);
elementNode.GetData<bool>(oldSetting);
classElement.RemoveElement(displayJointSetupIndex);
}
//if the old setting was on set it to 'Selected'. otherwise 'Never'
if (oldSetting)
{
classElement.AddElementWithData(context, "Display Debug", EditorJointConfig::DisplaySetupState::Selected);
}
else
{
classElement.AddElementWithData(context, "Display Debug", EditorJointConfig::DisplaySetupState::Never);
}
}
return result;
}

@ -100,12 +100,21 @@ namespace PhysX
AZ_TYPE_INFO(EditorJointConfig, "{8A966D65-CA97-4786-A13C-ACAA519D97EA}");
static void Reflect(AZ::ReflectContext* context);
enum class DisplaySetupState : AZ::u8
{
Never = 0,
Selected,
Always
};
void SetLeadEntityId(AZ::EntityId leadEntityId);
JointGenericProperties ToGenericProperties() const;
JointComponentConfiguration ToGameTimeConfig() const;
bool ShowSetupDisplay() const;
bool m_breakable = false;
bool m_displayJointSetup = false;
DisplaySetupState m_displayJointSetup = DisplaySetupState::Selected;
bool m_inComponentMode = false;
bool m_selectLeadOnSnap = true;
bool m_selfCollide = false;
@ -129,3 +138,8 @@ namespace PhysX
};
} // namespace PhysX
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(PhysX::EditorJointConfig::DisplaySetupState, "{17EBE6BD-289A-4326-8A24-DCE3B7FEC51E}");
} // namespace AZ

@ -215,7 +215,7 @@ namespace PhysX
{
EditorJointComponent::DisplayEntityViewport(viewportInfo, debugDisplay);
if (!m_config.m_displayJointSetup &&
if (!m_config.ShowSetupDisplay() &&
!m_config.m_inComponentMode)
{
return;

@ -211,7 +211,7 @@ namespace PhysX
{
EditorJointComponent::DisplayEntityViewport(viewportInfo, debugDisplay);
if (!m_config.m_displayJointSetup &&
if (!m_config.ShowSetupDisplay() &&
!m_config.m_inComponentMode)
{
return;

Loading…
Cancel
Save