Merge branch 'development' into jillich/MM20220201

Signed-off-by: Benjamin Jillich <jillich@amazon.com>
monroegm-disable-blank-issue-2
Benjamin Jillich 4 years ago
commit 9eb101778d

@ -62,15 +62,16 @@ def Multiplayer_AutoComponent_RPC():
Report.critical_result(TestSuccessFailTuples.find_network_player, player_id.IsValid())
# 4) Check the editor logs for expected and unexpected log output
# Authority->Autonomous RPC
PLAYERID_RPC_WAIT_TIME_SECONDS = 1.0 # The player id is sent from the server as soon as the player script is spawned. 1 second should be more than enough time to send/receive that RPC.
helper.succeed_if_log_line_found('EditorServer', 'Script: AutoComponent_RPC: Sending client PlayerNumber 1', section_tracer.prints, PLAYERID_RPC_WAIT_TIME_SECONDS)
helper.succeed_if_log_line_found('Script', "AutoComponent_RPC: I'm Player #1", section_tracer.prints, PLAYERID_RPC_WAIT_TIME_SECONDS)
# Uncomment once editor game-play mode supports level entities with net-binding
#PLAYFX_RPC_WAIT_TIME_SECONDS = 1.1 # The server will send an RPC to play an fx on the client every second.
#helper.succeed_if_log_line_found('EditorServer', "Script: AutoComponent_RPC_NetLevelEntity Activated on entity: NetLevelEntity", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
#helper.succeed_if_log_line_found('EditorServer', "Script: AutoComponent_RPC_NetLevelEntity: Authority sending RPC to play some fx.", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
#helper.succeed_if_log_line_found('Script', "AutoComponent_RPC_NetLevelEntity: I'm a client playing some superficial fx.", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
# Authority->Client RPC
PLAYFX_RPC_WAIT_TIME_SECONDS = 1.1 # The server will send an RPC to play an fx on the client every second.
helper.succeed_if_log_line_found('EditorServer', "Script: AutoComponent_RPC_NetLevelEntity Activated on entity: NetLevelEntity", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
helper.succeed_if_log_line_found('EditorServer', "Script: AutoComponent_RPC_NetLevelEntity: Authority sending RPC to play some fx.", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
helper.succeed_if_log_line_found('Script', "AutoComponent_RPC_NetLevelEntity: I'm a client playing some fx.", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
# Exit game mode

@ -568,22 +568,10 @@
"$type": "EditorScriptCanvasComponent",
"Id": 14750978061505735417,
"m_name": "GlobalGameData",
"m_assetHolder": {
"m_asset": {
"assetId": {
"guid": "{B16589A0-EA01-56BC-8141-91A3967FB95F}"
},
"assetHint": "levels/multiplayer/autocomponent_rpc/globalgamedata.scriptcanvas"
}
},
"runtimeDataIsValid": true,
"runtimeDataOverrides": {
"source": {
"assetId": {
"guid": "{B16589A0-EA01-56BC-8141-91A3967FB95F}"
},
"assetHint": "levels/multiplayer/autocomponent_rpc/globalgamedata.scriptcanvas"
}
"sourceHandle": {
"id": "{B16589A0-EA01-56BC-8141-91A3967FB95F}",
"path": "levels/multiplayer/autocomponent_rpc/globalgamedata.scriptcanvas"
}
},
"Component_[16436925042043744033]": {
@ -636,6 +624,13 @@
"$type": "SelectionComponent",
"Id": 12302672911455629152
},
"Component_[12517591696100736853]": {
"$type": "GenericComponentWrapper",
"Id": 12517591696100736853,
"m_template": {
"$type": "AutomatedTesting::NetworkTestLevelEntityComponent"
}
},
"Component_[14169903623243423134]": {
"$type": "EditorVisibilityComponent",
"Id": 14169903623243423134
@ -644,13 +639,6 @@
"$type": "EditorInspectorComponent",
"Id": 14607413934411389854
},
"Component_[15396284312416541768]": {
"$type": "GenericComponentWrapper",
"Id": 15396284312416541768,
"m_template": {
"$type": "Multiplayer::LocalPredictionPlayerInputComponent"
}
},
"Component_[15494977028055234270]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 15494977028055234270
@ -682,22 +670,10 @@
"$type": "EditorScriptCanvasComponent",
"Id": 7256163899440301540,
"m_name": "AutoComponent_RPC_NetLevelEntity",
"m_assetHolder": {
"m_asset": {
"assetId": {
"guid": "{1D517006-AC01-5ECA-AE66-0E007871F0CD}"
},
"assetHint": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc_netlevelentity.scriptcanvas"
}
},
"runtimeDataIsValid": true,
"runtimeDataOverrides": {
"source": {
"assetId": {
"guid": "{1D517006-AC01-5ECA-AE66-0E007871F0CD}"
},
"assetHint": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc_netlevelentity.scriptcanvas"
}
"sourceHandle": {
"id": "{1D517006-AC01-5ECA-AE66-0E007871F0CD}",
"path": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc_netlevelentity.scriptcanvas"
}
},
"Component_[731336627222243355]": {
@ -730,13 +706,6 @@
"$type": "NetBindComponent"
}
},
"Component_[9816897251206708579]": {
"$type": "GenericComponentWrapper",
"Id": 9816897251206708579,
"m_template": {
"$type": "AutomatedTesting::NetworkTestPlayerComponent"
}
},
"Component_[9880860858035405475]": {
"$type": "EditorOnlyEntityComponent",
"Id": 9880860858035405475

@ -5,7 +5,7 @@
"ClassData": {
"m_scriptCanvas": {
"Id": {
"id": 7369225496155711251
"id": 7558387155527535988
},
"Name": "AutoComponent_RPC_NetLevelEntity",
"Components": {
@ -93,7 +93,6 @@
],
"Datums": [
{
"isOverloadedStorage": false,
"scriptCanvasType": {
"m_type": 1
},
@ -108,6 +107,9 @@
"methodType": 2,
"methodName": "GetAuthorityToClientNoParams_PlayFxEventByEntityId",
"className": "NetworkTestLevelEntityComponent",
"resultSlotIDs": [
{}
],
"inputSlots": [
{
"m_id": "{AE2A0AA3-99DD-4DE4-AFEA-7560F078943C}"
@ -688,6 +690,199 @@
}
}
},
{
"Id": {
"id": 11750998249450
},
"Name": "SC-Node(IsNetEntityRoleAuthority)",
"Components": {
"Component_[17217487756380135718]": {
"$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method",
"Id": 17217487756380135718,
"Slots": [
{
"id": {
"m_id": "{C58EF254-1A51-443B-B35E-B26831323D27}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "EntityId: 0",
"Descriptor": {
"ConnectionType": 1,
"SlotType": 2
},
"DataType": 1
},
{
"id": {
"m_id": "{98927A53-663A-452D-ABAF-01D31F7D5D53}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "In",
"Descriptor": {
"ConnectionType": 1,
"SlotType": 1
}
},
{
"id": {
"m_id": "{89F646CA-FBC6-45D2-916B-0B47474EE693}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "Out",
"Descriptor": {
"ConnectionType": 2,
"SlotType": 1
}
},
{
"id": {
"m_id": "{3FFC81A6-5C31-4CBA-8253-5DF361F10610}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "Is Role Authority",
"DisplayDataType": {
"m_type": 0
},
"Descriptor": {
"ConnectionType": 2,
"SlotType": 2
},
"DataType": 1
}
],
"Datums": [
{
"isOverloadedStorage": false,
"scriptCanvasType": {
"m_type": 1
},
"isNullPointer": false,
"$type": "EntityId",
"value": {
"id": 2901262558
},
"label": "Entity Id"
}
],
"methodType": 2,
"methodName": "IsNetEntityRoleAuthority",
"className": "NetBindComponent",
"inputSlots": [
{
"m_id": "{C58EF254-1A51-443B-B35E-B26831323D27}"
}
],
"prettyClassName": "NetBindComponent"
}
}
},
{
"Id": {
"id": 13206992162794
},
"Name": "SC-Node(Gate)",
"Components": {
"Component_[18126119383071583133]": {
"$type": "Gate",
"Id": 18126119383071583133,
"Slots": [
{
"id": {
"m_id": "{3896AA13-516C-410F-AB9C-2CAA5E71AEF6}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "Condition",
"toolTip": "If true the node will signal the Output and proceed execution",
"Descriptor": {
"ConnectionType": 1,
"SlotType": 2
},
"DataType": 1
},
{
"id": {
"m_id": "{F651B19A-FD1A-44EB-9C16-0CDB44CD85AA}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "In",
"toolTip": "Input signal",
"Descriptor": {
"ConnectionType": 1,
"SlotType": 1
}
},
{
"id": {
"m_id": "{78807DC9-82B7-4893-ADA4-53E51C2AD3D1}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "True",
"toolTip": "Signaled if the condition provided evaluates to true.",
"Descriptor": {
"ConnectionType": 2,
"SlotType": 1
}
},
{
"id": {
"m_id": "{3B353484-F14C-4D93-AD1D-6F3EDAE4B71C}"
},
"contracts": [
{
"$type": "SlotTypeContract"
}
],
"slotName": "False",
"toolTip": "Signaled if the condition provided evaluates to false.",
"Descriptor": {
"ConnectionType": 2,
"SlotType": 1
}
}
],
"Datums": [
{
"isOverloadedStorage": false,
"scriptCanvasType": {
"m_type": 0
},
"isNullPointer": false,
"$type": "bool",
"value": false,
"label": "Condition"
}
]
}
}
},
{
"Id": {
"id": 57025381737912
@ -882,7 +1077,6 @@
],
"Datums": [
{
"isOverloadedStorage": false,
"scriptCanvasType": {
"m_type": 1
},
@ -897,6 +1091,9 @@
"methodType": 2,
"methodName": "AuthorityToClientNoParams_PlayFxByEntityId",
"className": "NetworkTestLevelEntityComponent",
"resultSlotIDs": [
{}
],
"inputSlots": [
{
"m_id": "{029728DF-0939-4D64-A9A1-3DB4B8AF127E}"
@ -1036,7 +1233,6 @@
],
"Datums": [
{
"isOverloadedStorage": false,
"scriptCanvasType": {
"m_type": 4,
"m_azType": "{F429F985-AF00-529B-8449-16E56694E5F9}"
@ -1223,34 +1419,6 @@
}
}
},
{
"Id": {
"id": 57055446508984
},
"Name": "srcEndpoint=(TimeDelay: Done), destEndpoint=(Repeater: Start)",
"Components": {
"Component_[6292481678297438578]": {
"$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
"Id": 6292481678297438578,
"sourceEndpoint": {
"nodeId": {
"id": 57012496836024
},
"slotId": {
"m_id": "{158B30BE-BD39-40AE-A8A8-F0E5694F0180}"
}
},
"targetEndpoint": {
"nodeId": {
"id": 56986727032248
},
"slotId": {
"m_id": "{07267CBA-B377-4B57-8A04-E322F8BFC07F}"
}
}
}
}
},
{
"Id": {
"id": 10269167405311
@ -1530,6 +1698,118 @@
}
}
}
},
{
"Id": {
"id": 13030898503658
},
"Name": "srcEndpoint=(TimeDelay: Done), destEndpoint=(IsNetEntityRoleAuthority: In)",
"Components": {
"Component_[14235185264262332827]": {
"$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
"Id": 14235185264262332827,
"sourceEndpoint": {
"nodeId": {
"id": 57012496836024
},
"slotId": {
"m_id": "{158B30BE-BD39-40AE-A8A8-F0E5694F0180}"
}
},
"targetEndpoint": {
"nodeId": {
"id": 11750998249450
},
"slotId": {
"m_id": "{98927A53-663A-452D-ABAF-01D31F7D5D53}"
}
}
}
}
},
{
"Id": {
"id": 14005856079850
},
"Name": "srcEndpoint=(IsNetEntityRoleAuthority: Out), destEndpoint=(If: In)",
"Components": {
"Component_[16302238484508620286]": {
"$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
"Id": 16302238484508620286,
"sourceEndpoint": {
"nodeId": {
"id": 11750998249450
},
"slotId": {
"m_id": "{89F646CA-FBC6-45D2-916B-0B47474EE693}"
}
},
"targetEndpoint": {
"nodeId": {
"id": 13206992162794
},
"slotId": {
"m_id": "{F651B19A-FD1A-44EB-9C16-0CDB44CD85AA}"
}
}
}
}
},
{
"Id": {
"id": 14302208823274
},
"Name": "srcEndpoint=(IsNetEntityRoleAuthority: Is Role Authority), destEndpoint=(If: Condition)",
"Components": {
"Component_[3887593885874168259]": {
"$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
"Id": 3887593885874168259,
"sourceEndpoint": {
"nodeId": {
"id": 11750998249450
},
"slotId": {
"m_id": "{3FFC81A6-5C31-4CBA-8253-5DF361F10610}"
}
},
"targetEndpoint": {
"nodeId": {
"id": 13206992162794
},
"slotId": {
"m_id": "{3896AA13-516C-410F-AB9C-2CAA5E71AEF6}"
}
}
}
}
},
{
"Id": {
"id": 14637216272362
},
"Name": "srcEndpoint=(If: True), destEndpoint=(Repeater: Start)",
"Components": {
"Component_[8721834474263401249]": {
"$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
"Id": 8721834474263401249,
"sourceEndpoint": {
"nodeId": {
"id": 13206992162794
},
"slotId": {
"m_id": "{78807DC9-82B7-4893-ADA4-53E51C2AD3D1}"
}
},
"targetEndpoint": {
"nodeId": {
"id": 56986727032248
},
"slotId": {
"m_id": "{07267CBA-B377-4B57-8A04-E322F8BFC07F}"
}
}
}
}
}
]
},
@ -1571,6 +1851,37 @@
}
}
},
{
"Key": {
"id": 11750998249450
},
"Value": {
"ComponentData": {
"{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
"$type": "NodeSaveData"
},
"{328FF15C-C302-458F-A43D-E1794DE0904E}": {
"$type": "GeneralNodeTitleComponentSaveData",
"PaletteOverride": "MethodNodeTitlePalette"
},
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
100.0,
60.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
"$type": "StylingComponentSaveData",
"SubStyle": ".method"
},
"{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
"$type": "PersistentIdComponentSaveData",
"PersistentId": "{73B270BC-9743-41C1-9E48-0CAB5A63AC97}"
}
}
}
},
{
"Key": {
"id": 11993350262154
@ -1587,8 +1898,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
-120.0,
340.0
60.0,
480.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1618,8 +1929,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
340.0,
360.0
520.0,
500.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1633,6 +1944,36 @@
}
}
},
{
"Key": {
"id": 13206992162794
},
"Value": {
"ComponentData": {
"{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
"$type": "NodeSaveData"
},
"{328FF15C-C302-458F-A43D-E1794DE0904E}": {
"$type": "GeneralNodeTitleComponentSaveData",
"PaletteOverride": "LogicNodeTitlePalette"
},
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
540.0,
60.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
"$type": "StylingComponentSaveData"
},
"{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
"$type": "PersistentIdComponentSaveData",
"PersistentId": "{3F73BD0E-D02D-4A48-9E25-F9FD4A0F1B89}"
}
}
}
},
{
"Key": {
"id": 16962627423626
@ -1649,8 +1990,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
440.0,
-40.0
1240.0,
0.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1680,8 +2021,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
80.0,
-60.0
860.0,
0.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1740,8 +2081,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
800.0,
260.0
980.0,
400.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1770,8 +2111,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
420.0,
100.0
1220.0,
140.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1800,8 +2141,8 @@
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
"$type": "GeometrySaveData",
"Position": [
800.0,
460.0
980.0,
600.0
]
},
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
@ -1877,16 +2218,16 @@
},
{
"Key": {
"id": 7369225496155711251
"id": 7558387155527535988
},
"Value": {
"ComponentData": {
"{5F84B500-8C45-40D1-8EFC-A5306B241444}": {
"$type": "SceneComponentSaveData",
"ViewParams": {
"Scale": 0.7585823890144868,
"AnchorX": -205.64674377441406,
"AnchorY": -467.9781799316406
"Scale": 0.9585879578077288,
"AnchorX": 488.2181091308594,
"AnchorY": -175.25778198242188
}
}
}
@ -1915,6 +2256,14 @@
"Key": 6462358712820489356,
"Value": 1
},
{
"Key": 8065262779685207188,
"Value": 1
},
{
"Key": 8452971738487658154,
"Value": 1
},
{
"Key": 10684225535275896474,
"Value": 3

@ -42,6 +42,16 @@
"RayTracingAccelerationStructurePass"
]
},
{
"Name": "TerrainDetailTextureComputePass",
"TemplateName": "TerrainDetailTextureComputePassTemplate",
"Enabled": false
},
{
"Name": "TerrainMacroTextureComputePass",
"TemplateName": "TerrainMacroTextureComputePassTemplate",
"Enabled": false
},
{
"Name": "DepthPrePass",
"TemplateName": "DepthMSAAParentTemplate",
@ -215,7 +225,7 @@
// Note: The following two lines represent the choice of rendering pipeline for the hair.
// You can either choose to use PPLL or ShortCut and accordingly change the flag
// 'm_usePPLLRenderTechnique' in the class 'HairFeatureProcessor.cpp'
// "TemplateName": "HairParentPassTemplate",
// "TemplateName": "HairParentPassTemplate",
"TemplateName": "HairParentShortCutPassTemplate",
"Enabled": true,
"Connections": [

@ -1,369 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : Tooltip that displays bitmap.
#include "EditorDefs.h"
#include "BitmapToolTip.h"
// Qt
#include <QVBoxLayout>
// Editor
#include "Util/Image.h"
#include "Util/ImageUtil.h"
static const int STATIC_TEXT_C_HEIGHT = 42;
static const int HISTOGRAM_C_HEIGHT = 130;
/////////////////////////////////////////////////////////////////////////////
// CBitmapToolTip
CBitmapToolTip::CBitmapToolTip(QWidget* parent)
: QWidget(parent, Qt::ToolTip)
, m_staticBitmap(new QLabel(this))
, m_staticText(new QLabel(this))
, m_rgbaHistogram(new CImageHistogramCtrl(this))
, m_alphaChannelHistogram(new CImageHistogramCtrl(this))
{
m_nTimer = 0;
m_hToolWnd = nullptr;
m_bShowHistogram = true;
m_bShowFullsize = false;
m_eShowMode = ESHOW_RGB;
connect(&m_timer, &QTimer::timeout, this, &CBitmapToolTip::OnTimer);
auto* layout = new QVBoxLayout(this);
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->addWidget(m_staticBitmap);
layout->addWidget(m_staticText);
auto* histogramLayout = new QHBoxLayout();
histogramLayout->addWidget(m_rgbaHistogram);
histogramLayout->addWidget(m_alphaChannelHistogram);
m_alphaChannelHistogram->setVisible(false);
layout->addLayout(histogramLayout);
setLayout(layout);
}
CBitmapToolTip::~CBitmapToolTip()
{
}
//////////////////////////////////////////////////////////////////////////
void CBitmapToolTip::GetShowMode(EShowMode& eShowMode, bool& bShowInOriginalSize) const
{
bShowInOriginalSize = CheckVirtualKey(Qt::Key_Space);
eShowMode = ESHOW_RGB;
if (m_bHasAlpha)
{
if (CheckVirtualKey(Qt::Key_Control))
{
eShowMode = ESHOW_RGB_ALPHA;
}
else if (CheckVirtualKey(Qt::Key_Alt))
{
eShowMode = ESHOW_ALPHA;
}
else if (CheckVirtualKey(Qt::Key_Shift))
{
eShowMode = ESHOW_RGBA;
}
}
else if (m_bIsLimitedHDR)
{
if (CheckVirtualKey(Qt::Key_Shift))
{
eShowMode = ESHOW_RGBE;
}
}
}
const char* CBitmapToolTip::GetShowModeDescription(EShowMode eShowMode, [[maybe_unused]] bool bShowInOriginalSize) const
{
switch (eShowMode)
{
case ESHOW_RGB:
return "RGB";
case ESHOW_RGB_ALPHA:
return "RGB+A";
case ESHOW_ALPHA:
return "Alpha";
case ESHOW_RGBA:
return "RGBA";
case ESHOW_RGBE:
return "RGBExp";
}
return "";
}
void CBitmapToolTip::RefreshViewmode()
{
LoadImage(m_filename);
if (m_eShowMode == ESHOW_RGB_ALPHA || m_eShowMode == ESHOW_RGBA)
{
m_rgbaHistogram->setVisible(true);
m_alphaChannelHistogram->setVisible(true);
}
else if (m_eShowMode == ESHOW_ALPHA)
{
m_rgbaHistogram->setVisible(false);
m_alphaChannelHistogram->setVisible(true);
}
else
{
m_rgbaHistogram->setVisible(true);
m_alphaChannelHistogram->setVisible(false);
}
}
bool CBitmapToolTip::LoadImage(const QString& imageFilename)
{
EShowMode eShowMode = ESHOW_RGB;
const char* pShowModeDescription = "RGB";
bool bShowInOriginalSize = false;
GetShowMode(eShowMode, bShowInOriginalSize);
pShowModeDescription = GetShowModeDescription(eShowMode, bShowInOriginalSize);
QString convertedFileName = Path::GamePathToFullPath(Path::ReplaceExtension(imageFilename, ".dds"));
// We need to check against both the image filename and the converted filename as it is possible that the
// converted file existed but failed to load previously and we reverted to loading the source asset.
bool alreadyLoadedImage = ((m_filename == convertedFileName) || (m_filename == imageFilename));
if (alreadyLoadedImage && (m_eShowMode == eShowMode) && (m_bShowFullsize == bShowInOriginalSize))
{
return true;
}
CCryFile fileCheck;
if (!fileCheck.Open(convertedFileName.toUtf8().data(), "rb"))
{
// if we didn't find it, then default back to just using what we can find (if any)
convertedFileName = imageFilename;
}
else
{
fileCheck.Close();
}
m_eShowMode = eShowMode;
m_bShowFullsize = bShowInOriginalSize;
CImageEx image;
image.SetHistogramEqualization(CheckVirtualKey(Qt::Key_Shift));
bool loadedRequestedAsset = true;
if (!CImageUtil::LoadImage(convertedFileName, image))
{
//Failed to load the requested asset, let's try loading the source asset if available.
loadedRequestedAsset = false;
if (!CImageUtil::LoadImage(imageFilename, image))
{
m_staticBitmap->clear();
return false;
}
}
QString imginfo;
m_filename = loadedRequestedAsset ? convertedFileName : imageFilename;
m_bHasAlpha = image.HasAlphaChannel();
m_bIsLimitedHDR = image.IsLimitedHDR();
GetShowMode(eShowMode, bShowInOriginalSize);
pShowModeDescription = GetShowModeDescription(eShowMode, bShowInOriginalSize);
if (m_bHasAlpha)
{
imginfo = tr("%1x%2 %3\nShowing %4 (ALT=Alpha, SHIFT=RGBA, CTRL=RGB+A, SPACE=see in original size)");
}
else if (m_bIsLimitedHDR)
{
imginfo = tr("%1x%2 %3\nShowing %4 (SHIFT=see hist.-equalized, SPACE=see in original size)");
}
else
{
imginfo = tr("%1x%2 %3\nShowing %4 (SPACE=see in original size)");
}
imginfo = imginfo.arg(image.GetWidth()).arg(image.GetHeight()).arg(image.GetFormatDescription()).arg(pShowModeDescription);
m_staticText->setText(imginfo);
int w = image.GetWidth();
int h = image.GetHeight();
int multiplier = (m_eShowMode == ESHOW_RGB_ALPHA ? 2 : 1);
int originalW = w * multiplier;
int originalH = h;
if (!bShowInOriginalSize || (w == 0))
{
w = 256;
}
if (!bShowInOriginalSize || (h == 0))
{
h = 256;
}
w *= multiplier;
resize(w + 4, h + 4 + STATIC_TEXT_C_HEIGHT + HISTOGRAM_C_HEIGHT);
setVisible(true);
CImageEx scaledImage;
if (bShowInOriginalSize && (originalW < w))
{
w = originalW;
}
if (bShowInOriginalSize && (originalH < h))
{
h = originalH;
}
scaledImage.Allocate(w, h);
if (m_eShowMode == ESHOW_RGB_ALPHA)
{
CImageUtil::ScaleToDoubleFit(image, scaledImage);
}
else
{
CImageUtil::ScaleToFit(image, scaledImage);
}
if (m_eShowMode == ESHOW_RGB || m_eShowMode == ESHOW_RGBE)
{
scaledImage.SwapRedAndBlue();
scaledImage.FillAlpha();
}
else if (m_eShowMode == ESHOW_ALPHA)
{
for (int hh = 0; hh < scaledImage.GetHeight(); hh++)
{
for (int ww = 0; ww < scaledImage.GetWidth(); ww++)
{
int a = scaledImage.ValueAt(ww, hh) >> 24;
scaledImage.ValueAt(ww, hh) = RGB(a, a, a);
}
}
}
else if (m_eShowMode == ESHOW_RGB_ALPHA)
{
int halfWidth = scaledImage.GetWidth() / 2;
for (int hh = 0; hh < scaledImage.GetHeight(); hh++)
{
for (int ww = 0; ww < halfWidth; ww++)
{
int r = GetRValue(scaledImage.ValueAt(ww, hh));
int g = GetGValue(scaledImage.ValueAt(ww, hh));
int b = GetBValue(scaledImage.ValueAt(ww, hh));
int a = scaledImage.ValueAt(ww, hh) >> 24;
scaledImage.ValueAt(ww, hh) = RGB(b, g, r);
scaledImage.ValueAt(ww + halfWidth, hh) = RGB(a, a, a);
}
}
}
else //if (m_showMode == ESHOW_RGBA)
{
scaledImage.SwapRedAndBlue();
}
QImage qImage(scaledImage.GetWidth(), scaledImage.GetHeight(), QImage::Format_RGB32);
memcpy(qImage.bits(), scaledImage.GetData(), qImage.sizeInBytes());
m_staticBitmap->setPixmap(QPixmap::fromImage(qImage));
if (m_bShowHistogram && scaledImage.GetData())
{
m_rgbaHistogram->ComputeHistogram(image, CImageHistogram::eImageFormat_32BPP_BGRA);
m_rgbaHistogram->setDrawMode(EHistogramDrawMode::OverlappedRGB);
m_alphaChannelHistogram->histogramDisplay()->CopyComputedDataFrom(m_rgbaHistogram->histogramDisplay());
m_alphaChannelHistogram->setDrawMode(EHistogramDrawMode::AlphaChannel);
}
return true;
}
void CBitmapToolTip::OnTimer()
{
/*
if (IsWindowVisible())
{
if (m_bHaveAnythingToRender)
Invalidate();
}
*/
if (m_hToolWnd)
{
QRect toolRc(m_toolRect);
QRect rc = geometry();
QPoint cursorPos = QCursor::pos();
toolRc.moveTopLeft(m_hToolWnd->mapToGlobal(toolRc.topLeft()));
if (!toolRc.contains(cursorPos) && !rc.contains(cursorPos))
{
setVisible(false);
}
else
{
RefreshViewmode();
}
}
}
//////////////////////////////////////////////////////////////////////////
void CBitmapToolTip::showEvent([[maybe_unused]] QShowEvent* event)
{
QPoint cursorPos = QCursor::pos();
move(cursorPos);
m_timer.start(500);
}
//////////////////////////////////////////////////////////////////////////
void CBitmapToolTip::hideEvent([[maybe_unused]] QHideEvent* event)
{
m_timer.stop();
}
//////////////////////////////////////////////////////////////////////////
void CBitmapToolTip::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Control || event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift)
{
RefreshViewmode();
}
}
void CBitmapToolTip::keyReleaseEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Control || event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift)
{
RefreshViewmode();
}
}
//////////////////////////////////////////////////////////////////////////
void CBitmapToolTip::SetTool(QWidget* pWnd, const QRect& rect)
{
assert(pWnd);
m_hToolWnd = pWnd;
m_toolRect = rect;
}
#include <Controls/moc_BitmapToolTip.cpp>

@ -1,88 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : Tooltip that displays bitmap.
#ifndef CRYINCLUDE_EDITOR_CONTROLS_BITMAPTOOLTIP_H
#define CRYINCLUDE_EDITOR_CONTROLS_BITMAPTOOLTIP_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "Controls/ImageHistogramCtrl.h"
#include <QLabel>
#include <QTimer>
#endif
//////////////////////////////////////////////////////////////////////////
class CBitmapToolTip
: public QWidget
{
Q_OBJECT
// Construction
public:
enum EShowMode
{
ESHOW_RGB = 0,
ESHOW_ALPHA,
ESHOW_RGBA,
ESHOW_RGB_ALPHA,
ESHOW_RGBE
};
CBitmapToolTip(QWidget* parent = nullptr);
virtual ~CBitmapToolTip();
bool Create(const RECT& rect);
// Attributes
public:
// Operations
public:
void RefreshViewmode();
bool LoadImage(const QString& imageFilename);
void SetTool(QWidget* pWnd, const QRect& rect);
// Generated message map functions
protected:
void OnTimer();
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;
private:
void GetShowMode(EShowMode& showMode, bool& showInOriginalSize) const;
const char* GetShowModeDescription(EShowMode showMode, bool showInOriginalSize) const;
QLabel* m_staticBitmap;
QLabel* m_staticText;
QString m_filename;
bool m_bShowHistogram;
EShowMode m_eShowMode;
bool m_bShowFullsize;
bool m_bHasAlpha;
bool m_bIsLimitedHDR;
CImageHistogramCtrl* m_rgbaHistogram;
CImageHistogramCtrl* m_alphaChannelHistogram;
int m_nTimer;
QWidget* m_hToolWnd;
QRect m_toolRect;
QTimer m_timer;
};
#endif // CRYINCLUDE_EDITOR_CONTROLS_BITMAPTOOLTIP_H

@ -1,172 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "QBitmapPreviewDialog.h"
#include <Controls/ui_QBitmapPreviewDialog.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QPainter>
#include <QScreen>
void QBitmapPreviewDialog::ImageData::setRgba8888(const void* buffer, const int& w, const int& h)
{
const unsigned long bytes = w * h * 4;
m_buffer.resize(bytes);
memcpy(m_buffer.data(), buffer, bytes);
m_image = QImage((uchar*)m_buffer.constData(), w, h, QImage::Format::Format_RGBA8888);
}
static void fillChecker(int w, int h, unsigned int* dst)
{
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
dst[y * w + x] = 0xFF000000 | (((x >> 2) + (y >> 2)) % 2 == 0 ? 0x007F7F7F : 0x00000000);
}
}
}
QBitmapPreviewDialog::QBitmapPreviewDialog(QWidget* parent)
: QWidget(parent)
, ui(new Ui::QBitmapTooltip)
{
ui->setupUi(this);
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_ShowWithoutActivating);
// Clear label text
ui->m_placeholderBitmap->setText("");
ui->m_placeholderHistogram->setText("");
ui->m_bitmapSize->setProperty("tableRow", "Odd");
ui->m_Mips->setProperty("tableRow", "Even");
ui->m_Mean->setProperty("tableRow", "Odd");
ui->m_StdDev->setProperty("tableRow", "Even");
ui->m_Median->setProperty("tableRow", "Odd");
ui->m_labelForBitmapSize->setProperty("tooltipLabel", "content");
ui->m_labelForMean->setProperty("tooltipLabel", "content");
ui->m_labelForMedian->setProperty("tooltipLabel", "content");
ui->m_labelForMips->setProperty("tooltipLabel", "content");
ui->m_labelForStdDev->setProperty("tooltipLabel", "content");
ui->m_vBitmapSize->setProperty("tooltipLabel", "content");
ui->m_vMean->setProperty("tooltipLabel", "content");
ui->m_vMedian->setProperty("tooltipLabel", "content");
ui->m_vMips->setProperty("tooltipLabel", "content");
ui->m_vStdDev->setProperty("tooltipLabel", "content");
// Initialize placeholder images
const int w = 64;
const int h = 64;
QByteArray buffer;
buffer.resize(w * h * 4);
unsigned int* dst = (unsigned int*)buffer.data();
fillChecker(w, h, dst);
m_checker.setRgba8888(buffer.constData(), w, h);
m_initialSize = window()->window()->geometry().size();
}
QBitmapPreviewDialog::~QBitmapPreviewDialog()
{
delete ui;
}
void QBitmapPreviewDialog::setImageRgba8888(const void* buffer, const int& w, const int& h, [[maybe_unused]] const QString& info)
{
m_imageMain.setRgba8888(buffer, w, h);
}
QRect QBitmapPreviewDialog::getHistogramArea()
{
return QRect(ui->m_placeholderHistogram->pos(), ui->m_placeholderHistogram->size());
}
void QBitmapPreviewDialog::setFullSize(const bool& fullSize)
{
if (fullSize)
{
QSize desktop = QApplication::screenAt(ui->m_placeholderBitmap->pos())->availableGeometry().size();
QSize image = m_imageMain.m_image.size();
QPoint location = mapToGlobal(ui->m_placeholderBitmap->pos());
QSize finalSize;
finalSize.setWidth((image.width() < (desktop.width() - location.x())) ? image.width() : (desktop.width() - location.x()));
finalSize.setHeight((image.height() < (desktop.height() - location.y())) ? image.height() : (desktop.height() - location.y()));
float scale = (finalSize.width() < finalSize.height()) ? finalSize.width() / float(m_imageMain.m_image.width()) : finalSize.height() / float(m_imageMain.m_image.height());
ui->m_placeholderBitmap->setFixedSize(scale * m_imageMain.m_image.size());
}
else
{
ui->m_placeholderBitmap->setFixedSize(256, 256);
}
adjustSize();
update();
}
void QBitmapPreviewDialog::paintEvent(QPaintEvent* e)
{
QWidget::paintEvent(e);
QRect rect(ui->m_placeholderBitmap->pos(), ui->m_placeholderBitmap->size());
drawImageData(rect, m_imageMain);
}
void QBitmapPreviewDialog::drawImageData(const QRect& rect, const ImageData& imgData)
{
// Draw the
QPainter p(this);
p.drawImage(rect.topLeft(), m_checker.m_image.scaled(rect.size()));
p.drawImage(rect.topLeft(), imgData.m_image.scaled(rect.size()));
// Draw border
QPen pen;
pen.setColor(QColor(0, 0, 0));
p.drawRect(rect.top(), rect.left(), rect.width() - 1, rect.height());
}
void QBitmapPreviewDialog::setSize(QString _value)
{
ui->m_vBitmapSize->setText(_value);
}
void QBitmapPreviewDialog::setMips(QString _value)
{
ui->m_vMips->setText(_value);
}
void QBitmapPreviewDialog::setMean(QString _value)
{
ui->m_vMean->setText(_value);
}
void QBitmapPreviewDialog::setMedian(QString _value)
{
ui->m_vMedian->setText(_value);
}
void QBitmapPreviewDialog::setStdDev(QString _value)
{
ui->m_vStdDev->setText(_value);
}
QSize QBitmapPreviewDialog::GetCurrentBitmapSize()
{
return ui->m_placeholderBitmap->size();
}
QSize QBitmapPreviewDialog::GetOriginalImageSize()
{
return m_imageMain.m_image.size();
}
#include <Controls/moc_QBitmapPreviewDialog.cpp>

@ -1,64 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef QBITMAPPREVIEWDIALOG_H
#define QBITMAPPREVIEWDIALOG_H
#if !defined(Q_MOC_RUN)
#include <QWidget>
#include <QPixmap>
#include <QImage>
#endif
class QLabel;
namespace Ui {
class QBitmapTooltip;
}
class QBitmapPreviewDialog
: public QWidget
{
Q_OBJECT
struct ImageData
{
QByteArray m_buffer;
QImage m_image;
void setRgba8888(const void* buffer, const int& w, const int& h);
};
public:
explicit QBitmapPreviewDialog(QWidget* parent = 0);
virtual ~QBitmapPreviewDialog();
QSize GetCurrentBitmapSize();
QSize GetOriginalImageSize();
protected:
void setImageRgba8888(const void* buffer, const int& w, const int& h, const QString& info);
void setSize(QString _value);
void setMips(QString _value);
void setMean(QString _value);
void setMedian(QString _value);
void setStdDev(QString _value);
QRect getHistogramArea();
void setFullSize(const bool& fullSize);
void paintEvent(QPaintEvent* e) override;
private:
void drawImageData(const QRect& rect, const ImageData& imgData);
protected:
Ui::QBitmapTooltip* ui;
QSize m_initialSize;
ImageData m_checker;
ImageData m_imageMain;
};
#endif // QBITMAPPREVIEWDIALOG_H

@ -1,390 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QBitmapTooltip</class>
<widget class="QWidget" name="QBitmapTooltip">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>510</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>256</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_placeholderBitmap">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>256</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string>Bitmap Area</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_placeholderHistogram">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>128</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string>Histogram Area</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="m_bitmapSize" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>24</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_labelForBitmapSize">
<property name="text">
<string>Size:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_vBitmapSize">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Size Value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="m_Mips" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>24</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_labelForMips">
<property name="text">
<string>DXT5 Mips:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_vMips">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Size Value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="m_Mean" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>24</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_labelForMean">
<property name="text">
<string>Mean:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_vMean">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Size Value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="m_StdDev" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>24</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_labelForStdDev">
<property name="text">
<string>StdDev:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_vStdDev">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Size Value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="m_Median" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>24</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_labelForMedian">
<property name="text">
<string>Median:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_vMedian">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Size Value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -1,528 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "QBitmapPreviewDialogImp.h"
// Cry
#include <ITexture.h>
// EditorCore
#include <Util/Image.h>
#include <Include/IImageUtil.h>
// QT
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: class '...' needs to have dll-interface to be used by clients of class '...'
#include <QEvent>
#include <QKeyEvent>
#include <QPainter>
#include <QPainterPath>
#include <qmath.h>
AZ_POP_DISABLE_WARNING
#include <Controls/ui_QBitmapPreviewDialog.h>
static const int kDefaultWidth = 256;
static const int kDefaultHeight = 256;
QBitmapPreviewDialogImp::QBitmapPreviewDialogImp(QWidget* parent)
: QBitmapPreviewDialog(parent)
, m_image(new CImageEx())
, m_showOriginalSize(false)
, m_showMode(ESHOW_RGB)
, m_histrogramMode(eHistogramMode_OverlappedRGB)
{
setMouseTracking(true);
setImage("");
ui->m_placeholderBitmap->setStyleSheet("background-color: rgba(0, 0, 0, 0);");
ui->m_placeholderHistogram->setStyleSheet("background-color: rgba(0, 0, 0, 0);");
ui->m_labelForBitmapSize->setProperty("tooltipLabel", "Content");
ui->m_labelForMean->setProperty("tooltipLabel", "Content");
ui->m_labelForMedian->setProperty("tooltipLabel", "Content");
ui->m_labelForMips->setProperty("tooltipLabel", "Content");
ui->m_labelForStdDev->setProperty("tooltipLabel", "Content");
ui->m_vBitmapSize->setProperty("tooltipLabel", "Content");
ui->m_vMean->setProperty("tooltipLabel", "Content");
ui->m_vMedian->setProperty("tooltipLabel", "Content");
ui->m_vMips->setProperty("tooltipLabel", "Content");
ui->m_vStdDev->setProperty("tooltipLabel", "Content");
setUIStyleMode(EUISTYLE_IMAGE_ONLY);
}
QBitmapPreviewDialogImp::~QBitmapPreviewDialogImp()
{
SAFE_DELETE(m_image);
}
void QBitmapPreviewDialogImp::setImage(const QString path)
{
if (path.isEmpty()
|| m_path == path
|| !GetIEditor()->GetImageUtil()->LoadImage(path.toUtf8().data(), *m_image))
{
return;
}
m_showOriginalSize = isSizeSmallerThanDefault();
m_path = path;
refreshData();
}
void QBitmapPreviewDialogImp::setShowMode(EShowMode mode)
{
if (mode == ESHOW_NumModes)
{
return;
}
m_showMode = mode;
refreshData();
update();
}
void QBitmapPreviewDialogImp::toggleShowMode()
{
m_showMode = (EShowMode)(((int)m_showMode + 1) % ESHOW_NumModes);
refreshData();
update();
}
void QBitmapPreviewDialogImp::setUIStyleMode(EUIStyle mode)
{
if (mode >= EUISTYLE_NumModes)
{
return;
}
m_uiStyle = mode;
if (m_uiStyle == EUISTYLE_IMAGE_ONLY)
{
ui->m_placeholderHistogram->hide();
ui->m_labelForBitmapSize->hide();
ui->m_labelForMean->hide();
ui->m_labelForMedian->hide();
ui->m_labelForMips->hide();
ui->m_labelForStdDev->hide();
ui->m_vBitmapSize->hide();
ui->m_vMean->hide();
ui->m_vMedian->hide();
ui->m_vMips->hide();
ui->m_vStdDev->hide();
}
else
{
ui->m_placeholderHistogram->show();
ui->m_labelForBitmapSize->show();
ui->m_labelForMean->show();
ui->m_labelForMedian->show();
ui->m_labelForMips->show();
ui->m_labelForStdDev->show();
ui->m_vBitmapSize->show();
ui->m_vMean->show();
ui->m_vMedian->show();
ui->m_vMips->show();
ui->m_vStdDev->show();
}
}
const QBitmapPreviewDialogImp::EShowMode& QBitmapPreviewDialogImp::getShowMode() const
{
return m_showMode;
}
void QBitmapPreviewDialogImp::setHistogramMode(EHistogramMode mode)
{
if (mode == eHistogramMode_NumModes)
{
return;
}
m_histrogramMode = mode;
}
void QBitmapPreviewDialogImp::toggleHistrogramMode()
{
m_histrogramMode = (EHistogramMode)(((int)m_histrogramMode + 1) % eHistogramMode_NumModes);
update();
}
const QBitmapPreviewDialogImp::EHistogramMode& QBitmapPreviewDialogImp::getHistogramMode() const
{
return m_histrogramMode;
}
void QBitmapPreviewDialogImp::toggleOriginalSize()
{
m_showOriginalSize = !m_showOriginalSize;
refreshData();
update();
}
bool QBitmapPreviewDialogImp::isSizeSmallerThanDefault()
{
return m_image->GetWidth() < kDefaultWidth && m_image->GetHeight() < kDefaultHeight;
}
void QBitmapPreviewDialogImp::setOriginalSize(bool value)
{
m_showOriginalSize = value;
refreshData();
update();
}
const char* QBitmapPreviewDialogImp::GetShowModeDescription(EShowMode eShowMode, [[maybe_unused]] bool bShowInOriginalSize) const
{
switch (eShowMode)
{
case ESHOW_RGB:
return "RGB";
case ESHOW_RGB_ALPHA:
return "RGB+A";
case ESHOW_ALPHA:
return "Alpha";
case ESHOW_RGBA:
return "RGBA";
case ESHOW_RGBE:
return "RGBExp";
}
return "";
}
const char* getHistrogramModeStr(QBitmapPreviewDialogImp::EHistogramMode mode, bool shortName)
{
switch (mode)
{
case QBitmapPreviewDialogImp::eHistogramMode_Luminosity:
return shortName ? "Lum" : "Luminosity";
case QBitmapPreviewDialogImp::eHistogramMode_OverlappedRGB:
return shortName ? "Overlap" : "Overlapped RGBA";
case QBitmapPreviewDialogImp::eHistogramMode_SplitRGB:
return shortName ? "R|G|B" : "Split RGB";
case QBitmapPreviewDialogImp::eHistogramMode_RedChannel:
return shortName ? "Red" : "Red Channel";
case QBitmapPreviewDialogImp::eHistogramMode_GreenChannel:
return shortName ? "Green" : "Green Channel";
case QBitmapPreviewDialogImp::eHistogramMode_BlueChannel:
return shortName ? "Blue" : "Blue Channel";
case QBitmapPreviewDialogImp::eHistogramMode_AlphaChannel:
return shortName ? "Alpha" : "Alpha Channel";
default:
break;
}
return "";
}
void QBitmapPreviewDialogImp::refreshData()
{
// Check if we have some usefull data loaded
if (m_image->GetWidth() * m_image->GetHeight() == 0)
{
return;
}
int w = m_image->GetWidth();
int h = m_image->GetHeight();
int multiplier = (m_showMode == ESHOW_RGB_ALPHA ? 2 : 1);
int originalW = w * multiplier;
int originalH = h;
if (!m_showOriginalSize || (w == 0))
{
w = kDefaultWidth;
}
if (!m_showOriginalSize || (h == 0))
{
h = kDefaultHeight;
}
w *= multiplier;
CImageEx scaledImage;
if (m_showOriginalSize && (originalW < w))
{
w = originalW;
}
if (m_showOriginalSize && (originalH < h))
{
h = originalH;
}
scaledImage.Allocate(w, h);
if (m_showMode == ESHOW_RGB_ALPHA)
{
GetIEditor()->GetImageUtil()->ScaleToDoubleFit(*m_image, scaledImage);
}
else
{
GetIEditor()->GetImageUtil()->ScaleToFit(*m_image, scaledImage);
}
if (m_showMode == ESHOW_RGB || m_showMode == ESHOW_RGBE)
{
scaledImage.FillAlpha();
}
else if (m_showMode == ESHOW_ALPHA)
{
for (int h2 = 0; h2 < scaledImage.GetHeight(); h2++)
{
for (int w2 = 0; w2 < scaledImage.GetWidth(); w2++)
{
int a = scaledImage.ValueAt(w2, h2) >> 24;
scaledImage.ValueAt(w2, h2) = RGB(a, a, a) | (a << 24);
}
}
}
else if (m_showMode == ESHOW_RGB_ALPHA)
{
int halfWidth = scaledImage.GetWidth() / 2;
for (int h2 = 0; h2 < scaledImage.GetHeight(); h2++)
{
for (int w2 = 0; w2 < halfWidth; w2++)
{
int r = GetRValue(scaledImage.ValueAt(w2, h2));
int g = GetGValue(scaledImage.ValueAt(w2, h2));
int b = GetBValue(scaledImage.ValueAt(w2, h2));
int a = scaledImage.ValueAt(w2, h2) >> 24;
scaledImage.ValueAt(w2, h2) = RGB(r, g, b) | (a << 24);
scaledImage.ValueAt(w2 + halfWidth, h2) = RGB(a, a, a) | (a << 24);
}
}
}
setImageRgba8888(scaledImage.GetData(), w, h, "");
setSize(QString().asprintf("%d x %d", m_image->GetWidth(), m_image->GetHeight()));
setMips(QString().asprintf("%d", m_image->GetNumberOfMipMaps()));
setFullSize(m_showOriginalSize);
// Compute histogram
m_histogram.ComputeHistogram((BYTE*)scaledImage.GetData(), w, h, CImageHistogram::eImageFormat_32BPP_RGBA);
}
void QBitmapPreviewDialogImp::paintEvent(QPaintEvent* e)
{
QBitmapPreviewDialog::paintEvent(e);
//if showing original size hide other information so it's easier to see
if (m_showOriginalSize)
{
return;
}
if (m_uiStyle == EUISTYLE_IMAGE_ONLY)
{
return;
}
QPainter p(this);
QPen pen;
QPainterPath path[4];
// Fill background color
QRect histogramRect = getHistogramArea();
p.fillRect(histogramRect, QColor(255, 255, 255));
// Draw borders
pen.setColor(QColor(0, 0, 0));
p.setPen(pen);
p.drawRect(histogramRect);
// Draw histogram
QVector<int> drawChannels;
switch (m_histrogramMode)
{
case eHistogramMode_Luminosity:
drawChannels.push_back(3);
break;
case eHistogramMode_SplitRGB:
drawChannels.push_back(0);
drawChannels.push_back(1);
drawChannels.push_back(2);
break;
case eHistogramMode_OverlappedRGB:
drawChannels.push_back(0);
drawChannels.push_back(1);
drawChannels.push_back(2);
break;
case eHistogramMode_RedChannel:
drawChannels.push_back(0);
break;
case eHistogramMode_GreenChannel:
drawChannels.push_back(1);
break;
case eHistogramMode_BlueChannel:
drawChannels.push_back(2);
break;
case eHistogramMode_AlphaChannel:
drawChannels.push_back(3);
break;
}
int graphWidth = qMax(histogramRect.width(), 1);
int graphHeight = qMax(histogramRect.height() - 2, 0);
int graphBottom = histogramRect.bottom() + 1;
int currX[4] = {0, 0, 0, 0};
int prevX[4] = {0, 0, 0, 0};
float scale = 0.0f;
static const int numSubGraphs = 3;
const int subGraph = qCeil(graphWidth / numSubGraphs);
// Fill background for Split RGB histogram
if (m_histrogramMode == eHistogramMode_SplitRGB)
{
const static QColor backgroundColor[numSubGraphs] =
{
QColor(255, 220, 220),
QColor(220, 255, 220),
QColor(220, 220, 255)
};
for (int i = 0; i < numSubGraphs; i++)
{
p.fillRect(histogramRect.left() + subGraph * i,
histogramRect.top(),
subGraph + (i == numSubGraphs - 1 ? 1 : 0),
histogramRect.height(), backgroundColor[i]);
}
}
int lastHeight[CImageHistogram::kNumChannels] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
for (int x = 0; x < graphWidth; ++x)
{
for (int j = 0; j < drawChannels.size(); j++)
{
const int c = drawChannels[j];
int& curr_x = currX[c];
int& prev_x = prevX[c];
int& last_height = lastHeight[c];
QPainterPath& curr_path = path[c];
curr_x = histogramRect.left() + x + 1;
int i = static_cast<int>(((float)x / (graphWidth - 1)) * (CImageHistogram::kNumColorLevels - 1));
if (m_histrogramMode == eHistogramMode_SplitRGB)
{
// Filter out to area which we are interested
const int k = x / subGraph;
if (k != c)
{
continue;
}
i = qCeil((i - (subGraph * c)) * numSubGraphs);
i = qMin(i, CImageHistogram::kNumColorLevels - 1);
i = qMax(i, 0);
}
if (m_histrogramMode == eHistogramMode_Luminosity)
{
scale = (float)m_histogram.m_lumCount[i] / m_histogram.m_maxLumCount;
}
else if (m_histogram.m_maxCount[c])
{
scale = (float)m_histogram.m_count[c][i] / m_histogram.m_maxCount[c];
}
int height = static_cast<int>(graphBottom - graphHeight * scale);
if (last_height == INT_MAX)
{
last_height = height;
}
curr_path.moveTo(prev_x, last_height);
curr_path.lineTo(curr_x, height);
last_height = height;
if (prev_x == INT_MAX)
{
prev_x = curr_x;
}
prev_x = curr_x;
}
}
static const QColor kChannelColor[4] =
{
QColor(255, 0, 0),
QColor(0, 255, 0),
QColor(0, 0, 255),
QColor(120, 120, 120)
};
for (int i = 0; i < drawChannels.size(); i++)
{
const int c = drawChannels[i];
pen.setColor(kChannelColor[c]);
p.setPen(pen);
p.drawPath(path[c]);
}
// Update histogram info
{
float mean = 0, stdDev = 0, median = 0;
switch (m_histrogramMode)
{
case eHistogramMode_Luminosity:
case eHistogramMode_SplitRGB:
case eHistogramMode_OverlappedRGB:
mean = m_histogram.m_meanAvg;
stdDev = m_histogram.m_stdDevAvg;
median = m_histogram.m_medianAvg;
break;
case eHistogramMode_RedChannel:
mean = m_histogram.m_mean[0];
stdDev = m_histogram.m_stdDev[0];
median = m_histogram.m_median[0];
break;
case eHistogramMode_GreenChannel:
mean = m_histogram.m_mean[1];
stdDev = m_histogram.m_stdDev[1];
median = m_histogram.m_median[1];
break;
case eHistogramMode_BlueChannel:
mean = m_histogram.m_mean[2];
stdDev = m_histogram.m_stdDev[2];
median = m_histogram.m_median[2];
break;
case eHistogramMode_AlphaChannel:
mean = m_histogram.m_mean[3];
stdDev = m_histogram.m_stdDev[3];
median = m_histogram.m_median[3];
break;
}
QString val;
val.setNum(mean);
setMean(val);
val.setNum(stdDev);
setStdDev(val);
val.setNum(median);
setMedian(val);
}
}
#include <Controls/moc_QBitmapPreviewDialogImp.cpp>

@ -1,89 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef QBITMAPPREVIEWDIALOG_IMP_H
#define QBITMAPPREVIEWDIALOG_IMP_H
#if !defined(Q_MOC_RUN)
#include "QBitmapPreviewDialog.h"
#include <Util/ImageHistogram.h>
#endif
class CImageEx;
class QBitmapPreviewDialogImp
: public QBitmapPreviewDialog
{
Q_OBJECT;
public:
enum EUIStyle
{
EUISTYLE_IMAGE_ONLY,
EUISTYLE_IMAGE_HISTOGRAM,
EUISTYLE_NumModes
};
enum EShowMode
{
ESHOW_RGB = 0,
ESHOW_ALPHA,
ESHOW_RGBA,
ESHOW_RGB_ALPHA,
ESHOW_RGBE,
ESHOW_NumModes,
};
enum EHistogramMode
{
eHistogramMode_Luminosity,
eHistogramMode_OverlappedRGB,
eHistogramMode_SplitRGB,
eHistogramMode_RedChannel,
eHistogramMode_GreenChannel,
eHistogramMode_BlueChannel,
eHistogramMode_AlphaChannel,
eHistogramMode_NumModes,
};
explicit QBitmapPreviewDialogImp(QWidget* parent = 0);
virtual ~QBitmapPreviewDialogImp();
void setImage(const QString path);
void setShowMode(EShowMode mode);
void toggleShowMode();
void setUIStyleMode(EUIStyle mode);
const EShowMode& getShowMode() const;
void setHistogramMode(EHistogramMode mode);
void toggleHistrogramMode();
const EHistogramMode& getHistogramMode() const;
void setOriginalSize(bool value);
void toggleOriginalSize();
bool isSizeSmallerThanDefault();
void paintEvent(QPaintEvent* e) override;
protected:
void refreshData();
private:
const char* GetShowModeDescription(EShowMode eShowMode, bool bShowInOriginalSize) const;
private:
CImageEx* m_image;
QString m_path;
CImageHistogram m_histogram;
bool m_showOriginalSize;
EShowMode m_showMode;
EHistogramMode m_histrogramMode;
EUIStyle m_uiStyle;
};
#endif // QBITMAPPREVIEWDIALOG_IMP_H

@ -1,642 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include <Controls/QToolTipWidget.h>
#include "QBitmapPreviewDialogImp.h"
#include "qcoreapplication.h"
#include "qguiapplication.h"
#include "qapplication.h"
#include <QDesktopWidget>
#include <QPainter>
#include <QtGlobal>
#include <qgraphicseffect.h>
void QToolTipWidget::RebuildLayout()
{
if (m_title != nullptr)
{
m_title->hide();
}
if (m_content != nullptr)
{
m_content->hide();
}
if (m_specialContent != nullptr)
{
m_specialContent->hide();
}
//empty layout
while (m_layout->count() > 0)
{
m_layout->takeAt(0);
}
qDeleteAll(m_currentShortcuts);
m_currentShortcuts.clear();
if (m_includeTextureShortcuts)
{
m_currentShortcuts.append(new QLabel(tr("Alt - Alpha"), this));
m_currentShortcuts.back()->setProperty("tooltipLabel", "Shortcut");
m_currentShortcuts.append(new QLabel(tr("Shift - RGBA"), this));
m_currentShortcuts.back()->setProperty("tooltipLabel", "Shortcut");
}
if (m_title != nullptr && !m_title->text().isEmpty())
{
m_layout->addWidget(m_title);
m_title->show();
}
for (QLabel* var : m_currentShortcuts)
{
if (var != nullptr)
{
m_layout->addWidget(var);
var->show();
}
}
if (m_specialContent != nullptr)
{
m_layout->addWidget(m_specialContent);
m_specialContent->show();
}
if (m_content != nullptr && !m_content->text().isEmpty())
{
m_layout->addWidget(m_content);
m_content->show();
}
m_background->adjustSize();
adjustSize();
}
void QToolTipWidget::Hide()
{
m_currentShortcuts.clear();
hide();
}
void QToolTipWidget::Show(QPoint pos, ArrowDirection dir)
{
if (!IsValid())
{
return;
}
m_arrow->m_direction = dir;
pos = AdjustTipPosByArrowSize(pos, dir);
m_normalPos = pos;
move(pos);
RebuildLayout();
show();
m_arrow->show();
}
void QToolTipWidget::Display(QRect targetRect, ArrowDirection preferredArrowDir)
{
if (!IsValid())
{
return;
}
KeepTipOnScreen(targetRect, preferredArrowDir);
RebuildLayout();
show();
m_arrow->show();
}
void QToolTipWidget::TryDisplay(QPoint mousePos, const QRect& rect, [[maybe_unused]] ArrowDirection preferredArrowDir)
{
if (rect.contains(mousePos))
{
Display(rect, QToolTipWidget::ArrowDirection::ARROW_RIGHT);
}
else
{
hide();
}
}
void QToolTipWidget::TryDisplay(QPoint mousePos, const QWidget* widget, ArrowDirection preferredArrowDir)
{
const QRect rect(widget->mapToGlobal(QPoint(0,0)), widget->size());
TryDisplay(mousePos, rect, preferredArrowDir);
}
void QToolTipWidget::SetTitle(QString title)
{
if (!title.isEmpty())
{
m_title->setText(title);
}
m_title->setProperty("tooltipLabel", "Title");
setWindowTitle("ToolTip - " + title);
}
void QToolTipWidget::SetContent(QString content)
{
m_content->setWordWrap(true);
m_content->setProperty("tooltipLabel", "Content");
//line-height is not supported via stylesheet so we use the html rich-text subset in QT for it.
m_content->setText(QString("<span style=\"line-height: 14px;\">%1</span>").arg(content));
}
void QToolTipWidget::AppendContent(QString content)
{
m_content->setText(m_content->text() + "\n\n" + content);
update();
RebuildLayout();
m_content->update();
m_content->repaint();
}
QToolTipWidget::QToolTipWidget(QWidget* parent)
: QWidget(parent)
{
m_background = new QWidget(this);
m_background->setProperty("tooltip", "Background");
m_background->stackUnder(this);
m_title = new QLabel(this);
m_currentShortcuts = QVector<QLabel*>();
m_content = new QLabel(this);
m_specialContent = nullptr;
setWindowTitle("ToolTip");
setObjectName("ToolTip");
m_layout = new QVBoxLayout(this);
m_normalPos = QPoint(0, 0);
m_arrow = new QArrow(m_background);
setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);
m_arrow->setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);
m_arrow->setAttribute(Qt::WA_TranslucentBackground, true);
m_background->setLayout(m_layout);
m_arrow->setObjectName("ToolTipArrow");
m_background->setObjectName("ToolTipBackground");
//we need a drop shadow for the background
QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect(this);
dropShadow->setBlurRadius(m_shadowRadius);
dropShadow->setColor(Qt::black);
dropShadow->setOffset(0);
dropShadow->setEnabled(true);
m_background->setGraphicsEffect(dropShadow);
//we need a second drop shadow effect for the arrow
dropShadow = new QGraphicsDropShadowEffect(m_arrow);
dropShadow->setBlurRadius(m_shadowRadius);
dropShadow->setColor(Qt::black);
dropShadow->setOffset(0);
dropShadow->setEnabled(true);
m_arrow->setGraphicsEffect(dropShadow);
}
QToolTipWidget::~QToolTipWidget()
{
}
void QToolTipWidget::AddSpecialContent(QString type, QString dataStream)
{
if (type.isEmpty())
{
m_includeTextureShortcuts = false;
if (m_specialContent != nullptr)
{
delete m_specialContent;
m_specialContent = nullptr;
}
return;
}
if (type == "TEXTURE")
{
if (m_specialContent == nullptr)
{
QCoreApplication::instance()->installEventFilter(this); //grab the event filter while displaying the advanced texture tooltip
m_specialContent = new QBitmapPreviewDialogImp(this);
}
QString path(dataStream);
qobject_cast<QBitmapPreviewDialogImp*>(m_specialContent)->setImage(path);
// set default showmode to RGB
qobject_cast<QBitmapPreviewDialogImp*>(m_specialContent)->setShowMode(QBitmapPreviewDialogImp::EShowMode::ESHOW_RGB);
QString dir = (path.split("/").count() > path.split("\\").count()) ? path.split("/").back() : path.split("\\").back();
SetTitle(dir);
//always use default size but not image size
qobject_cast<QBitmapPreviewDialogImp*>(m_specialContent)->setOriginalSize(false);
m_includeTextureShortcuts = true;
}
else if (type == "ADD TO CONTENT")
{
AppendContent(dataStream);
m_includeTextureShortcuts = false;
if (m_specialContent != nullptr)
{
delete m_specialContent;
m_specialContent = nullptr;
}
}
else if (type == "REPLACE TITLE")
{
SetTitle(dataStream);
m_includeTextureShortcuts = false;
if (m_specialContent != nullptr)
{
delete m_specialContent;
m_specialContent = nullptr;
}
}
else if (type == "REPLACE CONTENT")
{
SetContent(dataStream);
m_includeTextureShortcuts = false;
if (m_specialContent != nullptr)
{
delete m_specialContent;
m_specialContent = nullptr;
}
}
else
{
m_includeTextureShortcuts = false;
if (m_specialContent != nullptr)
{
delete m_specialContent;
m_specialContent = nullptr;
}
return;
}
m_special = type;
}
bool QToolTipWidget::eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::KeyPress)
{
if (m_special == "TEXTURE" && m_specialContent != nullptr)
{
const QKeyEvent* ke = static_cast<QKeyEvent*>(event);
Qt::KeyboardModifiers mods = ke->modifiers();
if (mods & Qt::KeyboardModifier::AltModifier)
{
((QBitmapPreviewDialogImp*)m_specialContent)->setShowMode(QBitmapPreviewDialogImp::ESHOW_ALPHA);
}
else if (mods & Qt::KeyboardModifier::ShiftModifier && !(mods & Qt::KeyboardModifier::ControlModifier))
{
((QBitmapPreviewDialogImp*)m_specialContent)->setShowMode(QBitmapPreviewDialogImp::ESHOW_RGBA);
}
}
}
if (event->type() == QEvent::KeyRelease)
{
if (m_special == "TEXTURE" && m_specialContent != nullptr)
{
const QKeyEvent* ke = static_cast<QKeyEvent*>(event);
Qt::KeyboardModifiers mods = ke->modifiers();
if (!(mods& Qt::KeyboardModifier::AltModifier) && !(mods & Qt::KeyboardModifier::ShiftModifier))
{
((QBitmapPreviewDialogImp*)m_specialContent)->setShowMode(QBitmapPreviewDialogImp::ESHOW_RGB);
}
}
}
return QWidget::eventFilter(obj, event);
}
void QToolTipWidget::hideEvent(QHideEvent* event)
{
QWidget::hideEvent(event);
m_arrow->hide();
}
void QToolTipWidget::UpdateOptionalData(QString optionalData)
{
AddSpecialContent(m_special, optionalData);
}
QPoint QToolTipWidget::AdjustTipPosByArrowSize(QPoint pos, ArrowDirection dir)
{
switch (dir)
{
case QToolTipWidget::ArrowDirection::ARROW_UP:
{
m_arrow->move(pos);
pos.setY(pos.y() + 10);
m_arrow->setFixedSize(20, 10);
pos -= QPoint(m_shadowRadius, m_shadowRadius);
break;
}
case QToolTipWidget::ArrowDirection::ARROW_LEFT:
{
m_arrow->move(pos);
pos.setX(pos.x() + 10);
m_arrow->setFixedSize(10, 20);
pos -= QPoint(m_shadowRadius, m_shadowRadius);
break;
}
case QToolTipWidget::ArrowDirection::ARROW_RIGHT:
{
pos.setX(pos.x() - 10);
m_arrow->move(QPoint(pos.x() + width(), pos.y()));
m_arrow->setFixedSize(10, 20);
pos -= QPoint(-m_shadowRadius, m_shadowRadius);
break;
}
case QToolTipWidget::ArrowDirection::ARROW_DOWN:
{
pos.setY(pos.y() - 10);
m_arrow->move(QPoint(pos.x(), pos.y() + height()));
m_arrow->setFixedSize(20, 10);
pos -= QPoint(m_shadowRadius, -m_shadowRadius);
break;
}
default:
m_arrow->move(-10, -10);
break;
}
return pos;
}
bool QToolTipWidget::IsValid()
{
if (m_title->text().isEmpty() ||
(m_content->text().isEmpty() && m_specialContent == nullptr))
{
return false;
}
return true;
}
void QToolTipWidget::KeepTipOnScreen(QRect targetRect, ArrowDirection preferredArrowDir)
{
QRect desktop = QApplication::desktop()->availableGeometry(this);
if (this->isHidden())
{
setAttribute(Qt::WA_DontShowOnScreen, true);
Show(QPoint(0, 0), preferredArrowDir);
hide();
setAttribute(Qt::WA_DontShowOnScreen, false);
}
//else assume the size is right
//calculate initial rect
QRect tipRect = QRect(0, 0, 0, 0);
switch (preferredArrowDir)
{
case QToolTipWidget::ArrowDirection::ARROW_UP:
{
//tip is below the widget with a left alignment
tipRect.setTopLeft(AdjustTipPosByArrowSize(targetRect.bottomLeft(), preferredArrowDir));
break;
}
case QToolTipWidget::ArrowDirection::ARROW_LEFT:
{
//tip is on the right with the top being even
tipRect.setTopLeft(AdjustTipPosByArrowSize(targetRect.topRight(), preferredArrowDir));
break;
}
case QToolTipWidget::ArrowDirection::ARROW_RIGHT:
{
//tip is on the left with the top being even
tipRect.setY(targetRect.top());
tipRect.setX(targetRect.left() - width());
tipRect.setTopLeft(AdjustTipPosByArrowSize(tipRect.topLeft(), preferredArrowDir));
break;
}
case QToolTipWidget::ArrowDirection::ARROW_DOWN:
{
//tip is above the widget with a left alignment
tipRect.setX(targetRect.left());
tipRect.setY(targetRect.top() - height());
tipRect.setTopLeft(AdjustTipPosByArrowSize(tipRect.topLeft(), preferredArrowDir));
break;
}
default:
{
//tip is on the right with the top being even
preferredArrowDir = QToolTipWidget::ArrowDirection::ARROW_LEFT;
tipRect.setTopLeft(AdjustTipPosByArrowSize(targetRect.topRight(), QToolTipWidget::ArrowDirection::ARROW_LEFT));
break;
}
}
tipRect.setSize(size());
//FixPositioning
if (preferredArrowDir == ArrowDirection::ARROW_LEFT || preferredArrowDir == ArrowDirection::ARROW_RIGHT)
{
if (tipRect.left() <= desktop.left())
{
m_arrow->m_direction = ArrowDirection::ARROW_LEFT;
tipRect.setTopLeft(AdjustTipPosByArrowSize(targetRect.topRight(), m_arrow->m_direction));
}
else if (tipRect.right() >= desktop.right())
{
m_arrow->m_direction = ArrowDirection::ARROW_RIGHT;
tipRect.setLeft(targetRect.left() - width());
tipRect.setTopLeft(AdjustTipPosByArrowSize(tipRect.topLeft(), m_arrow->m_direction));
}
}
else if (preferredArrowDir == ArrowDirection::ARROW_UP || preferredArrowDir == ArrowDirection::ARROW_DOWN)
{
if (tipRect.top() <= desktop.top())
{
m_arrow->m_direction = ArrowDirection::ARROW_UP;
tipRect.setTopLeft(AdjustTipPosByArrowSize(targetRect.bottomLeft(), m_arrow->m_direction));
}
else if (tipRect.bottom() >= desktop.bottom())
{
m_arrow->m_direction = ArrowDirection::ARROW_DOWN;
tipRect.setY(targetRect.top() - height());
tipRect.setTopLeft(AdjustTipPosByArrowSize(tipRect.topLeft(), m_arrow->m_direction));
}
}
//Nudge tip without arrow
if (preferredArrowDir == ArrowDirection::ARROW_UP || preferredArrowDir == ArrowDirection::ARROW_DOWN)
{
if (tipRect.left() <= desktop.left())
{
tipRect.setLeft(desktop.left());
}
else if (tipRect.right() >= desktop.right())
{
tipRect.setLeft(desktop.right() - width());
}
}
else if (preferredArrowDir == ArrowDirection::ARROW_RIGHT || preferredArrowDir == ArrowDirection::ARROW_LEFT)
{
if (tipRect.top() <= desktop.top())
{
tipRect.setTop(desktop.top());
}
else if (tipRect.bottom() >= desktop.bottom())
{
tipRect.setTop(desktop.bottom() - height());
}
}
m_normalPos = tipRect.topLeft();
move(m_normalPos);
}
QPolygonF QToolTipWidget::QArrow::CreateArrow()
{
QVector<QPointF> vertex;
//3 points in triangle
vertex.reserve(3);
//all magic number below are given in order to draw smooth transitions between tooltip and arrow
if (m_direction == ArrowDirection::ARROW_UP)
{
vertex.push_back(QPointF(10, 1));
vertex.push_back(QPointF(19, 10));
vertex.push_back(QPointF(0, 10));
}
else if (m_direction == ArrowDirection::ARROW_RIGHT)
{
vertex.push_back(QPointF(9, 10));
vertex.push_back(QPointF(0, 19));
vertex.push_back(QPointF(0, 1));
}
else if (m_direction == ArrowDirection::ARROW_LEFT)
{
vertex.push_back(QPointF(1, 10));
vertex.push_back(QPointF(10, 19));
vertex.push_back(QPointF(10, 0));
}
else //ArrowDirection::ARROW_DOWN
{
vertex.push_back(QPointF(10, 10));
vertex.push_back(QPointF(19, 0));
vertex.push_back(QPointF(0, 0));
}
return QPolygonF(vertex);
}
void QToolTipWidget::QArrow::paintEvent([[maybe_unused]] QPaintEvent* event)
{
QColor color(255, 255, 255, 255);
QPainter painter(this);
painter.fillRect(rect(), Qt::transparent); //force transparency
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setBrush(color);
painter.setPen(Qt::NoPen);
painter.drawPolygon(CreateArrow());
//painter.setRenderHint(QPainter::Antialiasing, false);
}
QToolTipWrapper::QToolTipWrapper(QWidget* parent)
: QObject(parent)
{
}
void QToolTipWrapper::SetTitle(QString title)
{
m_title = title;
}
void QToolTipWrapper::SetContent(QString content)
{
AddSpecialContent("REPLACE CONTENT", content);
}
void QToolTipWrapper::AppendContent(QString content)
{
AddSpecialContent("ADD TO CONTENT", content);
}
void QToolTipWrapper::AddSpecialContent(QString type, QString dataStream)
{
if (type == "REPLACE CONTENT")
{
m_contentOperations.clear();
}
m_contentOperations.push_back({type, dataStream});
}
void QToolTipWrapper::UpdateOptionalData(QString optionalData)
{
m_contentOperations.push_back({"UPDATE OPTIONAL", optionalData});
}
void QToolTipWrapper::Display(QRect targetRect, QToolTipWidget::ArrowDirection preferredArrowDir)
{
GetOrCreateToolTip()->Display(targetRect, preferredArrowDir);
}
void QToolTipWrapper::TryDisplay(QPoint mousePos, const QWidget * widget, QToolTipWidget::ArrowDirection preferredArrowDir)
{
GetOrCreateToolTip()->TryDisplay(mousePos, widget, preferredArrowDir);
}
void QToolTipWrapper::TryDisplay(QPoint mousePos, const QRect & widget, QToolTipWidget::ArrowDirection preferredArrowDir)
{
GetOrCreateToolTip()->TryDisplay(mousePos, widget, preferredArrowDir);
}
void QToolTipWrapper::hide()
{
DestroyToolTip();
}
void QToolTipWrapper::show()
{
GetOrCreateToolTip()->show();
}
bool QToolTipWrapper::isVisible() const
{
return m_actualTooltip && m_actualTooltip->isVisible();
}
void QToolTipWrapper::update()
{
if (m_actualTooltip)
{
m_actualTooltip->update();
}
}
void QToolTipWrapper::ReplayContentOperations(QToolTipWidget* tooltipWidget)
{
tooltipWidget->SetTitle(m_title);
for (const auto& operation : m_contentOperations)
{
if (operation.first == "UPDATE OPTIONAL")
{
tooltipWidget->UpdateOptionalData(operation.second);
}
else
{
tooltipWidget->AddSpecialContent(operation.first, operation.second);
}
}
}
QToolTipWidget * QToolTipWrapper::GetOrCreateToolTip()
{
if (!m_actualTooltip)
{
QToolTipWidget* tooltipWidget = new QToolTipWidget(static_cast<QWidget*>(parent()));
tooltipWidget->setAttribute(Qt::WA_DeleteOnClose);
ReplayContentOperations(tooltipWidget);
m_actualTooltip = tooltipWidget;
}
return m_actualTooltip.data();
}
void QToolTipWrapper::DestroyToolTip()
{
if (m_actualTooltip)
{
m_actualTooltip->deleteLater();
}
}

@ -1,148 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef QToolTipWidget_h__
#define QToolTipWidget_h__
#include "EditorCoreAPI.h"
#include <QPointer>
#include <QWidget>
#include <QLabel>
#include <QString>
#include <QMap>
#include <QMapIterator>
#include <QVector>
#include <QVBoxLayout>
#include <memory>
class IQToolTip
{
public:
virtual void SetTitle(QString title) = 0;
virtual void SetContent(QString content) = 0;
virtual void AppendContent(QString content) = 0;
virtual void AddSpecialContent(QString type, QString dataStream) = 0;
virtual void UpdateOptionalData(QString optionalData) = 0;
};
class EDITOR_CORE_API QToolTipWidget
: public QWidget
, public IQToolTip
{
public:
enum class ArrowDirection
{
ARROW_UP,
ARROW_LEFT,
ARROW_RIGHT,
ARROW_DOWN
};
class QArrow
: public QWidget
{
public:
ArrowDirection m_direction;
QPoint m_pos;
QArrow(QWidget* parent)
: QWidget(parent){ setWindowFlags(Qt::ToolTip); }
virtual ~QArrow(){}
QPolygonF CreateArrow();
virtual void paintEvent(QPaintEvent*) override;
};
QToolTipWidget(QWidget* parent);
~QToolTipWidget();
void SetTitle(QString title) override;
void SetContent(QString content) override;
void AppendContent(QString content) override;
void AddSpecialContent(QString type, QString dataStream) override;
void UpdateOptionalData(QString optionalData) override;
void Display(QRect targetRect, ArrowDirection preferredArrowDir);
//! Displays the tooltip on the given widget, only if the mouse is over it.
void TryDisplay(QPoint mousePos, const QWidget* widget, ArrowDirection preferredArrowDir);
//! Displays the tooltip on the given rect, only if the mouse is over it.
void TryDisplay(QPoint mousePos, const QRect& widget, ArrowDirection preferredArrowDir);
void Hide();
protected:
void Show(QPoint pos, ArrowDirection dir);
bool IsValid();
void KeepTipOnScreen(QRect targetRect, ArrowDirection preferredArrowDir);
QPoint AdjustTipPosByArrowSize(QPoint pos, ArrowDirection dir);
virtual bool eventFilter(QObject* obj, QEvent* event) override;
void RebuildLayout();
virtual void hideEvent(QHideEvent*) override;
QLabel* m_title;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QVector<QLabel*> m_currentShortcuts;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
//can be anything from QLabel to QBitMapPreviewDialog
//must allow movement, and show/hide calls
QLabel* m_content;
QWidget* m_specialContent;
QWidget* m_background;
QVBoxLayout* m_layout;
QString m_special;
QPoint m_normalPos;
QArrow* m_arrow;
const int m_shadowRadius = 5;
bool m_includeTextureShortcuts; //added since Qt does not support modifier only shortcuts
};
// HACK: The EditorUI_QT classes all were keeping persistent references to QToolTipWidgets around
// This led to many, many top-level widget creations, which led to many platform-side window allocations
// which led to crashes in Qt5.15. As this is legacy code, this is a drop-in replacement that only
// allocates the actual QToolTipWidget (and thus platform window) while the tooltip is visible
class EDITOR_CORE_API QToolTipWrapper
: public QObject
, public IQToolTip
{
public:
QToolTipWrapper(QWidget* parent);
void SetTitle(QString title) override;
void SetContent(QString content) override;
void AppendContent(QString content) override;
void AddSpecialContent(QString type, QString dataStream) override;
void UpdateOptionalData(QString optionalData) override;
void Display(QRect targetRect, QToolTipWidget::ArrowDirection preferredArrowDir);
void TryDisplay(QPoint mousePos, const QWidget* widget, QToolTipWidget::ArrowDirection preferredArrowDir);
void TryDisplay(QPoint mousePos, const QRect& widget, QToolTipWidget::ArrowDirection preferredArrowDir);
void hide();
void show();
bool isVisible() const;
void update();
void repaint(){update();} //Things really shouldn't be calling repaint on these...
void Hide(){hide();}
void close(){hide();}
private:
void ReplayContentOperations(QToolTipWidget* tooltipWidget);
QToolTipWidget* GetOrCreateToolTip();
void DestroyToolTip();
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // conditional expression is constant, needs to have dll-interface to be used by clients of class 'AzQtComponents::FilteredSearchWidget'
QPointer<QToolTipWidget> m_actualTooltip;
AZ_POP_DISABLE_WARNING
QString m_title;
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // conditional expression is constant, needs to have dll-interface to be used by clients of class 'AzQtComponents::FilteredSearchWidget'
QVector<QPair<QString, QString>> m_contentOperations;
AZ_POP_DISABLE_WARNING
};
#endif // QToolTipWidget_h__

@ -10,7 +10,6 @@
// Editor
#include "PropertyCtrl.h"
#include "PropertyResourceCtrl.h"
#include "PropertyGenericCtrl.h"
#include "PropertyMiscCtrl.h"
#include "PropertyMotionCtrl.h"
@ -21,7 +20,6 @@ void RegisterReflectedVarHandlers()
if (!registered)
{
registered = true;
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew FileResourceSelectorWidgetHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequencePropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequenceIdPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew LocalStringPropertyHandler());

@ -1,383 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "PropertyResourceCtrl.h"
// Qt
#include <QHBoxLayout>
#include <QLineEdit>
// AzToolsFramework
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.h>
// Editor
#include "Controls/QToolTipWidget.h"
#include "Controls/BitmapToolTip.h"
BrowseButton::BrowseButton(PropertyType type, QWidget* parent /*= nullptr*/)
: QToolButton(parent)
, m_propertyType(type)
{
setAutoRaise(true);
setIcon(QIcon(QStringLiteral(":/stylesheet/img/UI20/browse-edit.svg")));
connect(this, &QAbstractButton::clicked, this, &BrowseButton::OnClicked);
}
void BrowseButton::SetPathAndEmit(const QString& path)
{
//only emit if path changes. Old property control
if (path != m_path)
{
m_path = path;
emit PathChanged(m_path);
}
}
class FileBrowseButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(FileBrowseButton, AZ::SystemAllocator, 0);
FileBrowseButton(PropertyType type, QWidget* pParent = nullptr)
: BrowseButton(type, pParent)
{
setToolTip("Browse...");
}
private:
void OnClicked() override
{
QString tempValue("");
if (!m_path.isEmpty() && !Path::GetExt(m_path).isEmpty())
{
tempValue = m_path;
}
AssetSelectionModel selection;
if (m_propertyType == ePropertyTexture)
{
// Filters for texture.
selection = AssetSelectionModel::AssetGroupSelection("Texture");
}
else
{
return;
}
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (selection.IsValid())
{
QString newPath = Path::FullPathToGamePath(selection.GetResult()->GetFullPath().c_str()).c_str();
switch (m_propertyType)
{
case ePropertyTexture:
newPath.replace("\\\\", "/");
if (newPath.size() > MAX_PATH)
{
newPath.resize(MAX_PATH);
}
}
SetPathAndEmit(newPath);
}
}
};
class AudioControlSelectorButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(AudioControlSelectorButton, AZ::SystemAllocator, 0);
AudioControlSelectorButton(PropertyType type, QWidget* pParent = nullptr)
: BrowseButton(type, pParent)
{
setToolTip(tr("Select Audio Control"));
}
private:
void OnClicked() override
{
AZStd::string resourceResult;
auto ConvertLegacyAudioPropertyType = [](const PropertyType type) -> AzToolsFramework::AudioPropertyType
{
switch (type)
{
case ePropertyAudioTrigger:
return AzToolsFramework::AudioPropertyType::Trigger;
case ePropertyAudioRTPC:
return AzToolsFramework::AudioPropertyType::Rtpc;
case ePropertyAudioSwitch:
return AzToolsFramework::AudioPropertyType::Switch;
case ePropertyAudioSwitchState:
return AzToolsFramework::AudioPropertyType::SwitchState;
case ePropertyAudioEnvironment:
return AzToolsFramework::AudioPropertyType::Environment;
case ePropertyAudioPreloadRequest:
return AzToolsFramework::AudioPropertyType::Preload;
default:
return AzToolsFramework::AudioPropertyType::NumTypes;
}
};
auto propType = ConvertLegacyAudioPropertyType(m_propertyType);
if (propType != AzToolsFramework::AudioPropertyType::NumTypes)
{
AzToolsFramework::AudioControlSelectorRequestBus::EventResult(
resourceResult, propType, &AzToolsFramework::AudioControlSelectorRequestBus::Events::SelectResource,
AZStd::string_view{ m_path.toUtf8().constData() });
SetPathAndEmit(QString{ resourceResult.c_str() });
}
}
};
class TextureEditButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(TextureEditButton, AZ::SystemAllocator, 0);
TextureEditButton(QWidget* pParent = nullptr)
: BrowseButton(ePropertyTexture, pParent)
{
setIcon(QIcon(QStringLiteral(":/stylesheet/img/UI20/open-in-internal-app.svg")));
setToolTip(tr("Launch default editor"));
}
private:
void OnClicked() override
{
CFileUtil::EditTextureFile(m_path.toUtf8().data(), true);
}
};
FileResourceSelectorWidget::FileResourceSelectorWidget(QWidget* pParent /*= nullptr*/)
: QWidget(pParent)
, m_propertyType(ePropertyInvalid)
, m_tooltip(nullptr)
{
m_pathEdit = new QLineEdit;
m_mainLayout = new QHBoxLayout(this);
m_mainLayout->addWidget(m_pathEdit, 1);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
// KDAB just ported the MFC texture preview tooltip, but looks like Amazon added their own. Not sure which to use.
// To switch to Amazon QToolTipWidget, remove FileResourceSelectorWidget::event and m_previewTooltip
#ifdef USE_QTOOLTIPWIDGET
m_tooltip = new QToolTipWidget(this);
installEventFilter(this);
#endif
connect(m_pathEdit, &QLineEdit::editingFinished, this, [this]() { OnPathChanged(m_pathEdit->text()); });
}
bool FileResourceSelectorWidget::eventFilter([[maybe_unused]] QObject* obj, QEvent* event)
{
if (m_propertyType == ePropertyTexture)
{
if (event->type() == QEvent::ToolTip)
{
QHelpEvent* e = (QHelpEvent*)event;
m_tooltip->AddSpecialContent("TEXTURE", m_path);
m_tooltip->TryDisplay(e->globalPos(), m_pathEdit, QToolTipWidget::ArrowDirection::ARROW_RIGHT);
return true;
}
if (event->type() == QEvent::Leave)
{
m_tooltip->hide();
}
}
return false;
}
void FileResourceSelectorWidget::SetPropertyType(PropertyType type)
{
if (m_propertyType == type)
{
return;
}
//if the property type changed for some reason, delete all the existing widgets
if (!m_buttons.isEmpty())
{
qDeleteAll(m_buttons.begin(), m_buttons.end());
m_buttons.clear();
}
m_previewToolTip.reset();
m_propertyType = type;
switch (type)
{
case ePropertyTexture:
AddButton(new FileBrowseButton(type));
AddButton(new TextureEditButton);
m_previewToolTip.reset(new CBitmapToolTip);
break;
case ePropertyAudioTrigger:
case ePropertyAudioSwitch:
case ePropertyAudioSwitchState:
case ePropertyAudioRTPC:
case ePropertyAudioEnvironment:
case ePropertyAudioPreloadRequest:
AddButton(new AudioControlSelectorButton(type));
break;
default:
break;
}
m_mainLayout->invalidate();
}
void FileResourceSelectorWidget::AddButton(BrowseButton* button)
{
m_mainLayout->addWidget(button);
m_buttons.push_back(button);
connect(button, &BrowseButton::PathChanged, this, &FileResourceSelectorWidget::OnPathChanged);
}
void FileResourceSelectorWidget::OnPathChanged(const QString& path)
{
bool changed = SetPath(path);
if (changed)
{
emit PathChanged(m_path);
}
}
bool FileResourceSelectorWidget::SetPath(const QString& path)
{
bool changed = false;
const QString newPath = path.toLower();
if (m_path != newPath)
{
m_path = newPath;
UpdateWidgets();
changed = true;
}
return changed;
}
void FileResourceSelectorWidget::UpdateWidgets()
{
m_pathEdit->setText(m_path);
foreach(BrowseButton * button, m_buttons)
{
button->SetPath(m_path);
}
if (m_previewToolTip)
{
m_previewToolTip->SetTool(this, rect());
}
}
QString FileResourceSelectorWidget::GetPath() const
{
return m_path;
}
QWidget* FileResourceSelectorWidget::GetLastInTabOrder()
{
return m_buttons.empty() ? nullptr : m_buttons.last();
}
QWidget* FileResourceSelectorWidget::GetFirstInTabOrder()
{
return m_buttons.empty() ? nullptr : m_buttons.first();
}
void FileResourceSelectorWidget::UpdateTabOrder()
{
if (m_buttons.count() >= 2)
{
for (int i = 0; i < m_buttons.count() - 1; ++i)
{
setTabOrder(m_buttons[i], m_buttons[i + 1]);
}
}
}
bool FileResourceSelectorWidget::event(QEvent* event)
{
if (event->type() == QEvent::ToolTip && m_previewToolTip && !m_previewToolTip->isVisible())
{
if (!m_path.isEmpty())
{
m_previewToolTip->LoadImage(m_path);
m_previewToolTip->setVisible(true);
}
event->accept();
return true;
}
if (event->type() == QEvent::Resize && m_previewToolTip)
{
m_previewToolTip->SetTool(this, rect());
}
return QWidget::event(event);
}
QWidget* FileResourceSelectorWidgetHandler::CreateGUI(QWidget* pParent)
{
FileResourceSelectorWidget* newCtrl = aznew FileResourceSelectorWidget(pParent);
connect(newCtrl, &FileResourceSelectorWidget::PathChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
return newCtrl;
}
void FileResourceSelectorWidgetHandler::ConsumeAttribute(FileResourceSelectorWidget* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
Q_UNUSED(GUI);
Q_UNUSED(attrib);
Q_UNUSED(attrValue);
Q_UNUSED(debugName);
}
void FileResourceSelectorWidgetHandler::WriteGUIValuesIntoProperty(size_t index, FileResourceSelectorWidget* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarResource val = instance;
val.m_propertyType = GUI->GetPropertyType();
val.m_path = GUI->GetPath().toUtf8().data();
instance = static_cast<property_t>(val);
}
bool FileResourceSelectorWidgetHandler::ReadValuesIntoGUI(size_t index, FileResourceSelectorWidget* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarResource val = instance;
GUI->SetPropertyType(val.m_propertyType);
GUI->SetPath(val.m_path.c_str());
return false;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyResourceCtrl.cpp>

@ -1,118 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYRESOURCECTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYRESOURCECTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include "ReflectedVar.h"
#include "Util/VariablePropertyType.h"
#include <QWidget>
#include <QtWidgets/QToolButton>
#include <QtCore/QVector>
#endif
class QLineEdit;
class QHBoxLayout;
class CBitmapToolTip;
class QToolTipWidget;
class BrowseButton
: public QToolButton
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(BrowseButton, AZ::SystemAllocator, 0);
BrowseButton(PropertyType type, QWidget* parent = nullptr);
void SetPath(const QString& path) { m_path = path; }
QString GetPath() const { return m_path; }
PropertyType GetPropertyType() const {return m_propertyType; }
signals:
void PathChanged(const QString& path);
protected:
void SetPathAndEmit(const QString& path);
virtual void OnClicked() = 0;
PropertyType m_propertyType;
QString m_path;
};
class FileResourceSelectorWidget
: public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(FileResourceSelectorWidget, AZ::SystemAllocator, 0);
FileResourceSelectorWidget(QWidget* pParent = nullptr);
bool SetPath(const QString& path);
QString GetPath() const;
void SetPropertyType(PropertyType type);
PropertyType GetPropertyType() const { return m_propertyType; }
QWidget* GetFirstInTabOrder();
QWidget* GetLastInTabOrder();
void UpdateTabOrder();
bool eventFilter(QObject* obj, QEvent* event) override;
signals:
void PathChanged(const QString& path);
protected:
bool event(QEvent* event) override;
private:
void OnAssignClicked();
void OnMaterialClicked();
void UpdateWidgets();
void AddButton(BrowseButton* button);
void OnPathChanged(const QString& path);
private:
QLineEdit* m_pathEdit;
PropertyType m_propertyType;
QString m_path;
QHBoxLayout* m_mainLayout;
QVector<BrowseButton*> m_buttons;
QScopedPointer<CBitmapToolTip> m_previewToolTip;
QToolTipWidget* m_tooltip;
};
class FileResourceSelectorWidgetHandler
: QObject
, public AzToolsFramework::PropertyHandler < CReflectedVarResource, FileResourceSelectorWidget >
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(FileResourceSelectorWidgetHandler, AZ::SystemAllocator, 0);
virtual AZ::u32 GetHandlerName(void) const override { return AZ_CRC("Resource", 0xbc91f416); }
virtual bool IsDefaultHandler() const override { return true; }
virtual QWidget* GetFirstInTabOrder(FileResourceSelectorWidget* widget) override { return widget->GetFirstInTabOrder(); }
virtual QWidget* GetLastInTabOrder(FileResourceSelectorWidget* widget) override { return widget->GetLastInTabOrder(); }
virtual void UpdateWidgetInternalTabbing(FileResourceSelectorWidget* widget) override { widget->UpdateTabOrder(); }
virtual QWidget* CreateGUI(QWidget* pParent) override;
virtual void ConsumeAttribute(FileResourceSelectorWidget* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(size_t index, FileResourceSelectorWidget* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(size_t index, FileResourceSelectorWidget* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
};
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYRESOURCECTRL_H

@ -70,12 +70,6 @@ void ReflectedVarInit::setupReflection(AZ::SerializeContext* serializeContext)
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarResource >("VarResource", "Resource")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarResource::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarResource::description)
;
ec->Class< CReflectedVarUser >("VarUser", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarUser::varName)

@ -588,7 +588,7 @@ QMenu* LevelEditorMenuHandler::CreateGameMenu()
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{
// Export to Engine

@ -706,7 +706,7 @@ void CCryEditApp::OnFileSave()
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{
@ -2364,7 +2364,7 @@ void CCryEditApp::ExportLevel(bool bExportToGame, bool bExportTexture, bool bAut
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{
AZ_Assert(false, "Prefab system doesn't require level exports.");
@ -2405,7 +2405,7 @@ bool CCryEditApp::UserExportToGame(bool bNoMsgBox)
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{
AZ_Assert(false, "Export Level should no longer exist.");
@ -2453,7 +2453,7 @@ void CCryEditApp::ExportToGame(bool bNoMsgBox)
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{
AZ_Assert(false, "Prefab system no longer exports levels.");
@ -2961,7 +2961,7 @@ CCryEditApp::ECreateLevelResult CCryEditApp::CreateLevel(const QString& levelNam
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
// If we are creating a new level and we're in simulate mode, then switch it off before we do anything else
if (GetIEditor()->GetGameEngine() && GetIEditor()->GetGameEngine()->GetSimulationMode())
@ -3107,7 +3107,7 @@ bool CCryEditApp::CreateLevel(bool& wasCreateLevelOperationCancelled)
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{
QString str = QObject::tr("Level %1 has been changed. Save Level?").arg(GetIEditor()->GetGameEngine()->GetLevelName());
@ -3321,7 +3321,7 @@ CCryEditDoc* CCryEditApp::OpenDocumentFile(const char* filename, bool addToMostR
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
// If we are loading and we're in simulate mode, then switch it off before we do anything else
if (GetIEditor()->GetGameEngine() && GetIEditor()->GetGameEngine()->GetSimulationMode())

@ -371,7 +371,7 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename)
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{
@ -636,7 +636,7 @@ bool CCryEditDoc::SaveModified()
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{
QMessageBox saveModifiedMessageBox(AzToolsFramework::GetActiveWindow());
@ -699,7 +699,7 @@ void CCryEditDoc::OnFileSaveAs()
CCryEditApp::instance()->AddToRecentFileList(levelFileDialog.GetFileName());
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{
AzToolsFramework::Prefab::TemplateId rootPrefabTemplateId =
@ -728,7 +728,7 @@ bool CCryEditDoc::BeforeOpenDocument(const QString& lpszPathName, TOpenDocContex
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{

@ -489,7 +489,7 @@ bool CGameEngine::LoadLevel(
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{

@ -100,7 +100,7 @@ bool CGameExporter::Export(unsigned int flags, [[maybe_unused]] EEndian eExportE
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{

@ -70,7 +70,7 @@ private:
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{
AZ_Assert(false, "Level.pak should no longer be used when prefabs are used for levels.");

@ -659,7 +659,7 @@ void MainWindow::InitActions()
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!usePrefabSystemForLevels)
{
am->AddAction(ID_FILE_EXPORTTOGAMENOSURFACETEXTURE, tr("&Export to Engine"))

@ -22,13 +22,6 @@ set(FILES
Controls/ReflectedPropertyControl/ReflectedVar.h
Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp
Controls/ReflectedPropertyControl/ReflectedVarWrapper.h
Controls/QBitmapPreviewDialog.cpp
Controls/QBitmapPreviewDialog.h
Controls/QBitmapPreviewDialog.ui
Controls/QBitmapPreviewDialogImp.cpp
Controls/QBitmapPreviewDialogImp.h
Controls/QToolTipWidget.h
Controls/QToolTipWidget.cpp
UsedResources.cpp
LyViewPaneNames.h
QtViewPaneManager.cpp

@ -313,8 +313,6 @@ set(FILES
AssetEditor/AssetEditorWindow.ui
Commands/CommandManager.cpp
Commands/CommandManager.h
Controls/BitmapToolTip.cpp
Controls/BitmapToolTip.h
Controls/ConsoleSCB.cpp
Controls/ConsoleSCB.h
Controls/ConsoleSCB.ui
@ -336,8 +334,6 @@ set(FILES
Controls/ReflectedPropertyControl/PropertyMiscCtrl.h
Controls/ReflectedPropertyControl/PropertyMotionCtrl.cpp
Controls/ReflectedPropertyControl/PropertyMotionCtrl.h
Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp
Controls/ReflectedPropertyControl/PropertyResourceCtrl.h
Controls/ReflectedPropertyControl/PropertyCtrl.cpp
Controls/ReflectedPropertyControl/PropertyCtrl.h
MainStatusBar.cpp

@ -447,13 +447,13 @@ namespace UnitTest
{
x -= 1;
});
// a <-- Root
// / \
// b c
// \ /
// d
/*
a <-- Root
/ \
b c
\ /
d
*/
a.Precedes(b, c);
d.Follows(b, c);
@ -522,20 +522,20 @@ namespace UnitTest
{
x -= 1;
});
// NOTE: The ideal way to express this topology is without the wait on the subgraph
// at task g, but this is more an illustrative test. Better is to express the entire
// graph in a single larger graph.
// a <-- Root
// / \
// b c - f
// \ \ \
// \ e - g
// \ /
// \ /
// \ /
// d
/*
NOTE: The ideal way to express this topology is without the wait on the subgraph
at task g, but this is more an illustrative test. Better is to express the entire
graph in a single larger graph.
a <-- Root
/ \
b c - f
\ \ \
\ e - g
\ /
\ /
\ /
d
*/
a.Precedes(b);
a.Precedes(c);
b.Precedes(d);
@ -593,17 +593,17 @@ namespace UnitTest
{
x += 0b1000;
});
// a <-- Root
// / \
// b c - f
// \ \ \
// \ e - g
// \ /
// \ /
// \ /
// d
/*
a <-- Root
/ \
b c - f
\ \ \
\ e - g
\ /
\ /
\ /
d
*/
a.Precedes(b, c);
b.Precedes(d);
c.Precedes(e, f);

@ -112,6 +112,7 @@ namespace AzFramework
virtual void SetPrefabSystemEnabled([[maybe_unused]] bool enable) {}
/// Returns true if Prefab System is enabled for use with levels, false if legacy level system is enabled (level.pak)
/// @deprecated Use 'IsPrefabSystemEnabled' instead
virtual bool IsPrefabSystemForLevelsEnabled() const { return false; }
/// Returns true if code should assert when the Legacy Slice System is used

@ -765,6 +765,7 @@ namespace AzFramework
bool Application::IsPrefabSystemForLevelsEnabled() const
{
AZ_Warning("Application", false, "'IsPrefabSystemForLevelsEnabled' is deprecated, please use 'IsPrefabSystemEnabled' instead.");
return IsPrefabSystemEnabled();
}

@ -1208,7 +1208,7 @@ namespace AZ::IO
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{
@ -1274,7 +1274,7 @@ namespace AZ::IO
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
AZStd::unique_lock lock(m_csZips);
for (auto it = m_arrZips.begin(); it != m_arrZips.end();)

@ -295,7 +295,7 @@ namespace AzToolsFramework
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
{

@ -19,13 +19,15 @@
#define AZ_DebugSecureSocket(...)
#define AZ_DebugSecureSocketConnection(window, fmt, ...)
//#define AZ_DebugUseSocketDebugLog
//#define AZ_DebugSecureSocket AZ_TracePrintf
//#define AZ_DebugSecureSocketConnection(window, fmt, ...) \
//{\
// AZStd::string line = AZStd::string::format(fmt, __VA_ARGS__);\
// this->m_dbgLog += line;\
//}
/*
#define AZ_DebugUseSocketDebugLog
#define AZ_DebugSecureSocket AZ_TracePrintf
#define AZ_DebugSecureSocketConnection(window, fmt, ...) \
{\
AZStd::string line = AZStd::string::format(fmt, __VA_ARGS__);\
this->m_dbgLog += line;\
}
*/
#if AZ_TRAIT_GRIDMATE_SECURE_SOCKET_DRIVER_HOOK_ENABLED
struct ssl_st;

@ -41,7 +41,7 @@ bool CLevelInfo::OpenLevelPak()
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
// The prefab system doesn't use level.pak
if (usePrefabSystemForLevels)
@ -62,7 +62,7 @@ void CLevelInfo::CloseLevelPak()
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
// The prefab system doesn't use level.pak
if (usePrefabSystemForLevels)
@ -82,7 +82,7 @@ bool CLevelInfo::ReadInfo()
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
// Set up a default game type for legacy code.
m_defaultGameTypeName = "mission0";

@ -1046,7 +1046,7 @@ AZ_POP_DISABLE_WARNING
// LEVEL SYSTEM
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (usePrefabSystemForLevels)
{

@ -999,79 +999,81 @@ namespace ImageProcessingAtom
}
// TODO: not working yet, debug and enable
//static void SplitAlgorithm(const void* i, void* o, struct prcparm* templ, int threads = 8)
//{
// struct prcparm fraction[32];
// int t, istart = 0, sstart = 0, ostart = 0;
// const bool scaler = true;
// int theight = 0;
// /* prepare data to be emitted to the threads */
// for (t = 0; t < threads; t++)
// {
// fraction[t] = *templ;
// /* adjust the processing-region according to the available threads */
// {
//#undef split /* only prefix-threads need aligned transpose (for not trashing suffix-thread data) */
//#define split(rows) !scaler \
// ? ((rows * (t + 1)) / threads) & (~(t != threads - 1 ? 15 : 0)) \
// : ((rows * (t + 1)) / threads) & (~0)
// /* area covered */
// const int inrows = (fraction[t].regional ? fraction[t].region.inrows : fraction[t].inrows);
// const int incols = (fraction[t].regional ? fraction[t].region.incols : fraction[t].incols);
// const int subrows = (fraction[t].regional ? fraction[t].region.subrows : fraction[t].subrows);
// const int subcols = (fraction[t].regional ? fraction[t].region.subcols : fraction[t].subcols);
// const int outrows = (fraction[t].regional ? fraction[t].region.outrows : fraction[t].outrows);
// const int outcols = (fraction[t].regional ? fraction[t].region.outcols : fraction[t].outcols);
// /* splitting blocks */
// const int istop = split(inrows), sstop = split(subrows), ostop = split(outrows);
// const int irows = istop - istart, srows = sstop - sstart, orows = ostop - ostart;
// const int icols = incols, scols = subcols, ocols = outcols;
// AZ_Assert(irows > 0, "%s: Expect row count to be above zero!", __FUNCTION__);
// AZ_Assert(orows > 0, "%s: Expect row count to be above zero!", __FUNCTION__);
// AZ_Assert(icols > 0, "%s: Expect column count to be above zero!", __FUNCTION__);
// AZ_Assert(ocols > 0, "%s: Expect column count to be above zero!", __FUNCTION__);
// /* now we are regional */
// fraction[t].regional = true;
// /* take previous regionality into account */
// fraction[t].region.intop += istart;
// fraction[t].region.subtop += sstart;
// fraction[t].region.outtop += ostart;
// fraction[t].region.inrows = irows;
// fraction[t].region.subrows = srows;
// fraction[t].region.outrows = orows;
// /* take previous regionality into account */
// fraction[t].region.inleft += 0;
// fraction[t].region.subleft += 0;
// fraction[t].region.outleft += 0;
// fraction[t].region.incols = icols;
// fraction[t].region.subcols = scols;
// fraction[t].region.outcols = ocols;
// /* advance block */
// istart = istop;
// sstart = sstop;
// ostart = ostop;
// /* check */
// theight += irows;
// }
// // the algorithm supports "i" and "o" pointing to the same memory
// CheckBoundaries((float*)i, (float*)o, &fraction[t]);
// RunAlgorithm((float*)i, (float*)o, &fraction[t]);
// }
// AZ_Assert(theight >= (templ->regional ? templ->region.inrows : templ->inrows), "%s: Invalid height!", __FUNCTION__);
//}
/*
static void SplitAlgorithm(const void* i, void* o, struct prcparm* templ, int threads = 8)
{
struct prcparm fraction[32];
int t, istart = 0, sstart = 0, ostart = 0;
const bool scaler = true;
int theight = 0;
// prepare data to be emitted to the threads
for (t = 0; t < threads; t++)
{
fraction[t] = *templ;
// adjust the processing-region according to the available threads
{
#undef split // only prefix-threads need aligned transpose (for not trashing suffix-thread data)
#define split(rows) !scaler \
? ((rows * (t + 1)) / threads) & (~(t != threads - 1 ? 15 : 0)) \
: ((rows * (t + 1)) / threads) & (~0)
// area covered
const int inrows = (fraction[t].regional ? fraction[t].region.inrows : fraction[t].inrows);
const int incols = (fraction[t].regional ? fraction[t].region.incols : fraction[t].incols);
const int subrows = (fraction[t].regional ? fraction[t].region.subrows : fraction[t].subrows);
const int subcols = (fraction[t].regional ? fraction[t].region.subcols : fraction[t].subcols);
const int outrows = (fraction[t].regional ? fraction[t].region.outrows : fraction[t].outrows);
const int outcols = (fraction[t].regional ? fraction[t].region.outcols : fraction[t].outcols);
// splitting blocks
const int istop = split(inrows), sstop = split(subrows), ostop = split(outrows);
const int irows = istop - istart, srows = sstop - sstart, orows = ostop - ostart;
const int icols = incols, scols = subcols, ocols = outcols;
AZ_Assert(irows > 0, "%s: Expect row count to be above zero!", __FUNCTION__);
AZ_Assert(orows > 0, "%s: Expect row count to be above zero!", __FUNCTION__);
AZ_Assert(icols > 0, "%s: Expect column count to be above zero!", __FUNCTION__);
AZ_Assert(ocols > 0, "%s: Expect column count to be above zero!", __FUNCTION__);
// now we are regional
fraction[t].regional = true;
// take previous regionality into account
fraction[t].region.intop += istart;
fraction[t].region.subtop += sstart;
fraction[t].region.outtop += ostart;
fraction[t].region.inrows = irows;
fraction[t].region.subrows = srows;
fraction[t].region.outrows = orows;
// take previous regionality into account
fraction[t].region.inleft += 0;
fraction[t].region.subleft += 0;
fraction[t].region.outleft += 0;
fraction[t].region.incols = icols;
fraction[t].region.subcols = scols;
fraction[t].region.outcols = ocols;
// advance block
istart = istop;
sstart = sstop;
ostart = ostop;
// check
theight += irows;
}
// the algorithm supports "i" and "o" pointing to the same memory
CheckBoundaries((float*)i, (float*)o, &fraction[t]);
RunAlgorithm((float*)i, (float*)o, &fraction[t]);
}
AZ_Assert(theight >= (templ->regional ? templ->region.inrows : templ->inrows), "%s: Invalid height!", __FUNCTION__);
}
*/
/* #################################################################################################################### \
*/

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18a2bfdeeabfbbf6397daab7c89f9f7321e4863b54a4669fa87e457cb113322c
size 78256

@ -42,6 +42,22 @@
},
"LoadAction": "Clear"
}
},
{
"Name": "VisualizationOutput",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"ClearValue": {
"Value": [
0.0,
0.0,
0.0,
0.0
]
},
"LoadAction": "Clear"
}
}
],
"ImageAttachments": [
@ -74,6 +90,13 @@
"Pass": "This",
"Attachment": "IrradianceImage"
}
},
{
"LocalSlot": "VisualizationOutput",
"AttachmentRef": {
"Pass": "DiffuseProbeGridVisualizationRayTracingPass",
"Attachment": "Output"
}
}
],
"PassRequests": [
@ -193,6 +216,18 @@
}
}
]
},
{
"Name": "DiffuseProbeGridVisualizationPreparePass",
"TemplateName": "DiffuseProbeGridVisualizationPreparePassTemplate"
},
{
"Name": "DiffuseProbeGridVisualizationAccelerationStructurePass",
"TemplateName": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate"
},
{
"Name": "DiffuseProbeGridVisualizationRayTracingPass",
"TemplateName": "DiffuseProbeGridVisualizationRayTracingPassTemplate"
}
]
}

@ -0,0 +1,13 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData":
{
"PassTemplate":
{
"Name": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate",
"PassClass": "DiffuseProbeGridVisualizationAccelerationStructurePass"
}
}
}

@ -0,0 +1,40 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "DiffuseProbeGridVisualizationCompositePassTemplate",
"PassClass": "DiffuseProbeGridVisualizationCompositePass",
"Slots": [
{
"Name": "VisualizationInput",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader"
},
{
"Name": "Depth",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"AspectFlags": [
"Depth"
]
}
},
{
"Name": "ColorInputOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
}
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"ShaderAsset": {
"FilePath": "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.shader"
},
"PipelineViewTag": "MainCamera"
}
}
}
}

@ -0,0 +1,13 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData":
{
"PassTemplate":
{
"Name": "DiffuseProbeGridVisualizationPreparePassTemplate",
"PassClass": "DiffuseProbeGridVisualizationPreparePass"
}
}
}

@ -0,0 +1,54 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "DiffuseProbeGridVisualizationRayTracingPassTemplate",
"PassClass": "DiffuseProbeGridVisualizationRayTracingPass",
"Slots": [
{
"Name": "Output",
"SlotType": "Output",
"ShaderInputName": "m_output",
"ScopeAttachmentUsage": "Shader",
"LoadStoreAction": {
"ClearValue": {
"Value": [
0.0,
0.0,
0.0,
0.0
]
},
"LoadAction": "Clear"
}
}
],
"ImageAttachments": [
{
"Name": "VisualizationImage",
"SizeSource": {
"Source": {
"Pass": "Parent",
"Attachment": "NormalInput"
}
},
"ImageDescriptor": {
"Format": "R32G32B32A32_FLOAT",
"SharedQueueMask": "Graphics"
}
}
],
"Connections": [
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "This",
"Attachment": "VisualizationImage"
}
}
]
}
}
}

@ -357,6 +357,33 @@
}
]
},
{
"Name": "DiffuseProbeGridVisualizationCompositePass",
"TemplateName": "DiffuseProbeGridVisualizationCompositePassTemplate",
"Connections": [
{
"LocalSlot": "VisualizationInput",
"AttachmentRef": {
"Pass": "OpaquePass",
"Attachment": "DiffuseProbeGridVisualization"
}
},
{
"LocalSlot": "Depth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "ColorInputOutput",
"AttachmentRef": {
"Pass": "PostProcessPass",
"Attachment": "Output"
}
}
]
},
{
"Name": "AuxGeomPass",
"TemplateName": "AuxGeomPassTemplate",
@ -365,8 +392,8 @@
{
"LocalSlot": "ColorInputOutput",
"AttachmentRef": {
"Pass": "PostProcessPass",
"Attachment": "Output"
"Pass": "DiffuseProbeGridVisualizationCompositePass",
"Attachment": "ColorInputOutput"
}
},
{

@ -46,6 +46,10 @@
"Name": "Output",
"SlotType": "Output"
},
{
"Name": "DiffuseProbeGridVisualization",
"SlotType": "Output"
},
// SwapChain here is only used to reference the frame height and format
{
"Name": "SwapChainOutput",
@ -59,6 +63,13 @@
"Pass": "DiffuseSpecularMergePass",
"Attachment": "Output"
}
},
{
"LocalSlot": "DiffuseProbeGridVisualization",
"AttachmentRef": {
"Pass": "DiffuseGlobalIlluminationPass",
"Attachment": "VisualizationOutput"
}
}
],
"PassRequests": [

@ -476,6 +476,22 @@
"Name": "DiffuseCompositePassTemplate",
"Path": "Passes/DiffuseComposite.pass"
},
{
"Name": "DiffuseProbeGridVisualizationPreparePassTemplate",
"Path": "Passes/DiffuseProbeGridVisualizationPrepare.pass"
},
{
"Name": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate",
"Path": "Passes/DiffuseProbeGridVisualizationAccelerationStructure.pass"
},
{
"Name": "DiffuseProbeGridVisualizationRayTracingPassTemplate",
"Path": "Passes/DiffuseProbeGridVisualizationRayTracing.pass"
},
{
"Name": "DiffuseProbeGridVisualizationCompositePassTemplate",
"Path": "Passes/DiffuseProbeGridVisualizationComposite.pass"
},
{
"Name": "DiffuseGlobalFullscreenPassTemplate",
"Path": "Passes/DiffuseGlobalFullscreen.pass"

@ -0,0 +1,65 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <scenesrg.srgi>
#include <viewsrg.srgi>
#include <Atom/Features/PostProcessing/FullscreenVertexUtil.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertexInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
#include <Atom/RPI/Math.azsli>
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float4> m_visualization;
Texture2D<float> m_depth;
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
}
// Vertex Shader
VSOutput MainVS(VSInput input)
{
VSOutput OUT;
float4 posTex = GetVertexPositionAndTexCoords(input.m_vertexID);
OUT.m_position = float4(posTex.x, posTex.y, 0.0, 1.0);
return OUT;
}
// Pixel Shader
PSOutput MainPS(VSOutput IN)
{
uint2 screenCoords = IN.m_position.xy;
float depth = PassSrg::m_depth.Load(uint3(screenCoords, 0)).r;
float4 visualization = PassSrg::m_visualization.Load(uint3(screenCoords, 0));
if (!any(visualization))
{
discard;
}
if (depth > visualization.a)
{
discard;
}
PSOutput OUT;
OUT.m_color = float4(visualization.rgb, 1.0f);
return OUT;
}

@ -0,0 +1,42 @@
{
"Source" : "DiffuseProbeGridVisualizationComposite.azsl",
"RasterState" :
{
"CullMode" : "Back"
},
"DepthStencilState" :
{
"Depth" :
{
"Enable" : false
}
},
"DrawList" : "forward",
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
},
"Supervariants":
[
{
"Name": "NoMSAA",
"PlusArguments": "--no-ms",
"MinusArguments": ""
}
]
}

@ -0,0 +1,34 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PrecompiledShaderAssetSourceData",
"ClassData":
{
"ShaderAssetFileName": "diffuseprobegridvisualizationprepare.azshader",
"PlatformIdentifiers": [
"pc",
"linux"
],
"Supervariants":
[
{
"Name": "",
"RootShaderVariantAssets":
[
{
"APIName": "dx12",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationprepare_dx12_0.azshadervariant"
},
{
"APIName": "vulkan",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationprepare_vulkan_0.azshadervariant"
},
{
"APIName": "null",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationprepare_null_0.azshadervariant"
}
]
}
]
}
}

@ -0,0 +1,34 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PrecompiledShaderAssetSourceData",
"ClassData":
{
"ShaderAssetFileName": "diffuseprobegridvisualizationraytracing.azshader",
"PlatformIdentifiers": [
"pc",
"linux"
],
"Supervariants":
[
{
"Name": "",
"RootShaderVariantAssets":
[
{
"APIName": "dx12",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracing_dx12_0.azshadervariant"
},
{
"APIName": "vulkan",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracing_vulkan_0.azshadervariant"
},
{
"APIName": "null",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracing_null_0.azshadervariant"
}
]
}
]
}
}

@ -0,0 +1,35 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PrecompiledShaderAssetSourceData",
"ClassData":
{
"ShaderAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit.azshader",
"PlatformIdentifiers":
[
"pc",
"linux"
],
"Supervariants":
[
{
"Name": "",
"RootShaderVariantAssets":
[
{
"APIName": "dx12",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit_dx12_0.azshadervariant"
},
{
"APIName": "vulkan",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit_vulkan_0.azshadervariant"
},
{
"APIName": "null",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit_null_0.azshadervariant"
}
]
}
]
}
}

@ -0,0 +1,35 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PrecompiledShaderAssetSourceData",
"ClassData":
{
"ShaderAssetFileName": "diffuseprobegridvisualizationraytracingmiss.azshader",
"PlatformIdentifiers":
[
"pc",
"linux"
],
"Supervariants":
[
{
"Name": "",
"RootShaderVariantAssets":
[
{
"APIName": "dx12",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingmiss_dx12_0.azshadervariant"
},
{
"APIName": "vulkan",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingmiss_vulkan_0.azshadervariant"
},
{
"APIName": "null",
"RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingmiss_null_0.azshadervariant"
}
]
}
]
}
}

@ -125,6 +125,9 @@ namespace AZ
virtual void SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl) = 0;
virtual void SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode) = 0;
virtual void SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures) = 0;
virtual void SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled) = 0;
virtual void SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes) = 0;
virtual void SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius) = 0;
virtual void BakeTextures(
const DiffuseProbeGridHandle& probeGrid,

@ -6,239 +6,241 @@
*
*/
//
// This is a quick guide on how to use the parameter macros included in this folder
//
// Part I: The Pattern
//
// The aim of this macro system is to allow users to define parameters once and have the macros generate a bunch of boilerplate code for each defined parameter.
// While these macros makes things a little more complex upfront, the ability to add and remove variables in just one place without having to dig
// through multiple files every time is great for iteration speed and maintenance. To accomplish this, we use a pattern similar to the following example:
//
// Let's say we want to specify class members in one place and have the members, getters and setters be auto generated.
// First, we define a macro MY_CLASS_PARAMS that uses a yet-undefined macro MAKE_PARAM(TYPE, NAME):
//
// #define MY_CLASS_PARAMS \
// MAKE_PARAM(float, Width) \
// MAKE_PARAM(float, Height) \
// MAKE_PARAM(float, Depth) \
//
// Now we need only specify what MAKE_PARAM needs to do and then we can call the MY_CLASS_PARAMS macro to apply the logic to all defined params. For instance:
//
// #define MAKE_PARAM(TYPE, NAME) TYPE m_##NAME;
// MY_CLASS_PARAMS
// #undef MAKE_PARAM
//
// This will generate the members as follows:
//
// float m_Width;
// float m_Height;
// float m_Depth;
//
// Now elsewhere in the class definition we can generate getters and setters:
//
// #define MAKE_PARAM(TYPE, NAME) \
// TYPE Get##NAME() { return m_##NAME; } \
// void Set##NAME(TYPE NAME) { m_##NAME = NAME; } \
//
// MY_CLASS_PARAMS
//
// #undef MAKE_PARAM
//
// This will generate the following:
//
// float GetWidth() { return m_Width; }
// void SetWidth(float Width) { m_Width = Width; }
// float GetHeight() { return m_Height; }
// void SetHeight(float Width) { m_Height = Height; }
// float GetDepth() { return m_Width; }
// void SetDepth(float Depth) { m_Depth = Depth; }
//
// If we wanted to generate further code for each variable, we need only redefine the MAKE_PARAM macro and invoke MY_CLASS_PARAMS
//
// ___________________________________________________________________________________________________________________________________________________
//
// Part II: Using .inl files
//
// A key difference between the above example and our macro system is that we put macro definitions in .inl files so they can be easily reused
// If we were to reuse the above example, it would look something like this:
//
// GenerateMembers.inl
//
// #define MAKE_PARAM(TYPE, NAME) TYPE m_##NAME;
//
// GenerateGettersAndSetters.inl
//
// #define MAKE_PARAM(TYPE, NAME) \
// TYPE Get##NAME() { return m_##NAME; } \
// void Set##NAME(TYPE NAME) { m_##NAME = NAME; } \
//
// BoxParams.inl
//
// MAKE_PARAM(float, Width) \
// MAKE_PARAM(float, Height) \
// MAKE_PARAM(float, Depth) \
//
// CylinderParams.inl
//
// MAKE_PARAM(float, Radius) \
// MAKE_PARAM(float, Height) \
//
// Now we can use these .inl files to generate two classes, each with members, getters and setters
//
// class Box
// {
// // Auto-gen members from BoxParams.inl
// #include<GenerateMembers.inl>
// #include<BoxParams.inl>
// #undef MAKE_PARAM
//
// // Auto-gen getters and setters from BoxParams.inl
// #include<GenerateGettersAndSetters.inl>
// #include<BoxParams.inl>
// #undef MAKE_PARAM
// }
//
// class Cylinder
// {
// // Auto-gen members from CylinderParams.inl
// #include<GenerateMembers.inl>
// #include<CylinderParams.inl>
// #undef MAKE_PARAM
//
// // Auto-gen getters and setters from CylinderParams.inl
// #include<GenerateGettersAndSetters.inl>
// #include<CylinderParams.inl>
// #undef MAKE_PARAM
// }
//
// This will result in the following code:
//
// class Box
// {
// // Auto-gen members from BoxParams.inl
// float m_Width;
// float m_Height;
// float m_Depth;
//
// // Auto-gen getters and setters from BoxParams.inl
// float GetWidth() { return m_Width; }
// void SetWidth(float Width) { m_Width = Width; }
// float GetHeight() { return m_Height; }
// void SetHeight(float Width) { m_Height = Height; }
// float GetDepth() { return m_Width; }
// void SetDepth(float Depth) { m_Depth = Depth; }
// }
//
// class Cylinder
// {
// // Auto-gen members from CylinderParams.inl
// float m_Radius;
// float m_Height;
//
// // Auto-gen getters and setters from CylinderParams.inl
// float GetRadius() { return m_Radius; }
// void SetRadius(float Radius) { m_Radius = Raidus; }
// float GetHeight() { return m_Height; }
// void SetHeight(float Width) { m_Height = Height; }
// }
//
// As you can see, this macro pattern allows us to add a member to Box or Cylinder by adding a single line to BoxParams.inl or CylinderParams.inl
// Because of the number of classes an boiler plate code involved in creating Open 3D Engine Component, this macro system allows us to change one line
// in one file instead of changing over a dozens of lines in half a dozen files.
//
// ___________________________________________________________________________________________________________________________________________________
//
// Part III: Using the Macros for Post Process members
//
// If you want to create a new post process, you can create a .inl file (see DepthOfFieldParams.inl for an example) and declare members using the macros below:
//
// #define AZ_GFX_BOOL_PARAM(Name, MemberName, DefaultValue)
// #define AZ_GFX_FLOAT_PARAM(Name, MemberName, DefaultValue)
// #define AZ_GFX_UINT32_PARAM(Name, MemberName, DefaultValue)
// #define AZ_GFX_VEC2_PARAM(Name, MemberName, DefaultValue)
// #define AZ_GFX_VEC3_PARAM(Name, MemberName, DefaultValue)
// #define AZ_GFX_VEC4_PARAM(Name, MemberName, DefaultValue)
//
// Where:
// Name - The name of the param that will be used for reflection and appended to setters and getters, for example Width
// MemberName - The name of the member defined inside your class, for example m_width
// DefaultValue - The default value that the member will be statically initialized to, for example 1.0f
// BOOL, FLOAT, UINT32, VEC2 etc. all designate the type of the param you are defining
//
// If you have a custom type for your parameter, you can use the AZ_GFX_COMMON_PARAM macro:
// AZ_GFX_COMMON_PARAM(Name, MemberName, DefaultValue, ValueType)
// The keywords here are the same as above, with the addition of ValueType: the custom type you want your param to be
//
// Example usages:
//
// #define AZ_GFX_VEC3_PARAM(Position, m_position, Vector3(0.0f, 0.0f, 0.0f))
//
// #define AZ_GFX_COMMON_PARAM(Format, m_format, Format::Unknown, FormatEnum)
//
// ___________________________________________________________________________________________________________________________________________________
//
// Part IV: Using the Macros for Post Process overrides
//
// The Post Process System allows users to specify whether settings should be overridden or not on a per-member basis.
// To enable this, when you declare a member that can be overridden by higher priority Post Process Settings, in addition
// to using the above macros to define the member, you should also use one of the following to specify the override:
//
// #define AZ_GFX_ANY_PARAM_BOOL_OVERRIDE(Name, MemberName, ValueType)
// #define AZ_GFX_INTEGER_PARAM_FLOAT_OVERRIDE(Name, MemberName, ValueType)
// #define AZ_GFX_FLOAT_PARAM_FLOAT_OVERRIDE(Name, MemberName, ValueType)
//
// Where:
// Name - The name of the param that will be used for reflection and appended to setters and getters, for example Width
// MemberName - The name of the member defined inside your class, for example m_width
// ValueType - The type of the parameter you defined (bool, float, uint32_t, Vector2 etc.)
//
// A bit more details on each of the override macros:
//
// AZ_GFX_ANY_PARAM_BOOL_OVERRIDE can be used for params of any type. The override variable will be a bool (checkbox in the UI).
// The override application is a simple binary operation: take all of the source or the target (no lerp) depending on the bool.
//
// AZ_GFX_INTEGER_PARAM_FLOAT_OVERRIDE should be used for params of integer types (int, uint, integer vectors...) The override variable
// will be a float from 0.0 to 1.0 (slider in the UI). The override will lerp between target and source using the override float
// variable. Note that for this reason the param integer type must support multiplication by a float value.
//
// AZ_GFX_FLOAT_PARAM_FLOAT_OVERRIDE should be used for params of floating point types (float, double, Vector4...) The override variable
// will be a float from 0.0 to 1.0 (slider in the UI). The override will lerp between target and source using the override float.
//
// Example usage:
//
// #define AZ_GFX_VEC3_PARAM(Position, m_position, Vector3(0.0f, 0.0f, 0.0f))
// #define AZ_GFX_FLOAT_PARAM_FLOAT_OVERRIDE(Position, m_position, Vector3)
//
// ___________________________________________________________________________________________________________________________________________________
//
// Part V: Defining functionality with .inl files
//
// There are many .inl fies in this folder that provide pre-defined behaviors for params declared with the above macros
// To use these files, start by including the .inl file that specifies the behavior, then include your own .inl that defines your params
// then include EndParams.inl (this will #undef all used macros so as to avoid collisions with subsequent macro usage further in the file)
//
// Here is an example of how that looks:
//
// #include <Atom/Feature/ParamMacros/StartParamFunctionsVirtual.inl> <- The behavior you want (behavior is described in each file)
// #include <Atom/Feature/PostProcess/PostProcessParams.inl> <- Your file in which you declare your params
// #include <Atom/Feature/ParamMacros/EndParams.inl> <- This #undef a bunch of macros to avoid conflicts
//
// You may of course use your own custom behaviors by specifying your definition for the param and override macros.
// You can specify each macro individually (AZ_GFX_BOOL_PARAM, AZ_GFX_FLOAT_PARAM, AZ_GFX_UINT32_PARAM, AZ_GFX_VEC2_PARAM, etc.)
// or you can specify the AZ_GFX_COMMON_PARAM and AZ_GFX_COMMON_OVERRIDE macros if there's no difference between variable types.
//
// AZ_GFX_COMMON_PARAM and AZ_GFX_COMMON_OVERRIDE are helper macros that the other _PARAM and _OVERRIDE macros can be mapped to
// using MapAllCommon.inl, allowing you to specify one definition for all types rather than each type individually.
// Here is an example of how we can use AZ_GFX_COMMON_PARAM and AZ_GFX_COMMON_OVERRIDE to auto-generate getters for our member parameters:
//
// #define AZ_GFX_COMMON_PARAM(Name, MemberName, DefaultValue, ValueType) \
// ValueType Get##Name() const override { return MemberName; } \
//
// #define AZ_GFX_COMMON_OVERRIDE(Name, MemberName, ValueType, OverrideValueType) \
// OverrideValueType Get##Name##Override() const override { return MemberName##Override; } \
//
// #include <Atom/Feature/ParamMacros/MapAllCommon.inl>
// #include <Atom/Feature/MyCustomFeature/MyCustomPostProcess.inl>
// #include <Atom/Feature/ParamMacros/EndParams.inl>
//
/*
This is a quick guide on how to use the parameter macros included in this folder
Part I: The Pattern
The aim of this macro system is to allow users to define parameters once and have the macros generate a bunch of boilerplate code for each defined parameter.
While these macros makes things a little more complex upfront, the ability to add and remove variables in just one place without having to dig
through multiple files every time is great for iteration speed and maintenance. To accomplish this, we use a pattern similar to the following example:
Let's say we want to specify class members in one place and have the members, getters and setters be auto generated.
First, we define a macro MY_CLASS_PARAMS that uses a yet-undefined macro MAKE_PARAM(TYPE, NAME):
#define MY_CLASS_PARAMS \
MAKE_PARAM(float, Width) \
MAKE_PARAM(float, Height) \
MAKE_PARAM(float, Depth) \
Now we need only specify what MAKE_PARAM needs to do and then we can call the MY_CLASS_PARAMS macro to apply the logic to all defined params. For instance:
#define MAKE_PARAM(TYPE, NAME) TYPE m_##NAME;
MY_CLASS_PARAMS
#undef MAKE_PARAM
This will generate the members as follows:
float m_Width;
float m_Height;
float m_Depth;
Now elsewhere in the class definition we can generate getters and setters:
#define MAKE_PARAM(TYPE, NAME) \
TYPE Get##NAME() { return m_##NAME; } \
void Set##NAME(TYPE NAME) { m_##NAME = NAME; } \
MY_CLASS_PARAMS
#undef MAKE_PARAM
This will generate the following:
float GetWidth() { return m_Width; }
void SetWidth(float Width) { m_Width = Width; }
float GetHeight() { return m_Height; }
void SetHeight(float Width) { m_Height = Height; }
float GetDepth() { return m_Width; }
void SetDepth(float Depth) { m_Depth = Depth; }
If we wanted to generate further code for each variable, we need only redefine the MAKE_PARAM macro and invoke MY_CLASS_PARAMS
___________________________________________________________________________________________________________________________________________________
Part II: Using .inl files
A key difference between the above example and our macro system is that we put macro definitions in .inl files so they can be easily reused
If we were to reuse the above example, it would look something like this:
GenerateMembers.inl
#define MAKE_PARAM(TYPE, NAME) TYPE m_##NAME;
GenerateGettersAndSetters.inl
#define MAKE_PARAM(TYPE, NAME) \
TYPE Get##NAME() { return m_##NAME; } \
void Set##NAME(TYPE NAME) { m_##NAME = NAME; } \
BoxParams.inl
MAKE_PARAM(float, Width) \
MAKE_PARAM(float, Height) \
MAKE_PARAM(float, Depth) \
CylinderParams.inl
MAKE_PARAM(float, Radius) \
MAKE_PARAM(float, Height) \
Now we can use these .inl files to generate two classes, each with members, getters and setters
class Box
{
// Auto-gen members from BoxParams.inl
#include<GenerateMembers.inl>
#include<BoxParams.inl>
#undef MAKE_PARAM
// Auto-gen getters and setters from BoxParams.inl
#include<GenerateGettersAndSetters.inl>
#include<BoxParams.inl>
#undef MAKE_PARAM
}
class Cylinder
{
// Auto-gen members from CylinderParams.inl
#include<GenerateMembers.inl>
#include<CylinderParams.inl>
#undef MAKE_PARAM
// Auto-gen getters and setters from CylinderParams.inl
#include<GenerateGettersAndSetters.inl>
#include<CylinderParams.inl>
#undef MAKE_PARAM
}
This will result in the following code:
class Box
{
// Auto-gen members from BoxParams.inl
float m_Width;
float m_Height;
float m_Depth;
// Auto-gen getters and setters from BoxParams.inl
float GetWidth() { return m_Width; }
void SetWidth(float Width) { m_Width = Width; }
float GetHeight() { return m_Height; }
void SetHeight(float Width) { m_Height = Height; }
float GetDepth() { return m_Width; }
void SetDepth(float Depth) { m_Depth = Depth; }
}
class Cylinder
{
// Auto-gen members from CylinderParams.inl
float m_Radius;
float m_Height;
// Auto-gen getters and setters from CylinderParams.inl
float GetRadius() { return m_Radius; }
void SetRadius(float Radius) { m_Radius = Raidus; }
float GetHeight() { return m_Height; }
void SetHeight(float Width) { m_Height = Height; }
}
As you can see, this macro pattern allows us to add a member to Box or Cylinder by adding a single line to BoxParams.inl or CylinderParams.inl
Because of the number of classes an boiler plate code involved in creating Open 3D Engine Component, this macro system allows us to change one line
in one file instead of changing over a dozens of lines in half a dozen files.
___________________________________________________________________________________________________________________________________________________
Part III: Using the Macros for Post Process members
If you want to create a new post process, you can create a .inl file (see DepthOfFieldParams.inl for an example) and declare members using the macros below:
#define AZ_GFX_BOOL_PARAM(Name, MemberName, DefaultValue)
#define AZ_GFX_FLOAT_PARAM(Name, MemberName, DefaultValue)
#define AZ_GFX_UINT32_PARAM(Name, MemberName, DefaultValue)
#define AZ_GFX_VEC2_PARAM(Name, MemberName, DefaultValue)
#define AZ_GFX_VEC3_PARAM(Name, MemberName, DefaultValue)
#define AZ_GFX_VEC4_PARAM(Name, MemberName, DefaultValue)
Where:
Name - The name of the param that will be used for reflection and appended to setters and getters, for example Width
MemberName - The name of the member defined inside your class, for example m_width
DefaultValue - The default value that the member will be statically initialized to, for example 1.0f
BOOL, FLOAT, UINT32, VEC2 etc. all designate the type of the param you are defining
If you have a custom type for your parameter, you can use the AZ_GFX_COMMON_PARAM macro:
AZ_GFX_COMMON_PARAM(Name, MemberName, DefaultValue, ValueType)
The keywords here are the same as above, with the addition of ValueType: the custom type you want your param to be
Example usages:
#define AZ_GFX_VEC3_PARAM(Position, m_position, Vector3(0.0f, 0.0f, 0.0f))
#define AZ_GFX_COMMON_PARAM(Format, m_format, Format::Unknown, FormatEnum)
___________________________________________________________________________________________________________________________________________________
Part IV: Using the Macros for Post Process overrides
The Post Process System allows users to specify whether settings should be overridden or not on a per-member basis.
To enable this, when you declare a member that can be overridden by higher priority Post Process Settings, in addition
to using the above macros to define the member, you should also use one of the following to specify the override:
#define AZ_GFX_ANY_PARAM_BOOL_OVERRIDE(Name, MemberName, ValueType)
#define AZ_GFX_INTEGER_PARAM_FLOAT_OVERRIDE(Name, MemberName, ValueType)
#define AZ_GFX_FLOAT_PARAM_FLOAT_OVERRIDE(Name, MemberName, ValueType)
Where:
Name - The name of the param that will be used for reflection and appended to setters and getters, for example Width
MemberName - The name of the member defined inside your class, for example m_width
ValueType - The type of the parameter you defined (bool, float, uint32_t, Vector2 etc.)
A bit more details on each of the override macros:
AZ_GFX_ANY_PARAM_BOOL_OVERRIDE can be used for params of any type. The override variable will be a bool (checkbox in the UI).
The override application is a simple binary operation: take all of the source or the target (no lerp) depending on the bool.
AZ_GFX_INTEGER_PARAM_FLOAT_OVERRIDE should be used for params of integer types (int, uint, integer vectors...) The override variable
will be a float from 0.0 to 1.0 (slider in the UI). The override will lerp between target and source using the override float
variable. Note that for this reason the param integer type must support multiplication by a float value.
AZ_GFX_FLOAT_PARAM_FLOAT_OVERRIDE should be used for params of floating point types (float, double, Vector4...) The override variable
will be a float from 0.0 to 1.0 (slider in the UI). The override will lerp between target and source using the override float.
Example usage:
#define AZ_GFX_VEC3_PARAM(Position, m_position, Vector3(0.0f, 0.0f, 0.0f))
#define AZ_GFX_FLOAT_PARAM_FLOAT_OVERRIDE(Position, m_position, Vector3)
___________________________________________________________________________________________________________________________________________________
Part V: Defining functionality with .inl files
There are many .inl fies in this folder that provide pre-defined behaviors for params declared with the above macros
To use these files, start by including the .inl file that specifies the behavior, then include your own .inl that defines your params
then include EndParams.inl (this will #undef all used macros so as to avoid collisions with subsequent macro usage further in the file)
Here is an example of how that looks:
#include <Atom/Feature/ParamMacros/StartParamFunctionsVirtual.inl> <- The behavior you want (behavior is described in each file)
#include <Atom/Feature/PostProcess/PostProcessParams.inl> <- Your file in which you declare your params
#include <Atom/Feature/ParamMacros/EndParams.inl> <- This #undef a bunch of macros to avoid conflicts
You may of course use your own custom behaviors by specifying your definition for the param and override macros.
You can specify each macro individually (AZ_GFX_BOOL_PARAM, AZ_GFX_FLOAT_PARAM, AZ_GFX_UINT32_PARAM, AZ_GFX_VEC2_PARAM, etc.)
or you can specify the AZ_GFX_COMMON_PARAM and AZ_GFX_COMMON_OVERRIDE macros if there's no difference between variable types.
AZ_GFX_COMMON_PARAM and AZ_GFX_COMMON_OVERRIDE are helper macros that the other _PARAM and _OVERRIDE macros can be mapped to
using MapAllCommon.inl, allowing you to specify one definition for all types rather than each type individually.
Here is an example of how we can use AZ_GFX_COMMON_PARAM and AZ_GFX_COMMON_OVERRIDE to auto-generate getters for our member parameters:
#define AZ_GFX_COMMON_PARAM(Name, MemberName, DefaultValue, ValueType) \
ValueType Get##Name() const override { return MemberName; } \
#define AZ_GFX_COMMON_OVERRIDE(Name, MemberName, ValueType, OverrideValueType) \
OverrideValueType Get##Name##Override() const override { return MemberName##Override; } \
#include <Atom/Feature/ParamMacros/MapAllCommon.inl>
#include <Atom/Feature/MyCustomFeature/MyCustomPostProcess.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
*/

@ -94,6 +94,10 @@
#include <DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridDownsamplePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceTracePass.h>
@ -278,6 +282,10 @@ namespace AZ
passSystem->AddPassCreator(Name("DiffuseProbeGridClassificationPass"), &Render::DiffuseProbeGridClassificationPass::Create);
passSystem->AddPassCreator(Name("DiffuseProbeGridDownsamplePass"), &Render::DiffuseProbeGridDownsamplePass::Create);
passSystem->AddPassCreator(Name("DiffuseProbeGridRenderPass"), &Render::DiffuseProbeGridRenderPass::Create);
passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationPreparePass"), &Render::DiffuseProbeGridVisualizationPreparePass::Create);
passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationAccelerationStructurePass"), &Render::DiffuseProbeGridVisualizationAccelerationStructurePass::Create);
passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationRayTracingPass"), &Render::DiffuseProbeGridVisualizationRayTracingPass::Create);
passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationCompositePass"), &Render::DiffuseProbeGridVisualizationCompositePass::Create);
passSystem->AddPassCreator(Name("LuminanceHistogramGeneratorPass"), &LuminanceHistogramGeneratorPass::Create);

@ -43,10 +43,15 @@ namespace AZ
m_irradianceImageAttachmentId = AZStd::string::format("ProbeIrradianceImageAttachmentId_%s", uuidString.c_str());
m_distanceImageAttachmentId = AZStd::string::format("ProbeDistanceImageAttachmentId_%s", uuidString.c_str());
m_probeDataImageAttachmentId = AZStd::string::format("ProbeDataImageAttachmentId_%s", uuidString.c_str());
m_visualizationTlasAttachmentId = AZStd::string::format("ProbeVisualizationTlasAttachmentId_%s", uuidString.c_str());
m_visualizationTlasInstancesAttachmentId = AZStd::string::format("ProbeVisualizationTlasInstancesAttachmentId_%s", uuidString.c_str());
// setup culling
m_cullable.m_cullData.m_scene = m_scene;
m_cullable.SetDebugName(AZ::Name("DiffuseProbeGrid Volume"));
// create the visualization TLAS
m_visualizationTlas = AZ::RHI::RayTracingTlas::CreateRHIRayTracingTlas();
}
void DiffuseProbeGrid::Simulate(uint32_t probeIndex)
@ -116,9 +121,6 @@ namespace AZ
// recompute the number of probes since the spacing changed
UpdateProbeCount();
// probes need to be relocated since the grid density changed
m_remainingRelocationIterations = DefaultNumRelocationIterations;
m_updateTextures = true;
}
@ -169,9 +171,6 @@ namespace AZ
m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_renderExtents / 2.0f);
// probes need to be relocated since the grid extents changed
m_remainingRelocationIterations = DefaultNumRelocationIterations;
m_updateTextures = true;
}
@ -201,9 +200,6 @@ namespace AZ
}
m_updateTextures = true;
// probes need to be relocated since the mode has changed
m_remainingRelocationIterations = DefaultNumRelocationIterations;
}
void DiffuseProbeGrid::SetBakedTextures(const DiffuseProbeGridBakedTextures& bakedTextures)
@ -253,6 +249,23 @@ namespace AZ
return m_cullable.m_isVisible;
}
void DiffuseProbeGrid::SetVisualizationEnabled(bool visualizationEnabled)
{
m_visualizationEnabled = visualizationEnabled;
m_visualizationTlasUpdateRequired = true;
}
void DiffuseProbeGrid::SetVisualizationSphereRadius(float visualizationSphereRadius)
{
m_visualizationSphereRadius = visualizationSphereRadius;
m_visualizationTlasUpdateRequired = true;
}
bool DiffuseProbeGrid::GetVisualizationTlasUpdateRequired() const
{
return m_visualizationTlasUpdateRequired || m_remainingRelocationIterations > 0;
}
uint32_t DiffuseProbeGrid::GetTotalProbeCount() const
{
return m_probeCountX * m_probeCountY * m_probeCountZ;
@ -341,6 +354,9 @@ namespace AZ
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeDataImage image");
}
// probes need to be relocated since the textures changed
m_remainingRelocationIterations = DefaultNumRelocationIterations;
}
m_updateTextures = false;
@ -348,8 +364,8 @@ namespace AZ
// textures have changed so we need to update the render Srg to bind the new ones
m_updateRenderObjectSrg = true;
// we need to clear the irradiance texture
m_irradianceClearRequired = true;
// we need to clear the Irradiance, Distance, and ProbeData textures
m_textureClearRequired = true;
}
void DiffuseProbeGrid::ComputeProbeCount(const AZ::Vector3& extents, const AZ::Vector3& probeSpacing, uint32_t& probeCountX, uint32_t& probeCountY, uint32_t& probeCountZ)
@ -753,6 +769,77 @@ namespace AZ
UpdateCulling();
}
void DiffuseProbeGrid::UpdateVisualizationPrepareSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& layout)
{
if (!m_visualizationPrepareSrg)
{
m_visualizationPrepareSrg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), layout->GetName());
AZ_Error("DiffuseProbeGrid", m_visualizationPrepareSrg.get(), "Failed to create VisualizationPrepare shader resource group");
}
RHI::ShaderInputConstantIndex constantIndex;
RHI::ShaderInputImageIndex imageIndex;
RHI::ShaderInputBufferIndex bufferIndex;
// TLAS instances
bufferIndex = layout->FindShaderInputBufferIndex(AZ::Name("m_tlasInstances"));
uint32_t tlasInstancesBufferByteCount = aznumeric_cast<uint32_t>(m_visualizationTlas->GetTlasInstancesBuffer()->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, tlasInstancesBufferByteCount / RayTracingTlasInstanceElementSize, RayTracingTlasInstanceElementSize);
m_visualizationPrepareSrg->SetBufferView(bufferIndex, m_visualizationTlas->GetTlasInstancesBuffer()->GetBufferView(bufferViewDescriptor).get());
// probe data
imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeData"));
m_visualizationPrepareSrg->SetImageView(imageIndex, GetProbeDataImage()->GetImageView(m_renderData->m_probeDataImageViewDescriptor).get());
// probe sphere radius
constantIndex = layout->FindShaderInputConstantIndex(Name("m_probeSphereRadius"));
m_visualizationPrepareSrg->SetConstant(constantIndex, m_visualizationSphereRadius);
SetGridConstants(m_visualizationPrepareSrg);
}
void DiffuseProbeGrid::UpdateVisualizationRayTraceSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& layout, const RHI::ImageView* outputImageView)
{
if (!m_visualizationRayTraceSrg)
{
m_visualizationRayTraceSrg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), layout->GetName());
AZ_Error("DiffuseProbeGrid", m_visualizationRayTraceSrg.get(), "Failed to create VisualizationRayTrace shader resource group");
}
RHI::ShaderInputConstantIndex constantIndex;
RHI::ShaderInputImageIndex imageIndex;
RHI::ShaderInputBufferIndex bufferIndex;
// TLAS
uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(m_visualizationTlas->GetTlasBuffer()->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(tlasBufferByteCount);
bufferIndex = layout->FindShaderInputBufferIndex(AZ::Name("m_tlas"));
m_visualizationRayTraceSrg->SetBufferView(bufferIndex, m_visualizationTlas->GetTlasBuffer()->GetBufferView(bufferViewDescriptor).get());
// probe irradiance
imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeIrradiance"));
m_visualizationRayTraceSrg->SetImageView(imageIndex, GetIrradianceImage()->GetImageView(m_renderData->m_probeIrradianceImageViewDescriptor).get());
// probe distance
imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeDistance"));
m_visualizationRayTraceSrg->SetImageView(imageIndex, GetDistanceImage()->GetImageView(m_renderData->m_probeDistanceImageViewDescriptor).get());
// probe data
imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeData"));
m_visualizationRayTraceSrg->SetImageView(imageIndex, GetProbeDataImage()->GetImageView(m_renderData->m_probeDataImageViewDescriptor).get());
// show inactive probes
constantIndex = layout->FindShaderInputConstantIndex(Name("m_showInactiveProbes"));
m_visualizationRayTraceSrg->SetConstant(constantIndex, m_visualizationShowInactiveProbes);
// output
imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_output"));
m_visualizationRayTraceSrg->SetImageView(imageIndex, outputImageView);
SetGridConstants(m_visualizationRayTraceSrg);
}
void DiffuseProbeGrid::UpdateCulling()
{
if (!m_drawPacket)

@ -8,6 +8,7 @@
#pragma once
#include <Atom/RHI/DrawPacketBuilder.h>
#include <Atom/RHI/RayTracingAccelerationStructure.h>
#include <Atom/RPI.Public/Culling.h>
#include <Atom/RPI.Public/PipelineState.h>
#include <Atom/RPI.Public/Scene.h>
@ -98,6 +99,15 @@ namespace AZ
DiffuseProbeGridMode GetMode() const { return m_mode; }
void SetMode(DiffuseProbeGridMode mode);
bool GetVisualizationEnabled() const { return m_visualizationEnabled; }
void SetVisualizationEnabled(bool visualizationEnabled);
bool GetVisualizationShowInactiveProbes() const { return m_visualizationShowInactiveProbes; }
void SetVisualizationShowInactiveProbes(bool visualizationShowInactiveProbes) { m_visualizationShowInactiveProbes = visualizationShowInactiveProbes; }
float GetVisualizationSphereRadius() const { return m_visualizationSphereRadius; }
void SetVisualizationSphereRadius(float visualizationSphereRadius);
uint32_t GetRemainingRelocationIterations() const { return aznumeric_cast<uint32_t>(m_remainingRelocationIterations); }
void DecrementRemainingRelocationIterations() { m_remainingRelocationIterations = AZStd::max(0, m_remainingRelocationIterations - 1); }
void ResetRemainingRelocationIterations() { m_remainingRelocationIterations = DefaultNumRelocationIterations; }
@ -125,6 +135,8 @@ namespace AZ
const Data::Instance<RPI::ShaderResourceGroup>& GetRelocationSrg() const { return m_relocationSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetClassificationSrg() const { return m_classificationSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetRenderObjectSrg() const { return m_renderObjectSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetVisualizationPrepareSrg() const { return m_visualizationPrepareSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetVisualizationRayTraceSrg() const { return m_visualizationRayTraceSrg; }
// Srg updates
void UpdateRayTraceSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
@ -135,6 +147,8 @@ namespace AZ
void UpdateRelocationSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
void UpdateClassificationSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
void UpdateRenderObjectSrg();
void UpdateVisualizationPrepareSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
void UpdateVisualizationRayTraceSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout, const RHI::ImageView* outputImageView);
// textures
const RHI::Ptr<RHI::Image> GetRayTraceImage() { return m_rayTraceImage[m_currentImageIndex]; }
@ -151,12 +165,14 @@ namespace AZ
const RHI::AttachmentId GetIrradianceImageAttachmentId() const { return m_irradianceImageAttachmentId; }
const RHI::AttachmentId GetDistanceImageAttachmentId() const { return m_distanceImageAttachmentId; }
const RHI::AttachmentId GetProbeDataImageAttachmentId() const { return m_probeDataImageAttachmentId; }
const RHI::AttachmentId GetProbeVisualizationTlasAttachmentId() const { return m_visualizationTlasAttachmentId; }
const RHI::AttachmentId GetProbeVisualizationTlasInstancesAttachmentId() const { return m_visualizationTlasInstancesAttachmentId; }
const DiffuseProbeGridRenderData* GetRenderData() const { return m_renderData; }
// the irradiance image needs to be manually cleared after it is resized in the editor
bool GetIrradianceClearRequired() const { return m_irradianceClearRequired; }
void ResetIrradianceClearRequired() { m_irradianceClearRequired = false; }
// the Irradiance, Distance, and ProbeData images need to be manually cleared after certain operations, e.g., changing the grid size
bool GetTextureClearRequired() const { return m_textureClearRequired; }
void ResetTextureClearRequired() { m_textureClearRequired = false; }
// texture readback
DiffuseProbeGridTextureReadback& GetTextureReadback() { return m_textureReadback; }
@ -168,7 +184,16 @@ namespace AZ
static constexpr uint32_t DefaultNumDistanceTexels = 14;
static constexpr int32_t DefaultNumRelocationIterations = 100;
// visualization TLAS
const RHI::Ptr<RHI::RayTracingTlas>& GetVisualizationTlas() const { return m_visualizationTlas; }
RHI::Ptr<RHI::RayTracingTlas>& GetVisualizationTlas() { return m_visualizationTlas; }
bool GetVisualizationTlasUpdateRequired() const;
void ResetVisualizationTlasUpdateRequired() { m_visualizationTlasUpdateRequired = false; }
private:
// helper functions
void UpdateTextures();
void ComputeProbeCount(const AZ::Vector3& extents, const AZ::Vector3& probeSpacing, uint32_t& probeCountX, uint32_t& probeCountY, uint32_t& probeCountZ);
bool ValidateProbeCount(const AZ::Vector3& extents, const AZ::Vector3& probeSpacing);
@ -248,7 +273,7 @@ namespace AZ
RHI::Ptr<RHI::Image> m_probeDataImage[ImageFrameCount];
uint32_t m_currentImageIndex = 0;
bool m_updateTextures = false;
bool m_irradianceClearRequired = true;
bool m_textureClearRequired = true;
// baked textures
Data::Instance<RPI::Image> m_bakedIrradianceImage;
@ -281,6 +306,17 @@ namespace AZ
RHI::AttachmentId m_irradianceImageAttachmentId;
RHI::AttachmentId m_distanceImageAttachmentId;
RHI::AttachmentId m_probeDataImageAttachmentId;
// probe visualization
bool m_visualizationEnabled = false;
bool m_visualizationShowInactiveProbes = false;
float m_visualizationSphereRadius = 0.5f;
RHI::Ptr<RHI::RayTracingTlas> m_visualizationTlas;
bool m_visualizationTlasUpdateRequired = false;
RHI::AttachmentId m_visualizationTlasAttachmentId;
RHI::AttachmentId m_visualizationTlasInstancesAttachmentId;
Data::Instance<RPI::ShaderResourceGroup> m_visualizationPrepareSrg;
Data::Instance<RPI::ShaderResourceGroup> m_visualizationRayTraceSrg;
};
} // namespace Render
} // namespace AZ

@ -75,27 +75,34 @@ namespace AZ
}
}
void DiffuseProbeGridBlendDistancePass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridBlendDistancePass::IsEnabled() const
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBlendDistancePass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridBlendDistancePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)

@ -42,8 +42,7 @@ namespace AZ
void LoadShader();
// Pass overrides
void FrameBeginInternal(FramePrepareParams params) override;
bool IsEnabled() const override;
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;

@ -75,27 +75,34 @@ namespace AZ
}
}
void DiffuseProbeGridBlendIrradiancePass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridBlendIrradiancePass::IsEnabled() const
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBlendIrradiancePass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridBlendIrradiancePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)

@ -42,8 +42,7 @@ namespace AZ
void LoadShader();
// Pass overrides
void FrameBeginInternal(FramePrepareParams params) override;
bool IsEnabled() const override;
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;

@ -83,27 +83,34 @@ namespace AZ
}
}
void DiffuseProbeGridBorderUpdatePass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridBorderUpdatePass::IsEnabled() const
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBorderUpdatePass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridBorderUpdatePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)

@ -40,8 +40,7 @@ namespace AZ
RHI::DispatchDirect& dispatchArgs);
// Pass overrides
void FrameBeginInternal(FramePrepareParams params) override;
bool IsEnabled() const override;
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;

@ -79,27 +79,34 @@ namespace AZ
}
}
void DiffuseProbeGridClassificationPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridClassificationPass::IsEnabled() const
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridClassificationPass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridClassificationPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
@ -160,15 +167,11 @@ namespace AZ
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetClassificationSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
uint32_t probeCountX;
uint32_t probeCountY;
diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY);
RHI::DispatchItem dispatchItem;
dispatchItem.m_arguments = shader.m_dispatchArgs;
dispatchItem.m_pipelineState = shader.m_pipelineState;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = diffuseProbeGrid->GetTotalProbeCount();
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1;
commandList->Submit(dispatchItem);

@ -43,8 +43,7 @@ namespace AZ
void LoadShader();
// Pass overrides
void FrameBeginInternal(FramePrepareParams params) override;
bool IsEnabled() const override;
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;

@ -7,6 +7,7 @@
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@ -39,6 +40,7 @@ namespace AZ
void DiffuseProbeGridFeatureProcessor::Activate()
{
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
RHI::Ptr<RHI::Device> device = rhiSystem->GetDevice();
m_diffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
m_realTimeDiffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
@ -49,7 +51,7 @@ namespace AZ
m_bufferPool = RHI::Factory::Get().CreateBufferPool();
m_bufferPool->SetName(Name("DiffuseProbeGridBoxBufferPool"));
[[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(*rhiSystem->GetDevice(), desc);
[[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(*device, desc);
AZ_Error("DiffuseProbeGridFeatureProcessor", resultCode == RHI::ResultCode::Success, "Failed to initialize buffer pool");
// create box mesh vertices and indices
@ -61,7 +63,7 @@ namespace AZ
imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead;
m_probeGridRenderData.m_imagePool = RHI::Factory::Get().CreateImagePool();
[[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_imagePool->Init(*rhiSystem->GetDevice(), imagePoolDesc);
[[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_imagePool->Init(*device, imagePoolDesc);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize output image pool");
}
@ -90,6 +92,22 @@ namespace AZ
AZ_Error("DiffuseProbeGridFeatureProcessor", m_probeGridRenderData.m_srgLayout != nullptr, "Failed to find ObjectSrg layout");
}
// initialize the buffer pools for the DiffuseProbeGrid visualization
m_visualizationBufferPools = RHI::RayTracingBufferPools::CreateRHIRayTracingBufferPools();
m_visualizationBufferPools->Init(device);
// load probe visualization model, the BLAS will be created in OnAssetReady()
m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
"Models/DiffuseProbeSphere.azmodel",
AZ::RPI::AssetUtils::TraceLevel::Assert);
if (!m_visualizationModelAsset.IsReady())
{
m_visualizationModelAsset.QueueLoad();
}
Data::AssetBus::MultiHandler::BusConnect(m_visualizationModelAsset.GetId());
EnableSceneNotification();
}
@ -106,6 +124,8 @@ namespace AZ
{
m_bufferPool.reset();
}
Data::AssetBus::MultiHandler::BusDisconnect();
}
void DiffuseProbeGridFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
@ -186,14 +206,20 @@ namespace AZ
void DiffuseProbeGridFeatureProcessor::OnEndPrepareRender()
{
// re-build the list of visible real-time diffuse probe grids
// re-build the list of visible diffuse probe grids
m_visibleDiffuseProbeGrids.clear();
m_visibleRealTimeDiffuseProbeGrids.clear();
for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids)
for (auto& diffuseProbeGrid : m_diffuseProbeGrids)
{
if (diffuseProbeGrid->GetIsVisible())
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::RealTime)
{
m_visibleRealTimeDiffuseProbeGrids.push_back(diffuseProbeGrid);
}
m_visibleDiffuseProbeGrids.push_back(diffuseProbeGrid);
}
}
}
@ -237,6 +263,17 @@ namespace AZ
m_realTimeDiffuseProbeGrids.erase(itEntry);
}
// remove from side list of visible grids
itEntry = AZStd::find_if(m_visibleDiffuseProbeGrids.begin(), m_visibleDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
{
return (entry == probeGrid);
});
if (itEntry != m_visibleDiffuseProbeGrids.end())
{
m_visibleDiffuseProbeGrids.erase(itEntry);
}
// remove from side list of visible real-time grids
itEntry = AZStd::find_if(m_visibleRealTimeDiffuseProbeGrids.begin(), m_visibleRealTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
{
@ -449,6 +486,24 @@ namespace AZ
probeGrid->SetBakedTextures(bakedTextures);
}
void DiffuseProbeGridFeatureProcessor::SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled)
{
AZ_Assert(probeGrid.get(), "SetVisualizationEnabled called with an invalid handle");
probeGrid->SetVisualizationEnabled(visualizationEnabled);
}
void DiffuseProbeGridFeatureProcessor::SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes)
{
AZ_Assert(probeGrid.get(), "SetVisualizationShowInactiveProbes called with an invalid handle");
probeGrid->SetVisualizationShowInactiveProbes(visualizationShowInactiveProbes);
}
void DiffuseProbeGridFeatureProcessor::SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius)
{
AZ_Assert(probeGrid.get(), "SetVisualizationSphereRadius called with an invalid handle");
probeGrid->SetVisualizationSphereRadius(visualizationSphereRadius);
}
void DiffuseProbeGridFeatureProcessor::CreateBoxMesh()
{
// vertex positions
@ -613,6 +668,71 @@ namespace AZ
}
}
void DiffuseProbeGridFeatureProcessor::OnVisualizationModelAssetReady(Data::Asset<Data::AssetData> asset)
{
Data::Asset<RPI::ModelAsset> modelAsset = asset;
m_visualizationModel = RPI::Model::FindOrCreate(modelAsset);
AZ_Assert(m_visualizationModel.get(), "Failed to load DiffuseProbeGrid visualization model");
const AZStd::span<const Data::Instance<RPI::ModelLod>>& modelLods = m_visualizationModel->GetLods();
AZ_Assert(!modelLods.empty(), "Invalid DiffuseProbeGrid visualization model");
if (modelLods.empty())
{
return;
}
const Data::Instance<RPI::ModelLod>& modelLod = modelLods[0];
AZ_Assert(!modelLod->GetMeshes().empty(), "Invalid DiffuseProbeGrid visualization model asset");
if (modelLod->GetMeshes().empty())
{
return;
}
const RPI::ModelLod::Mesh& mesh = modelLod->GetMeshes()[0];
// setup a stream layout and shader input contract for the position vertex stream
static const char* PositionSemantic = "POSITION";
static const RHI::Format PositionStreamFormat = RHI::Format::R32G32B32_FLOAT;
RHI::InputStreamLayoutBuilder layoutBuilder;
layoutBuilder.AddBuffer()->Channel(PositionSemantic, PositionStreamFormat);
RHI::InputStreamLayout inputStreamLayout = layoutBuilder.End();
RPI::ShaderInputContract::StreamChannelInfo positionStreamChannelInfo;
positionStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(PositionSemantic));
positionStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(PositionStreamFormat);
RPI::ShaderInputContract shaderInputContract;
shaderInputContract.m_streamChannels.emplace_back(positionStreamChannelInfo);
// retrieve vertex/index buffers
RPI::ModelLod::StreamBufferViewList streamBufferViews;
[[maybe_unused]] bool result = modelLod->GetStreamsForMesh(
inputStreamLayout,
streamBufferViews,
nullptr,
shaderInputContract,
0);
AZ_Assert(result, "Failed to retrieve DiffuseProbeGrid visualization mesh stream buffer views");
m_visualizationVB = streamBufferViews[0];
m_visualizationIB = mesh.m_indexBufferView;
// create the BLAS object
RHI::RayTracingBlasDescriptor blasDescriptor;
blasDescriptor.Build()
->Geometry()
->VertexFormat(PositionStreamFormat)
->VertexBuffer(m_visualizationVB)
->IndexBuffer(m_visualizationIB)
;
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
m_visualizationBlas = AZ::RHI::RayTracingBlas::CreateRHIRayTracingBlas();
m_visualizationBlas->CreateBuffers(*device, &blasDescriptor, *m_visualizationBufferPools);
}
void DiffuseProbeGridFeatureProcessor::HandleAssetNotification(Data::Asset<Data::AssetData> asset, DiffuseProbeGridTextureNotificationType notificationType)
{
for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
@ -632,15 +752,29 @@ namespace AZ
}
void DiffuseProbeGridFeatureProcessor::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
if (asset.GetId() == m_visualizationModelAsset.GetId())
{
OnVisualizationModelAssetReady(asset);
}
else
{
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready);
}
}
void DiffuseProbeGridFeatureProcessor::OnAssetError(Data::Asset<Data::AssetData> asset)
{
AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str());
if (asset.GetId() == m_visualizationModelAsset.GetId())
{
AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load probe visualization model asset [%s]", asset.GetHint().c_str());
}
else
{
AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str());
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Error);
}
}
} // namespace Render
} // namespace AZ

@ -9,6 +9,9 @@
#pragma once
#include <Atom/Feature/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessorInterface.h>
#include <Atom/RHI/RayTracingBufferPools.h>
#include <Atom/RHI/RayTracingAccelerationStructure.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGrid.h>
namespace AZ
@ -46,6 +49,9 @@ namespace AZ
void SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl) override;
void SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode) override;
void SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures) override;
void SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled) override;
void SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes) override;
void SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius) override;
void BakeTextures(
const DiffuseProbeGridHandle& probeGrid,
@ -76,9 +82,19 @@ namespace AZ
// retrieve the side list of probe grids that are using real-time (raytraced) mode
DiffuseProbeGridVector& GetRealTimeProbeGrids() { return m_realTimeDiffuseProbeGrids; }
// retrieve the side list of probe grids that are using real-time (raytraced) mode and visible (on screen)
// retrieve the side list of probe grids that are visible (on screen), both real-time (raytraced) and baked
DiffuseProbeGridVector& GetVisibleProbeGrids() { return m_visibleDiffuseProbeGrids; }
// retrieve the side list of probe grids that are real-time (raytraced) and visible (on screen)
DiffuseProbeGridVector& GetVisibleRealTimeProbeGrids() { return m_visibleRealTimeDiffuseProbeGrids; }
// returns the RayTracingBufferPool used for the DiffuseProbeGrid visualization
RHI::RayTracingBufferPools& GetVisualizationBufferPools() { return *m_visualizationBufferPools; }
// returns the RayTracingBlas for the visualization model
const RHI::Ptr<RHI::RayTracingBlas>& GetVisualizationBlas() const { return m_visualizationBlas; }
RHI::Ptr<RHI::RayTracingBlas>& GetVisualizationBlas() { return m_visualizationBlas; }
private:
AZ_DISABLE_COPY_MOVE(DiffuseProbeGridFeatureProcessor);
@ -108,6 +124,9 @@ namespace AZ
void UpdatePipelineStates();
void UpdatePasses();
// loads the probe visualization model and creates the BLAS
void OnVisualizationModelAssetReady(Data::Asset<Data::AssetData> asset);
// list of all diffuse probe grids
const size_t InitialProbeGridAllocationSize = 64;
DiffuseProbeGridVector m_diffuseProbeGrids;
@ -115,6 +134,9 @@ namespace AZ
// side list of diffuse probe grids that are in real-time mode (subset of m_diffuseProbeGrids)
DiffuseProbeGridVector m_realTimeDiffuseProbeGrids;
// side list of diffuse probe grids that are visible, both real-time and baked modes (subset of m_diffuseProbeGrids)
DiffuseProbeGridVector m_visibleDiffuseProbeGrids;
// side list of diffuse probe grids that are in real-time mode and visible (subset of m_realTimeDiffuseProbeGrids)
DiffuseProbeGridVector m_visibleRealTimeDiffuseProbeGrids;
@ -157,6 +179,14 @@ namespace AZ
};
typedef AZStd::vector<NotifyTextureAssetEntry> NotifyTextureAssetVector;
NotifyTextureAssetVector m_notifyTextureAssets;
// visualization
RHI::Ptr<RHI::RayTracingBufferPools> m_visualizationBufferPools;
Data::Asset<RPI::ModelAsset> m_visualizationModelAsset;
RHI::Ptr<RHI::RayTracingBlas> m_visualizationBlas;
Data::Instance<RPI::Model> m_visualizationModel;
RHI::StreamBufferView m_visualizationVB;
RHI::IndexBufferView m_visualizationIB;
};
} // namespace Render
} // namespace AZ

@ -107,15 +107,40 @@ namespace AZ
m_rayTracingPipelineState->Init(*device.get(), &descriptor);
}
void DiffuseProbeGridRayTracingPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridRayTracingPass::IsEnabled() const
{
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
if (!rayTracingFeatureProcessor)
{
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
return true;
}
void DiffuseProbeGridRayTracingPass::FrameBeginInternal(FramePrepareParams params)
{
RPI::Scene* scene = m_pipeline->GetScene();
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
if (!m_initialized)
{
CreateRayTracingPipelineState();
@ -131,13 +156,6 @@ namespace AZ
m_rayTracingShaderTable->Init(*device.get(), rayTracingBufferPools);
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
}
RenderPass::FrameBeginInternal(params);
}
@ -156,9 +174,16 @@ namespace AZ
// TLAS
{
AZ::RHI::AttachmentId tlasAttachmentId = rayTracingFeatureProcessor->GetTlasAttachmentId();
if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(tlasAttachmentId))
const RHI::Ptr<RHI::Buffer>& rayTracingTlasBuffer = rayTracingFeatureProcessor->GetTlas()->GetTlasBuffer();
if (rayTracingTlasBuffer)
{
uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(rayTracingFeatureProcessor->GetTlas()->GetTlasBuffer()->GetDescriptor().m_byteCount);
if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(tlasAttachmentId))
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(tlasAttachmentId, rayTracingTlasBuffer);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import ray tracing TLAS buffer with error %d", result);
}
uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(rayTracingTlasBuffer->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor tlasBufferViewDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, tlasBufferByteCount);
RHI::BufferScopeAttachmentDescriptor desc;
@ -191,10 +216,10 @@ namespace AZ
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetIrradianceImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeIrradianceImageViewDescriptor;
if (diffuseProbeGrid->GetIrradianceClearRequired())
if (diffuseProbeGrid->GetTextureClearRequired())
{
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear;
diffuseProbeGrid->ResetIrradianceClearRequired();
}
else
{
@ -212,7 +237,15 @@ namespace AZ
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetDistanceImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDistanceImageViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare;
if (diffuseProbeGrid->GetTextureClearRequired())
{
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear;
}
else
{
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
}
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite);
}
@ -225,10 +258,20 @@ namespace AZ
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetProbeDataImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDataImageViewDescriptor;
if (diffuseProbeGrid->GetTextureClearRequired())
{
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear;
}
else
{
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
}
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite);
}
diffuseProbeGrid->ResetTextureClearRequired();
}
}

@ -45,6 +45,7 @@ namespace AZ
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
// Pass overrides
bool IsEnabled() const override;
void FrameBeginInternal(FramePrepareParams params) override;
// revision number of the ray tracing TLAS when the shader table was built

@ -74,49 +74,70 @@ namespace AZ
}
}
void DiffuseProbeGridRelocationPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridRelocationPass::IsEnabled() const
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridRelocationPass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
// create the Relocation Srgs for each DiffuseProbeGrid, and check to see if any grids need relocation
bool needRelocation = false;
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids())
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
// check TLAS version
uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision();
if (rayTracingDataRevision != m_rayTracingDataRevision)
{
// the TLAS changed, relocate probes
m_rayTracingDataRevision = rayTracingDataRevision;
diffuseProbeGrid->ResetRemainingRelocationIterations();
return true;
}
// check to see if any grids need relocation
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids())
{
if (diffuseProbeGrid->GetRemainingRelocationIterations() > 0)
{
needRelocation = true;
return true;
}
}
if (!needRelocation)
return false;
}
void DiffuseProbeGridRelocationPass::FrameBeginInternal(FramePrepareParams params)
{
// no diffuseProbeGrids require relocation, this pass can be skipped entirely
return;
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridRelocationPass requires the RayTracingFeatureProcessor");
// reset the relocation iterations on the grids if the TLAS was updated
uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision();
if (rayTracingDataRevision != m_rayTracingDataRevision)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids())
{
diffuseProbeGrid->ResetRemainingRelocationIterations();
}
}
m_rayTracingDataRevision = rayTracingDataRevision;
RenderPass::FrameBeginInternal(params);
}
@ -160,11 +181,7 @@ namespace AZ
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() in ShaderResourceGroupData.cpp)
diffuseProbeGrid->UpdateRelocationSrg(m_shader, m_srgLayout);
diffuseProbeGrid->GetRelocationSrg()->Compile();
// relocation stops after a limited number of iterations
diffuseProbeGrid->DecrementRemainingRelocationIterations();
}
}
@ -180,19 +197,30 @@ namespace AZ
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetRelocationSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
uint32_t probeCountX;
uint32_t probeCountY;
diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY);
RHI::DispatchItem dispatchItem;
dispatchItem.m_arguments = m_dispatchArgs;
dispatchItem.m_pipelineState = m_pipelineState;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = diffuseProbeGrid->GetTotalProbeCount();
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1;
commandList->Submit(dispatchItem);
}
}
void DiffuseProbeGridRelocationPass::FrameEndInternal()
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// submit the DispatchItems for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids())
{
// relocation stops after a limited number of iterations
diffuseProbeGrid->DecrementRemainingRelocationIterations();
}
RenderPass::FrameEndInternal();
}
} // namespace Render
} // namespace AZ

@ -42,11 +42,12 @@ namespace AZ
void LoadShader();
// Pass overrides
bool IsEnabled() const override;
void FrameBeginInternal(FramePrepareParams params) override;
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
void FrameEndInternal() override;
// shader
Data::Instance<RPI::Shader> m_shader;

@ -51,18 +51,35 @@ namespace AZ
AZ_Assert(m_shaderResourceGroup, "[DiffuseProbeGridRenderPass '%s']: Failed to create SRG", GetPathName().GetCStr());
}
void DiffuseProbeGridRenderPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridRenderPass::IsEnabled() const
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!scene)
{
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
{
// no diffuse probe grids
return;
return false;
}
return true;
}
void DiffuseProbeGridRenderPass::FrameBeginInternal(FramePrepareParams params)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// get output attachment size
AZ_Assert(GetInputOutputCount() > 0, "DiffuseProbeGridRenderPass: Could not find output bindings");
RPI::PassAttachment* m_outputAttachment = GetInputOutputBinding(0).m_attachment.get();

@ -36,7 +36,8 @@ namespace AZ
explicit DiffuseProbeGridRenderPass(const RPI::PassDescriptor& descriptor);
// Pass behavior overrides...
virtual void FrameBeginInternal(FramePrepareParams params) override;
bool IsEnabled() const override;
void FrameBeginInternal(FramePrepareParams params) override;
// Scope producer functions...
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;

@ -0,0 +1,192 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RHI/FrameScheduler.h>
#include <Atom/RHI/CommandList.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h>
#include <RayTracing/RayTracingFeatureProcessor.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationAccelerationStructurePass> DiffuseProbeGridVisualizationAccelerationStructurePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationAccelerationStructurePass> diffuseProbeGridVisualizationAccelerationStructurePass = aznew DiffuseProbeGridVisualizationAccelerationStructurePass(descriptor);
return AZStd::move(diffuseProbeGridVisualizationAccelerationStructurePass);
}
DiffuseProbeGridVisualizationAccelerationStructurePass::DiffuseProbeGridVisualizationAccelerationStructurePass(const RPI::PassDescriptor& descriptor)
: Pass(descriptor)
{
// disable this pass if we're on a platform that doesn't support raytracing
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
if (device->GetFeatures().m_rayTracing == false || !AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED)
{
SetEnabled(false);
}
}
bool DiffuseProbeGridVisualizationAccelerationStructurePass::ShouldUpdate(const AZStd::shared_ptr<DiffuseProbeGrid>& diffuseProbeGrid) const
{
return (diffuseProbeGrid->GetVisualizationEnabled() && diffuseProbeGrid->GetVisualizationTlasUpdateRequired());
}
bool DiffuseProbeGridVisualizationAccelerationStructurePass::IsEnabled() const
{
if (!Pass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (diffuseProbeGridFeatureProcessor)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (ShouldUpdate(diffuseProbeGrid))
{
return true;
}
}
}
return false;
}
void DiffuseProbeGridVisualizationAccelerationStructurePass::BuildInternal()
{
SetScopeId(RHI::ScopeId(GetPathName()));
}
void DiffuseProbeGridVisualizationAccelerationStructurePass::FrameBeginInternal(FramePrepareParams params)
{
params.m_frameGraphBuilder->ImportScopeProducer(*this);
}
void DiffuseProbeGridVisualizationAccelerationStructurePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// import and attach the visualization TLAS buffers
RHI::Ptr<RHI::RayTracingTlas>& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas();
const RHI::Ptr<RHI::Buffer>& tlasBuffer = visualizationTlas->GetTlasBuffer();
const RHI::Ptr<RHI::Buffer>& tlasInstancesBuffer = visualizationTlas->GetTlasInstancesBuffer();
if (tlasBuffer && tlasInstancesBuffer)
{
// TLAS buffer
{
AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId();
if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false)
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasBuffer);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS buffer with error %d", result);
}
uint32_t byteCount = aznumeric_cast<uint32_t>(tlasBuffer->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(byteCount);
RHI::BufferScopeAttachmentDescriptor desc;
desc.m_attachmentId = attachmentId;
desc.m_bufferViewDescriptor = bufferViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Write);
}
// TLAS Instances buffer
{
AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasInstancesAttachmentId();
if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false)
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasInstancesBuffer);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS Instances buffer with error %d", result);
}
uint32_t byteCount = aznumeric_cast<uint32_t>(tlasInstancesBuffer->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, byteCount / RayTracingTlasInstanceElementSize, RayTracingTlasInstanceElementSize);
RHI::BufferScopeAttachmentDescriptor desc;
desc.m_attachmentId = attachmentId;
desc.m_bufferViewDescriptor = bufferViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read);
}
}
}
}
void DiffuseProbeGridVisualizationAccelerationStructurePass::BuildCommandList(const RHI::FrameGraphExecuteContext& context)
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// build the visualization BLAS from the DiffuseProbeGridFeatureProcessor
// Note: the BLAS is used by all DiffuseProbeGrid visualization TLAS objects
if (m_visualizationBlasBuilt == false)
{
context.GetCommandList()->BuildBottomLevelAccelerationStructure(*diffuseProbeGridFeatureProcessor->GetVisualizationBlas());
m_visualizationBlasBuilt = true;
}
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
if (!diffuseProbeGrid->GetVisualizationTlas()->GetTlasBuffer())
{
continue;
}
// build the TLAS object
context.GetCommandList()->BuildTopLevelAccelerationStructure(*diffuseProbeGrid->GetVisualizationTlas());
}
}
void DiffuseProbeGridVisualizationAccelerationStructurePass::FrameEndInternal()
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// TLAS is now updated
diffuseProbeGrid->ResetVisualizationTlasUpdateRequired();
}
}
} // namespace RPI
} // namespace AZ

@ -0,0 +1,53 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RHI/ScopeProducer.h>
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Buffer/Buffer.h>
#include <Atom/RHI/RayTracingBufferPools.h>
namespace AZ
{
namespace Render
{
//! This pass builds the DiffuseProbeGrid visualization acceleration structure
class DiffuseProbeGridVisualizationAccelerationStructurePass final
: public RPI::Pass
, public RHI::ScopeProducer
{
public:
AZ_RPI_PASS(DiffuseProbeGridVisualizationAccelerationStructurePass);
AZ_RTTI(DiffuseProbeGridVisualizationAccelerationStructurePass, "{103D8917-D4DC-4CA3-BFB4-CD62846D282A}", Pass);
AZ_CLASS_ALLOCATOR(DiffuseProbeGridVisualizationAccelerationStructurePass, SystemAllocator, 0);
//! Creates a DiffuseProbeGridVisualizationAccelerationStructurePass
static RPI::Ptr<DiffuseProbeGridVisualizationAccelerationStructurePass> Create(const RPI::PassDescriptor& descriptor);
~DiffuseProbeGridVisualizationAccelerationStructurePass() = default;
private:
explicit DiffuseProbeGridVisualizationAccelerationStructurePass(const RPI::PassDescriptor& descriptor);
bool ShouldUpdate(const AZStd::shared_ptr<DiffuseProbeGrid>& diffuseProbeGrid) const;
// Scope producer functions
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void BuildCommandList(const RHI::FrameGraphExecuteContext& context) override;
// Pass overrides
bool IsEnabled() const override;
void BuildInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
void FrameEndInternal() override;
bool m_visualizationBlasBuilt = false;
};
} // namespace RPI
} // namespace AZ

@ -0,0 +1,62 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationCompositePass> DiffuseProbeGridVisualizationCompositePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationCompositePass> pass = aznew DiffuseProbeGridVisualizationCompositePass(descriptor);
return AZStd::move(pass);
}
DiffuseProbeGridVisualizationCompositePass::DiffuseProbeGridVisualizationCompositePass(const RPI::PassDescriptor& descriptor)
: RPI::FullscreenTrianglePass(descriptor)
{
if (!AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED)
{
SetEnabled(false);
}
}
bool DiffuseProbeGridVisualizationCompositePass::IsEnabled() const
{
if (!FullscreenTrianglePass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (diffuseProbeGridFeatureProcessor)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (diffuseProbeGrid->GetVisualizationEnabled())
{
return true;
}
}
}
return false;
}
} // namespace RPI
} // namespace AZ

@ -0,0 +1,39 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
namespace AZ
{
namespace Render
{
//! This pass composites the DiffuseProbeGrid visualization image onto the main scene
class DiffuseProbeGridVisualizationCompositePass
: public RPI::FullscreenTrianglePass
{
public:
AZ_RPI_PASS(DiffuseProbeGridVisualizationCompositePass);
AZ_RTTI(Render::DiffuseProbeGridVisualizationCompositePass, "{64BD5779-AB30-41C1-81B7-B93D864355E5}", RPI::FullscreenTrianglePass);
AZ_CLASS_ALLOCATOR(Render::DiffuseProbeGridVisualizationCompositePass, SystemAllocator, 0);
//! Creates a new pass without a PassTemplate
static RPI::Ptr<DiffuseProbeGridVisualizationCompositePass> Create(const RPI::PassDescriptor& descriptor);
~DiffuseProbeGridVisualizationCompositePass() = default;
private:
explicit DiffuseProbeGridVisualizationCompositePass(const RPI::PassDescriptor& descriptor);
// Pass behavior overrides...
bool IsEnabled() const override;
};
} // namespace RPI
} // namespace AZ

@ -0,0 +1,270 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RHI/CommandList.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h>
#include <RayTracing/RayTracingFeatureProcessor.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationPreparePass> DiffuseProbeGridVisualizationPreparePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationPreparePass> diffuseProbeGridVisualizationPreparePass = aznew DiffuseProbeGridVisualizationPreparePass(descriptor);
return AZStd::move(diffuseProbeGridVisualizationPreparePass);
}
DiffuseProbeGridVisualizationPreparePass::DiffuseProbeGridVisualizationPreparePass(const RPI::PassDescriptor& descriptor)
: RenderPass(descriptor)
{
// disable this pass if we're on a platform that doesn't support raytracing
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
if (device->GetFeatures().m_rayTracing == false || !AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED)
{
SetEnabled(false);
}
else
{
LoadShader();
}
}
void DiffuseProbeGridVisualizationPreparePass::LoadShader()
{
// load shaders
// Note: the shader may not be available on all platforms
AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPrepare.azshader";
m_shader = RPI::LoadCriticalShader(shaderFilePath);
if (m_shader == nullptr)
{
return;
}
RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor;
const auto& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor);
AZ_Assert(m_pipelineState, "Failed to acquire pipeline state");
m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass);
AZ_Assert(m_srgLayout.get(), "Failed to find Srg layout");
const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs);
if (!outcome.IsSuccess())
{
AZ_Error("PassSystem", false, "[DiffuseProbeGridVisualizationPreparePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str());
}
}
bool DiffuseProbeGridVisualizationPreparePass::ShouldUpdate(const AZStd::shared_ptr<DiffuseProbeGrid>& diffuseProbeGrid) const
{
return (diffuseProbeGrid->GetVisualizationEnabled() && diffuseProbeGrid->GetVisualizationTlasUpdateRequired());
}
bool DiffuseProbeGridVisualizationPreparePass::IsEnabled() const
{
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (diffuseProbeGridFeatureProcessor)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (ShouldUpdate(diffuseProbeGrid))
{
return true;
}
}
}
return false;
}
void DiffuseProbeGridVisualizationPreparePass::FrameBeginInternal(FramePrepareParams params)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// create the TLAS descriptor by adding an instance entry for each probe in the grid
RHI::RayTracingTlasDescriptor tlasDescriptor;
RHI::RayTracingTlasDescriptor* tlasDescriptorBuild = tlasDescriptor.Build();
// initialize the transform for each probe to Identity(), they will be updated by the compute shader
AZ::Transform transform = AZ::Transform::Identity();
uint32_t probeCount = diffuseProbeGrid->GetTotalProbeCount();
for (uint32_t index = 0; index < probeCount; ++index)
{
tlasDescriptorBuild->Instance()
->InstanceID(index)
->HitGroupIndex(0)
->Blas(diffuseProbeGridFeatureProcessor->GetVisualizationBlas())
->Transform(transform)
;
}
// create the TLAS buffers from on the descriptor
RHI::Ptr<RHI::RayTracingTlas>& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas();
visualizationTlas->CreateBuffers(*device, &tlasDescriptor, diffuseProbeGridFeatureProcessor->GetVisualizationBufferPools());
}
RenderPass::FrameBeginInternal(params);
}
void DiffuseProbeGridVisualizationPreparePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
{
RenderPass::SetupFrameGraphDependencies(frameGraph);
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// import and attach the visualization TLAS and probe data
RHI::Ptr<RHI::RayTracingTlas>& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas();
const RHI::Ptr<RHI::Buffer>& tlasBuffer = visualizationTlas->GetTlasBuffer();
const RHI::Ptr<RHI::Buffer>& tlasInstancesBuffer = visualizationTlas->GetTlasInstancesBuffer();
if (tlasBuffer && tlasInstancesBuffer)
{
// TLAS buffer
{
AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId();
if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false)
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasBuffer);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS buffer with error %d", result);
}
uint32_t byteCount = aznumeric_cast<uint32_t>(tlasBuffer->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(byteCount);
RHI::BufferScopeAttachmentDescriptor desc;
desc.m_attachmentId = attachmentId;
desc.m_bufferViewDescriptor = bufferViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Write);
}
// TLAS Instances buffer
{
AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasInstancesAttachmentId();
if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false)
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasInstancesBuffer);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS Instances buffer with error %d", result);
}
uint32_t byteCount = aznumeric_cast<uint32_t>(tlasInstancesBuffer->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, byteCount / RayTracingTlasInstanceElementSize, RayTracingTlasInstanceElementSize);
RHI::BufferScopeAttachmentDescriptor desc;
desc.m_attachmentId = attachmentId;
desc.m_bufferViewDescriptor = bufferViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Write);
}
// probe data
{
AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeDataImageAttachmentId();
if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false)
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(attachmentId, diffuseProbeGrid->GetProbeDataImage());
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid probe data buffer with error %d", result);
}
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = attachmentId;
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDataImageViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read);
}
}
}
}
void DiffuseProbeGridVisualizationPreparePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context)
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// the DiffuseProbeGrid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() in ShaderResourceGroupData.cpp)
diffuseProbeGrid->UpdateVisualizationPrepareSrg(m_shader, m_srgLayout);
diffuseProbeGrid->GetVisualizationPrepareSrg()->Compile();
}
}
void DiffuseProbeGridVisualizationPreparePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
{
RHI::CommandList* commandList = context.GetCommandList();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetVisualizationPrepareSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
RHI::DispatchItem dispatchItem;
dispatchItem.m_arguments = m_dispatchArgs;
dispatchItem.m_pipelineState = m_pipelineState;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = diffuseProbeGrid->GetTotalProbeCount();
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1;
dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1;
commandList->Submit(dispatchItem);
}
}
} // namespace RPI
} // namespace AZ

@ -0,0 +1,52 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI.Public/Pass/RenderPass.h>
#include <Atom/RPI.Public/Shader/Shader.h>
namespace AZ
{
namespace Render
{
//! This pass updates the DiffuseProbeGrid visualization TLAS instances buffer
class DiffuseProbeGridVisualizationPreparePass final
: public RPI::RenderPass
{
public:
AZ_RPI_PASS(DiffuseProbeGridVisualizationPreparePass);
AZ_RTTI(DiffuseProbeGridVisualizationPreparePass, "{33BD769D-378B-4142-8C11-6A2ADA2BB095}", Pass);
AZ_CLASS_ALLOCATOR(DiffuseProbeGridVisualizationPreparePass, SystemAllocator, 0);
//! Creates a DiffuseProbeGridVisualizationPreparePass
static RPI::Ptr<DiffuseProbeGridVisualizationPreparePass> Create(const RPI::PassDescriptor& descriptor);
~DiffuseProbeGridVisualizationPreparePass() = default;
private:
explicit DiffuseProbeGridVisualizationPreparePass(const RPI::PassDescriptor& descriptor);
void LoadShader();
bool ShouldUpdate(const AZStd::shared_ptr<DiffuseProbeGrid>& diffuseProbeGrid) const;
// Pass overrides
bool IsEnabled() const override;
void FrameBeginInternal(FramePrepareParams params) override;
void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override;
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
// shader
Data::Instance<RPI::Shader> m_shader;
const RHI::PipelineState* m_pipelineState = nullptr;
RHI::Ptr<RHI::ShaderResourceGroupLayout> m_srgLayout;
RHI::DispatchDirect m_dispatchArgs;
};
} // namespace RPI
} // namespace AZ

@ -0,0 +1,300 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RHI/CommandList.h>
#include <Atom/RHI/DispatchRaysItem.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/View.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationRayTracingPass> DiffuseProbeGridVisualizationRayTracingPass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationRayTracingPass> pass = aznew DiffuseProbeGridVisualizationRayTracingPass(descriptor);
return AZStd::move(pass);
}
DiffuseProbeGridVisualizationRayTracingPass::DiffuseProbeGridVisualizationRayTracingPass(const RPI::PassDescriptor& descriptor)
: RPI::RenderPass(descriptor)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
if (device->GetFeatures().m_rayTracing == false || !AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED)
{
// raytracing or GI is not supported on this platform
SetEnabled(false);
}
}
void DiffuseProbeGridVisualizationRayTracingPass::CreateRayTracingPipelineState()
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
// load the ray tracing shader
// Note: the shader may not be available on all platforms
AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracing.azshader";
m_rayTracingShader = RPI::LoadCriticalShader(shaderFilePath);
if (m_rayTracingShader == nullptr)
{
return;
}
auto shaderVariant = m_rayTracingShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
RHI::PipelineStateDescriptorForRayTracing rayGenerationShaderDescriptor;
shaderVariant.ConfigurePipelineState(rayGenerationShaderDescriptor);
// closest hit shader
AZStd::string closestHitShaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingClosestHit.azshader";
m_closestHitShader = RPI::LoadCriticalShader(closestHitShaderFilePath);
auto closestHitShaderVariant = m_closestHitShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
RHI::PipelineStateDescriptorForRayTracing closestHitShaderDescriptor;
closestHitShaderVariant.ConfigurePipelineState(closestHitShaderDescriptor);
// miss shader
AZStd::string missShaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingMiss.azshader";
m_missShader = RPI::LoadCriticalShader(missShaderFilePath);
auto missShaderVariant = m_missShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
RHI::PipelineStateDescriptorForRayTracing missShaderDescriptor;
missShaderVariant.ConfigurePipelineState(missShaderDescriptor);
// global pipeline state and Srg
m_globalPipelineState = m_rayTracingShader->AcquirePipelineState(rayGenerationShaderDescriptor);
AZ_Assert(m_globalPipelineState, "Failed to acquire ray tracing global pipeline state");
m_globalSrgLayout = m_rayTracingShader->FindShaderResourceGroupLayout(Name{ "RayTracingGlobalSrg" });
AZ_Assert(m_globalSrgLayout != nullptr, "Failed to find RayTracingGlobalSrg layout for shader [%s]", shaderFilePath.c_str());
// build the ray tracing pipeline state descriptor
RHI::RayTracingPipelineStateDescriptor descriptor;
descriptor.Build()
->PipelineState(m_globalPipelineState.get())
->MaxPayloadSize(64)
->MaxAttributeSize(32)
->MaxRecursionDepth(2)
->ShaderLibrary(rayGenerationShaderDescriptor)
->RayGenerationShaderName(AZ::Name("RayGen"))
->ShaderLibrary(missShaderDescriptor)
->MissShaderName(AZ::Name("Miss"))
->ShaderLibrary(closestHitShaderDescriptor)
->ClosestHitShaderName(AZ::Name("ClosestHit"))
->HitGroup(AZ::Name("HitGroup"))
->ClosestHitShaderName(AZ::Name("ClosestHit"));
// create the ray tracing pipeline state object
m_rayTracingPipelineState = RHI::Factory::Get().CreateRayTracingPipelineState();
m_rayTracingPipelineState->Init(*device.get(), &descriptor);
}
bool DiffuseProbeGridVisualizationRayTracingPass::IsEnabled() const
{
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (diffuseProbeGridFeatureProcessor)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (diffuseProbeGrid->GetVisualizationEnabled())
{
return true;
}
}
}
return false;
}
void DiffuseProbeGridVisualizationRayTracingPass::FrameBeginInternal(FramePrepareParams params)
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!m_initialized)
{
CreateRayTracingPipelineState();
m_initialized = true;
}
if (!m_rayTracingShaderTable)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RHI::RayTracingBufferPools& rayTracingBufferPools = diffuseProbeGridFeatureProcessor->GetVisualizationBufferPools();
m_rayTracingShaderTable = RHI::Factory::Get().CreateRayTracingShaderTable();
m_rayTracingShaderTable->Init(*device.get(), rayTracingBufferPools);
AZStd::shared_ptr<RHI::RayTracingShaderTableDescriptor> descriptor = AZStd::make_shared<RHI::RayTracingShaderTableDescriptor>();
// build the ray tracing shader table descriptor
descriptor->Build(AZ::Name("RayTracingShaderTable"), m_rayTracingPipelineState)
->RayGenerationRecord(AZ::Name("RayGen"))
->MissRecord(AZ::Name("Miss"))
->HitGroupRecord(AZ::Name("HitGroup"))
;
m_rayTracingShaderTable->Build(descriptor);
}
RenderPass::FrameBeginInternal(params);
}
void DiffuseProbeGridVisualizationRayTracingPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
{
RenderPass::SetupFrameGraphDependencies(frameGraph);
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!diffuseProbeGrid->GetVisualizationEnabled())
{
continue;
}
// TLAS
{
AZ::RHI::AttachmentId tlasAttachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId();
const RHI::Ptr<RHI::Buffer>& visualizationTlasBuffer = diffuseProbeGrid->GetVisualizationTlas()->GetTlasBuffer();
if (visualizationTlasBuffer)
{
if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(tlasAttachmentId))
{
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(tlasAttachmentId, visualizationTlasBuffer);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import ray tracing TLAS buffer with error %d", result);
}
uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(visualizationTlasBuffer->GetDescriptor().m_byteCount);
RHI::BufferViewDescriptor tlasBufferViewDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, tlasBufferByteCount);
RHI::BufferScopeAttachmentDescriptor desc;
desc.m_attachmentId = tlasAttachmentId;
desc.m_bufferViewDescriptor = tlasBufferViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite);
}
}
// probe irradiance
{
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetIrradianceImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeIrradianceImageViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read);
}
// probe distance
{
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetDistanceImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDistanceImageViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read);
}
// probe data
{
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetProbeDataImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDataImageViewDescriptor;
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read);
}
}
// retrieve the visualization image size, this will determine the number of rays to cast
RPI::Ptr<RPI::PassAttachment> visualizationImageAttachment = m_ownedAttachments[0];
AZ_Assert(visualizationImageAttachment.get(), "Invalid DiffuseProbeGrid Visualization image");
m_outputAttachmentSize = visualizationImageAttachment->GetTransientImageDescriptor().m_imageDescriptor.m_size;
}
void DiffuseProbeGridVisualizationRayTracingPass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context)
{
const RHI::ImageView* outputImageView = context.GetImageView(GetOutputBinding(0).m_attachment->GetAttachmentId());
AZ_Assert(outputImageView, "Failed to retrieve output ImageView");
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!diffuseProbeGrid->GetVisualizationEnabled())
{
continue;
}
// the DiffuseProbeGridVisualization Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader
// inputs (see line ValidateSetImageView() in ShaderResourceGroupData.cpp)
diffuseProbeGrid->UpdateVisualizationRayTraceSrg(m_rayTracingShader, m_globalSrgLayout, outputImageView);
diffuseProbeGrid->GetVisualizationRayTraceSrg()->Compile();
}
}
void DiffuseProbeGridVisualizationRayTracingPass::BuildCommandListInternal([[maybe_unused]] const RHI::FrameGraphExecuteContext& context)
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
const AZStd::vector<RPI::ViewPtr>& views = m_pipeline->GetViews(RPI::PipelineViewTag{ "MainCamera" });
if (views.empty())
{
return;
}
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!diffuseProbeGrid->GetVisualizationEnabled())
{
continue;
}
const RHI::ShaderResourceGroup* shaderResourceGroups[] = {
diffuseProbeGrid->GetVisualizationRayTraceSrg()->GetRHIShaderResourceGroup(),
views[0]->GetRHIShaderResourceGroup()
};
RHI::DispatchRaysItem dispatchRaysItem;
dispatchRaysItem.m_width = m_outputAttachmentSize.m_width;
dispatchRaysItem.m_height = m_outputAttachmentSize.m_height;
dispatchRaysItem.m_depth = 1;
dispatchRaysItem.m_rayTracingPipelineState = m_rayTracingPipelineState.get();
dispatchRaysItem.m_rayTracingShaderTable = m_rayTracingShaderTable.get();
dispatchRaysItem.m_shaderResourceGroupCount = RHI::ArraySize(shaderResourceGroups);
dispatchRaysItem.m_shaderResourceGroups = shaderResourceGroups;
dispatchRaysItem.m_globalPipelineState = m_globalPipelineState.get();
// submit the DispatchRays item
context.GetCommandList()->Submit(dispatchRaysItem);
}
}
} // namespace RPI
} // namespace AZ

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save