Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into mnaumov/2372_signOffFix
Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>
This commit is contained in:
@@ -8,7 +8,7 @@ INTRODUCTION
|
||||
------------
|
||||
|
||||
EditorPythonBindings is a Python project that contains a collection of editor testing tools
|
||||
developed by the Lumberyard feature teams. The project contains tools for system level
|
||||
developed by the O3DE feature teams. The project contains tools for system level
|
||||
editor tests.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ installed on your system.
|
||||
|
||||
INSTALL
|
||||
-----------
|
||||
It is recommended to set up these these tools with Lumberyard's CMake build commands.
|
||||
It is recommended to set up these these tools with O3DE's CMake build commands.
|
||||
Assuming CMake is already setup on your operating system, below are some sample build commands:
|
||||
cd /path/to/od3e/
|
||||
mkdir windows_vs2019
|
||||
|
||||
@@ -27,19 +27,19 @@ class TestPythonAssetProcessing(object):
|
||||
unexpected_lines = []
|
||||
expected_lines = [
|
||||
'Mock asset exists',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.azmodel) found',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.azmodel) found',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.azmodel) found',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.azmodel) found',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.azmodel) found',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.azmodel) found',
|
||||
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found'
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive_1.azmodel) found',
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative_1.azmodel) found',
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive_1.azmodel) found',
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative_1.azmodel) found',
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive_1.azmodel) found',
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative_1.azmodel) found',
|
||||
'AssetId found for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center_1.azmodel) found'
|
||||
]
|
||||
timeout = 180
|
||||
halt_on_unexpected = False
|
||||
test_directory = os.path.join(os.path.dirname(__file__))
|
||||
testFile = os.path.join(test_directory, 'AssetBuilder_test_case.py')
|
||||
editor.args.extend(['-NullRenderer', "--skipWelcomeScreenDialog", "--autotest_mode", "--runpythontest", testFile])
|
||||
editor.args.extend(['-NullRenderer', '-rhi=Null', "--skipWelcomeScreenDialog", "--autotest_mode", "--runpythontest", testFile])
|
||||
|
||||
with editor.start():
|
||||
editorlog_file = os.path.join(editor.workspace.paths.project_log(), 'Editor.log')
|
||||
|
||||
@@ -29,21 +29,21 @@ if (assetIdString.endswith(':528cca58') is False):
|
||||
print ('Mock asset exists')
|
||||
|
||||
# These tests detect if the geom_group.fbx file turns into a number of azmodel product assets
|
||||
def test_azmodel_product(generatedModelAssetPath, expectedSubId):
|
||||
def test_azmodel_product(generatedModelAssetPath):
|
||||
azModelAssetType = azlmbr.math.Uuid_CreateString('{2C7477B6-69C5-45BE-8163-BCD6A275B6D8}', 0)
|
||||
assetId = azlmbr.asset.AssetCatalogRequestBus(azlmbr.bus.Broadcast, 'GetAssetIdByPath', generatedModelAssetPath, azModelAssetType, False)
|
||||
assetIdString = assetId.to_string()
|
||||
if (assetIdString.endswith(':' + expectedSubId) is False):
|
||||
raise_and_stop(f'Asset at path {generatedModelAssetPath} has unexpected asset ID ({assetIdString}) for ({generatedModelAssetPath}), expected {expectedSubId}!')
|
||||
if (assetId.is_valid()):
|
||||
print(f'AssetId found for asset ({generatedModelAssetPath}) found')
|
||||
else:
|
||||
print(f'Expected subId for asset ({generatedModelAssetPath}) found')
|
||||
raise_and_stop(f'Asset at path {generatedModelAssetPath} has unexpected asset ID ({assetIdString})!')
|
||||
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.azmodel', '1024be55')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.azmodel', '1052c94e')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.azmodel', '10130556')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.azmodel', '1065724d')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.azmodel', '10d16e68')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.azmodel', '10a71973')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel', '10412075')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive_1.azmodel')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative_1.azmodel')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive_1.azmodel')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative_1.azmodel')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive_1.azmodel')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative_1.azmodel')
|
||||
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center_1.azmodel')
|
||||
|
||||
azlmbr.editor.EditorToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'ExitNoPrompt')
|
||||
|
||||
+13
-13
@@ -47,28 +47,28 @@ def open_material(file_path):
|
||||
"""
|
||||
:return: uuid of material document opened
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "OpenDocument", file_path)
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(bus.Broadcast, "OpenDocument", file_path)
|
||||
|
||||
|
||||
def is_open(document_id):
|
||||
"""
|
||||
:return: bool
|
||||
"""
|
||||
return materialeditor.MaterialDocumentRequestBus(bus.Event, "IsOpen", document_id)
|
||||
return azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "IsOpen", document_id)
|
||||
|
||||
|
||||
def save_document(document_id):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "SaveDocument", document_id)
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(bus.Broadcast, "SaveDocument", document_id)
|
||||
|
||||
|
||||
def save_document_as_copy(document_id, target_path):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
|
||||
bus.Broadcast, "SaveDocumentAsCopy", document_id, target_path
|
||||
)
|
||||
|
||||
@@ -77,7 +77,7 @@ def save_document_as_child(document_id, target_path):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
|
||||
bus.Broadcast, "SaveDocumentAsChild", document_id, target_path
|
||||
)
|
||||
|
||||
@@ -86,39 +86,39 @@ def save_all():
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "SaveAllDocuments")
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(bus.Broadcast, "SaveAllDocuments")
|
||||
|
||||
|
||||
def close_document(document_id):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "CloseDocument", document_id)
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(bus.Broadcast, "CloseDocument", document_id)
|
||||
|
||||
|
||||
def close_all_documents():
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "CloseAllDocuments")
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(bus.Broadcast, "CloseAllDocuments")
|
||||
|
||||
|
||||
def close_all_except_selected(document_id):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "CloseAllDocumentsExcept", document_id)
|
||||
return azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(bus.Broadcast, "CloseAllDocumentsExcept", document_id)
|
||||
|
||||
|
||||
def get_property(document_id, property_name):
|
||||
"""
|
||||
:return: property value or invalid value if the document is not open or the property_name can't be found
|
||||
"""
|
||||
return materialeditor.MaterialDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name)
|
||||
return azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name)
|
||||
|
||||
|
||||
def set_property(document_id, property_name, value):
|
||||
materialeditor.MaterialDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value)
|
||||
azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value)
|
||||
|
||||
|
||||
def is_pane_visible(pane_name):
|
||||
@@ -175,7 +175,7 @@ def wait_for_condition(function, timeout_in_seconds=1.0):
|
||||
with Timeout(timeout_in_seconds) as t:
|
||||
while True:
|
||||
try:
|
||||
atomtools.general.idle_wait_frames(1)
|
||||
azlmbr.atomtools.general.idle_wait_frames(1)
|
||||
except Exception:
|
||||
print("WARNING: Couldn't wait for frame")
|
||||
|
||||
@@ -269,6 +269,6 @@ class ScreenshotHelper:
|
||||
|
||||
|
||||
def capture_screenshot(file_path):
|
||||
return ScreenshotHelper(atomtools.general.idle_wait_frames).capture_screenshot_blocking(
|
||||
return ScreenshotHelper(azlmbr.atomtools.general.idle_wait_frames).capture_screenshot_blocking(
|
||||
os.path.join(file_path)
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
|
||||
5) Verify if Mesh Asset is assigned via both OK/Enter options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- This test file must be called from the O3DE Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ class TestBasicEditorWorkflows(EditorTestHelper):
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Open Lumberyard editor and check if basic Editor workflows are completable.
|
||||
Open O3DE editor and check if basic Editor workflows are completable.
|
||||
|
||||
Expected Behavior:
|
||||
- A new level can be created
|
||||
@@ -48,7 +48,7 @@ class TestBasicEditorWorkflows(EditorTestHelper):
|
||||
- Level can be exported
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- This test file must be called from the O3DE Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class TestEditMenuOptions(EditorTestHelper):
|
||||
2) Interact with Edit Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- This test file must be called from the O3DE Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class TestFileMenuOptions(EditorTestHelper):
|
||||
2) Interact with File Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- This test file must be called from the O3DE Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class TestViewMenuOptions(EditorTestHelper):
|
||||
2) Interact with View Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- This test file must be called from the O3DE Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ def Pane_PropertiesChanged_RetainsOnRestart():
|
||||
from utils import TestHelper as helper
|
||||
import pyside_utils
|
||||
|
||||
# Lumberyard Imports
|
||||
# O3DE Imports
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
# Pyside imports
|
||||
|
||||
@@ -53,7 +53,7 @@ def Editor_NewExistingLevels_Works():
|
||||
10) Save, Load and Export an existing level and close editor
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- This test file must be called from the O3DE Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
|
||||
+1
-31
@@ -1,17 +1,5 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "iPhoneNotificationIcon40x40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "iPhoneNotificationIcon60x60.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
@@ -48,18 +36,6 @@
|
||||
"filename" : "iPhoneAppIcon180x180.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "iPadNotificationIcon20x20.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "iPadNotificationIcon40x40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
@@ -101,16 +77,10 @@
|
||||
"idiom" : "ipad",
|
||||
"filename" : "iPadProAppIcon167x167.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "iOSAppStoreIcon1024x1024.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-31
@@ -1,17 +1,5 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "iPhoneNotificationIcon40x40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "iPhoneNotificationIcon60x60.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
@@ -48,18 +36,6 @@
|
||||
"filename" : "iPhoneAppIcon180x180.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "iPadNotificationIcon20x20.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "iPadNotificationIcon40x40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
@@ -101,16 +77,10 @@
|
||||
"idiom" : "ipad",
|
||||
"filename" : "iPadProAppIcon167x167.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "iOSAppStoreIcon1024x1024.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-46
@@ -1,50 +1,5 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "2436h",
|
||||
"filename" : "iPhoneLaunchImage1125x2436.png",
|
||||
"minimum-system-version" : "11.0",
|
||||
"orientation" : "portrait",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "2436h",
|
||||
"filename" : "iPhoneLaunchImage2436x1125.png",
|
||||
"minimum-system-version" : "11.0",
|
||||
"orientation" : "landscape",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "736h",
|
||||
"filename" : "iPhoneLaunchImage1242x2208.png",
|
||||
"minimum-system-version" : "8.0",
|
||||
"orientation" : "portrait",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "736h",
|
||||
"filename" : "iPhoneLaunchImage2208x1242.png",
|
||||
"minimum-system-version" : "8.0",
|
||||
"orientation" : "landscape",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "667h",
|
||||
"filename" : "iPhoneLaunchImage750x1334.png",
|
||||
"minimum-system-version" : "8.0",
|
||||
"orientation" : "portrait",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
@@ -166,4 +121,4 @@
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,9 +238,13 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Gui
|
||||
3rdParty::Qt::Widgets
|
||||
3rdParty::Qt::Test
|
||||
Legacy::CryCommon
|
||||
AZ::AzToolsFramework
|
||||
AZ::AzToolsFramework.Tests
|
||||
AZ::AzToolsFrameworkTestCommon
|
||||
Legacy::EditorLib
|
||||
Gem::AtomToolsFramework.Static
|
||||
RUNTIME_DEPENDENCIES
|
||||
Gem::LmbrCentral
|
||||
)
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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 <AzFramework/Viewport/CameraInput.h>
|
||||
#include <AzFramework/Viewport/ViewportControllerList.h>
|
||||
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
|
||||
#include <Editor/ViewportManipulatorController.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
|
||||
|
||||
class EditorInteractionViewportSelectionFake : public AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
// EditorInteractionSystemViewportSelectionRequestBus overrides ...
|
||||
void SetHandler(const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder);
|
||||
void SetDefaultHandler();
|
||||
bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction);
|
||||
bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction);
|
||||
|
||||
AZStd::function<bool(const MouseInteractionEvent& mouseInteraction)> m_internalHandleMouseViewportInteraction;
|
||||
AZStd::function<bool(const MouseInteractionEvent& mouseInteraction)> m_internalHandleMouseManipulatorInteraction;
|
||||
};
|
||||
|
||||
void EditorInteractionViewportSelectionFake::Connect()
|
||||
{
|
||||
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
|
||||
}
|
||||
|
||||
void EditorInteractionViewportSelectionFake::Disconnect()
|
||||
{
|
||||
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void EditorInteractionViewportSelectionFake::SetHandler(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
void EditorInteractionViewportSelectionFake::SetDefaultHandler()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
bool EditorInteractionViewportSelectionFake::InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
if (m_internalHandleMouseViewportInteraction)
|
||||
{
|
||||
return m_internalHandleMouseViewportInteraction(mouseInteraction);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EditorInteractionViewportSelectionFake::InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
if (m_internalHandleMouseManipulatorInteraction)
|
||||
{
|
||||
return m_internalHandleMouseManipulatorInteraction(mouseInteraction);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class ViewportManipulatorControllerFixture : public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
static const AzFramework::ViewportId TestViewportId = AzFramework::ViewportId(0);
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
|
||||
m_rootWidget = AZStd::make_unique<QWidget>();
|
||||
m_rootWidget->setFixedSize(QSize(100, 100));
|
||||
|
||||
m_controllerList = AZStd::make_shared<AzFramework::ViewportControllerList>();
|
||||
m_controllerList->RegisterViewportContext(TestViewportId);
|
||||
|
||||
m_inputChannelMapper = AZStd::make_unique<AzToolsFramework::QtEventToAzInputMapper>(m_rootWidget.get(), TestViewportId);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
m_inputChannelMapper.reset();
|
||||
|
||||
m_controllerList->UnregisterViewportContext(TestViewportId);
|
||||
m_controllerList.reset();
|
||||
m_rootWidget.reset();
|
||||
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<QWidget> m_rootWidget;
|
||||
AzFramework::ViewportControllerListPtr m_controllerList;
|
||||
AZStd::unique_ptr<AzToolsFramework::QtEventToAzInputMapper> m_inputChannelMapper;
|
||||
};
|
||||
|
||||
TEST_F(ViewportManipulatorControllerFixture, An_event_is_not_propagated_to_the_viewport_when_a_manipulator_handles_it_first)
|
||||
{
|
||||
// forward input events to our controller list
|
||||
QObject::connect(
|
||||
m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(),
|
||||
[this](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event)
|
||||
{
|
||||
m_controllerList->HandleInputChannelEvent(
|
||||
AzFramework::ViewportControllerInputEvent{ TestViewportId, nullptr, *inputChannel });
|
||||
});
|
||||
|
||||
EditorInteractionViewportSelectionFake editorInteractionViewportFake;
|
||||
editorInteractionViewportFake.m_internalHandleMouseManipulatorInteraction = [](const MouseInteractionEvent&)
|
||||
{
|
||||
// report the event was handled (manipulator was interacted with)
|
||||
return true;
|
||||
};
|
||||
|
||||
bool viewportInteractionCalled = false;
|
||||
editorInteractionViewportFake.m_internalHandleMouseViewportInteraction = [&viewportInteractionCalled](const MouseInteractionEvent&)
|
||||
{
|
||||
// we should not call this as the manipulator will have consumed this event
|
||||
viewportInteractionCalled = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
editorInteractionViewportFake.Connect();
|
||||
|
||||
m_controllerList->Add(AZStd::make_shared<SandboxEditor::ViewportManipulatorController>());
|
||||
|
||||
// simulate a press and move
|
||||
MousePressAndMove(m_rootWidget.get(), QPoint(10, 10), QPoint(10, 10), Qt::MouseButton::LeftButton);
|
||||
MouseMove(m_rootWidget.get(), QPoint(20, 20), QPoint(10, 10), Qt::MouseButton::LeftButton);
|
||||
MouseMove(m_rootWidget.get(), QPoint(30, 30), QPoint(0, 0), Qt::MouseButton::LeftButton);
|
||||
QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier, QPoint(30, 30));
|
||||
|
||||
// ensure the viewport did not receive the event when it was intercepted first by the manipulator
|
||||
EXPECT_FALSE(viewportInteractionCalled);
|
||||
|
||||
editorInteractionViewportFake.Disconnect();
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/Debug/TraceContext.h>
|
||||
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
|
||||
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
|
||||
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
|
||||
#include <SceneSerializationHandler.h>
|
||||
|
||||
@@ -96,7 +97,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SceneAPI::Containers::Scene> scene =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
if (!scene)
|
||||
{
|
||||
AZ_TracePrintf(Utilities::ErrorWindow, "Failed to load the requested scene.");
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace SandboxEditor
|
||||
{
|
||||
}
|
||||
|
||||
ViewportManipulatorControllerInstance::~ViewportManipulatorControllerInstance() = default;
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
@@ -103,14 +105,21 @@ namespace SandboxEditor
|
||||
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
|
||||
if (event.m_priority == ManipulatorPriority)
|
||||
{
|
||||
AzFramework::ScreenPoint screenPosition = AzFramework::ScreenPoint(0, 0);
|
||||
ViewportMouseCursorRequestBus::EventResult(
|
||||
screenPosition, GetViewportId(), &ViewportMouseCursorRequestBus::Events::ViewportCursorScreenPosition);
|
||||
const auto* position = event.m_inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
|
||||
AZ_Assert(position, "Expected PositionData2D but found nullptr");
|
||||
|
||||
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPosition;
|
||||
AzFramework::WindowSize windowSize;
|
||||
AzFramework::WindowRequestBus::EventResult(
|
||||
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
|
||||
|
||||
auto screenPoint = AzFramework::ScreenPoint(
|
||||
position->m_normalizedPosition.GetX() * windowSize.m_width,
|
||||
position->m_normalizedPosition.GetY() * windowSize.m_height);
|
||||
|
||||
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint;
|
||||
AZStd::optional<ProjectedViewportRay> ray;
|
||||
ViewportInteractionRequestBus::EventResult(
|
||||
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPosition);
|
||||
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint);
|
||||
|
||||
if (ray.has_value())
|
||||
{
|
||||
@@ -118,6 +127,7 @@ namespace SandboxEditor
|
||||
m_mouseInteraction.m_mousePick.m_rayDirection = ray.value().direction;
|
||||
}
|
||||
}
|
||||
|
||||
eventType = MouseEvent::Move;
|
||||
}
|
||||
else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
|
||||
@@ -217,8 +227,7 @@ namespace SandboxEditor
|
||||
interactionHandled, AzToolsFramework::GetEntityContextId(), targetInteractionEvent, mouseInteractionEvent);
|
||||
}
|
||||
|
||||
// Only filter button/key press events, not release events
|
||||
return interactionHandled && event.m_inputChannel.IsActive();
|
||||
return interactionHandled;
|
||||
}
|
||||
|
||||
void ViewportManipulatorControllerInstance::ResetInputChannels()
|
||||
|
||||
@@ -8,25 +8,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzFramework/Viewport/MultiViewportController.h>
|
||||
#include <AzFramework/Input/Events/InputChannelEventListener.h>
|
||||
#include <AzFramework/Viewport/MultiViewportController.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
#include <SandboxAPI.h>
|
||||
|
||||
namespace SandboxEditor
|
||||
{
|
||||
class ViewportManipulatorControllerInstance;
|
||||
using ViewportManipulatorController = AzFramework::MultiViewportController<ViewportManipulatorControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities>;
|
||||
using ViewportManipulatorController = AzFramework::
|
||||
MultiViewportController<ViewportManipulatorControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities>;
|
||||
|
||||
class ViewportManipulatorControllerInstance final
|
||||
: public AzFramework::MultiViewportControllerInstanceInterface<ViewportManipulatorController>
|
||||
{
|
||||
public:
|
||||
explicit ViewportManipulatorControllerInstance(AzFramework::ViewportId viewport, ViewportManipulatorController* controller);
|
||||
SANDBOX_API ViewportManipulatorControllerInstance(AzFramework::ViewportId viewport, ViewportManipulatorController* controller);
|
||||
SANDBOX_API ~ViewportManipulatorControllerInstance();
|
||||
|
||||
bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
|
||||
void ResetInputChannels() override;
|
||||
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
|
||||
SANDBOX_API bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
|
||||
SANDBOX_API void ResetInputChannels() override;
|
||||
SANDBOX_API void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
|
||||
|
||||
private:
|
||||
bool IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton) const;
|
||||
@@ -39,4 +43,4 @@ namespace SandboxEditor
|
||||
AZStd::unordered_map<AzToolsFramework::ViewportInteraction::MouseButton, AZ::ScriptTimePoint> m_pendingDoubleClicks;
|
||||
AZ::ScriptTimePoint m_curTime;
|
||||
};
|
||||
} //namespace SandboxEditor
|
||||
} // namespace SandboxEditor
|
||||
|
||||
@@ -20,6 +20,7 @@ set(FILES
|
||||
Lib/Tests/test_ViewPanePythonBindings.cpp
|
||||
Lib/Tests/test_ViewportTitleDlgPythonBindings.cpp
|
||||
Lib/Tests/test_DisplaySettingsPythonBindings.cpp
|
||||
Lib/Tests/test_ViewportManipulatorController.cpp
|
||||
DisplaySettingsPythonFuncs.cpp
|
||||
DisplaySettingsPythonFuncs.h
|
||||
)
|
||||
|
||||
+11
-3
@@ -207,7 +207,10 @@ namespace AzFramework
|
||||
// Handles Win32 Window Event callbacks
|
||||
LRESULT CALLBACK NativeWindowImpl_Win32::WindowCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
NativeWindowImpl_Win32* nativeWindowImpl = reinterpret_cast<NativeWindowImpl_Win32*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
NativeWindowImpl_Win32* nativeWindowImpl = reinterpret_cast<NativeWindowImpl_Win32*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
|
||||
// If set to true, call DefWindowProc to ensure the default Windows behavior occurs
|
||||
bool shouldBubbleEventUp = false;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
@@ -276,14 +279,19 @@ namespace AzFramework
|
||||
uint32_t refreshRate = DisplayConfig.dmDisplayFrequency;
|
||||
WindowNotificationBus::Event(
|
||||
nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnRefreshRateChanged, refreshRate);
|
||||
shouldBubbleEventUp = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
shouldBubbleEventUp = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!shouldBubbleEventUp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void NativeWindowImpl_Win32::WindowSizeChanged(const uint32_t width, const uint32_t height)
|
||||
|
||||
@@ -10,22 +10,9 @@
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
StringifySerializer::StringifySerializer(char delimeter, bool outputFieldNames, const AZStd::string& seperator)
|
||||
: m_delimeter(delimeter)
|
||||
, m_outputFieldNames(outputFieldNames)
|
||||
, m_separator(seperator)
|
||||
const StringifySerializer::ValueMap& StringifySerializer::GetValueMap() const
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
const AZStd::string& StringifySerializer::GetString() const
|
||||
{
|
||||
return m_string;
|
||||
}
|
||||
|
||||
const StringifySerializer::StringMap& StringifySerializer::GetValueMap() const
|
||||
{
|
||||
return m_map;
|
||||
return m_valueMap;
|
||||
}
|
||||
|
||||
SerializerMode StringifySerializer::GetSerializerMode() const
|
||||
@@ -137,22 +124,9 @@ namespace AzNetworking
|
||||
template <typename T>
|
||||
bool StringifySerializer::ProcessData(const char* name, const T& value)
|
||||
{
|
||||
// Only add delimeters after we have processed at least one element
|
||||
if (!m_string.empty())
|
||||
{
|
||||
m_string += m_delimeter;
|
||||
}
|
||||
|
||||
if (m_outputFieldNames)
|
||||
{
|
||||
m_string += m_prefix;
|
||||
m_string += name;
|
||||
m_string += m_separator;
|
||||
}
|
||||
|
||||
AZ::CVarFixedString string = AZ::ConsoleTypeHelpers::ValueToString(value);
|
||||
m_string += string.c_str();
|
||||
m_map[m_prefix + name] = string.c_str();
|
||||
const AZStd::string keyString = m_prefix + name;
|
||||
AZ::CVarFixedString valueString = AZ::ConsoleTypeHelpers::ValueToString(value);
|
||||
m_valueMap[keyString] = valueString.c_str();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,17 +20,12 @@ namespace AzNetworking
|
||||
{
|
||||
public:
|
||||
|
||||
using StringMap = AZStd::map<AZStd::string, AZStd::string>;
|
||||
using ValueMap = AZStd::map<AZStd::string, AZStd::string>;
|
||||
|
||||
StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "=");
|
||||
StringifySerializer() = default;
|
||||
|
||||
// GetString
|
||||
// After serializing objects, get the serialized values as a single string
|
||||
const AZStd::string& GetString() const;
|
||||
|
||||
// GetValueMap
|
||||
// After serializing objects, get the serialized values as key value pairs
|
||||
const StringMap& GetValueMap() const;
|
||||
//! After serializing objects, get the serialized values as a map of key/value pairs.
|
||||
const ValueMap& GetValueMap() const;
|
||||
|
||||
// ISerializer interfaces
|
||||
SerializerMode GetSerializerMode() const override;
|
||||
@@ -62,15 +57,8 @@ namespace AzNetworking
|
||||
template <typename T>
|
||||
bool ProcessData(const char* name, const T& value);
|
||||
|
||||
private:
|
||||
|
||||
char m_delimeter;
|
||||
bool m_outputFieldNames = true;
|
||||
|
||||
StringMap m_map;
|
||||
AZStd::string m_string;
|
||||
ValueMap m_valueMap;
|
||||
AZStd::string m_prefix;
|
||||
AZStd::string m_separator;
|
||||
AZStd::deque<AZStd::size_t> m_prefixSizeStack;
|
||||
};
|
||||
}
|
||||
|
||||
+20
-29
@@ -162,7 +162,6 @@ namespace AzToolsFramework
|
||||
: QObject(sourceWidget)
|
||||
, m_sourceWidget(sourceWidget)
|
||||
, m_keyboardModifiers(AZStd::make_shared<AzFramework::ModifierKeyStates>())
|
||||
, m_cursorPosition(AZStd::make_shared<AzFramework::InputChannel::PositionData2D>())
|
||||
{
|
||||
InitializeKeyMappings();
|
||||
InitializeMouseButtonMappings();
|
||||
@@ -230,24 +229,17 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
// Because there's no "end" to mouse movement and wheel events, we reset mouse movement channels that have been opened
|
||||
// during the next processed non-mouse event.
|
||||
if (m_mouseChannelsNeedUpdate && event->type() != QEvent::Type::MouseMove && event->type() != QEvent::Type::Wheel)
|
||||
{
|
||||
m_cursorPosition->m_normalizedPositionDelta = AZ::Vector2::CreateZero();
|
||||
ProcessPendingMouseEvents();
|
||||
m_mouseChannelsNeedUpdate = false;
|
||||
}
|
||||
const auto eventType = event->type();
|
||||
|
||||
// Only accept mouse & key release events that originate from an object that is not our target widget,
|
||||
// as we don't want to erroneously intercept user input meant for another component.
|
||||
if (object != m_sourceWidget && event->type() != QEvent::Type::KeyRelease && event->type() != QEvent::Type::MouseButtonRelease)
|
||||
if (object != m_sourceWidget && eventType != QEvent::Type::KeyRelease && eventType != QEvent::Type::MouseButtonRelease)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If our focus changes, go ahead and reset all input devices.
|
||||
if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
|
||||
if (eventType == QEvent::FocusIn || eventType == QEvent::FocusOut)
|
||||
{
|
||||
HandleFocusChange(event);
|
||||
}
|
||||
@@ -255,27 +247,28 @@ namespace AzToolsFramework
|
||||
// ShortcutOverride is used in lieu of KeyPress for high priority input channels like Alt
|
||||
// that need to be accepted and stopped before they bubble up and cause unintended behavior.
|
||||
else if (
|
||||
event->type() == QEvent::Type::KeyPress || event->type() == QEvent::Type::KeyRelease ||
|
||||
event->type() == QEvent::Type::ShortcutOverride)
|
||||
eventType == QEvent::Type::KeyPress || eventType == QEvent::Type::KeyRelease || eventType == QEvent::Type::ShortcutOverride)
|
||||
{
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
HandleKeyEvent(keyEvent);
|
||||
}
|
||||
// Map mouse events to input channels.
|
||||
else if (event->type() == QEvent::Type::MouseButtonPress || event->type() == QEvent::Type::MouseButtonRelease || event->type() == QEvent::Type::MouseButtonDblClick)
|
||||
else if (
|
||||
eventType == QEvent::Type::MouseButtonPress || eventType == QEvent::Type::MouseButtonRelease ||
|
||||
eventType == QEvent::Type::MouseButtonDblClick)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
HandleMouseButtonEvent(mouseEvent);
|
||||
}
|
||||
// Map mouse movement to the movement input channels.
|
||||
// This includes SystemCursorPosition alongside Movement::X and Movement::Y.
|
||||
else if (event->type() == QEvent::Type::MouseMove)
|
||||
else if (eventType == QEvent::Type::MouseMove)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
HandleMouseMoveEvent(mouseEvent);
|
||||
}
|
||||
// Map wheel events to the mouse Z movement channel.
|
||||
else if (event->type() == QEvent::Type::Wheel)
|
||||
else if (eventType == QEvent::Type::Wheel)
|
||||
{
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
HandleWheelEvent(wheelEvent);
|
||||
@@ -303,14 +296,16 @@ namespace AzToolsFramework
|
||||
auto mouseWheelChannel =
|
||||
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::Z);
|
||||
|
||||
systemCursorChannel->ProcessRawInputEvent(m_cursorPosition->m_normalizedPositionDelta.GetLength());
|
||||
systemCursorChannel->ProcessRawInputEvent(m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetLength());
|
||||
// Generate movement events based on the pixel delta divided by the DPI scaling factor, to calculate a rough approximation
|
||||
// of cursor movement velocity.
|
||||
movementXChannel->ProcessRawInputEvent(
|
||||
m_cursorPosition->m_normalizedPositionDelta.GetX() * aznumeric_cast<float>(m_sourceWidget->width()) / m_sourceWidget->devicePixelRatioF());
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetX() * aznumeric_cast<float>(m_sourceWidget->width()) /
|
||||
m_sourceWidget->devicePixelRatioF());
|
||||
movementYChannel->ProcessRawInputEvent(
|
||||
m_cursorPosition->m_normalizedPositionDelta.GetY() * aznumeric_cast<float>(m_sourceWidget->height()) / m_sourceWidget->devicePixelRatioF());
|
||||
mouseWheelChannel->ProcessRawInputEvent(0.f);
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetY() * aznumeric_cast<float>(m_sourceWidget->height()) /
|
||||
m_sourceWidget->devicePixelRatioF());
|
||||
mouseWheelChannel->ProcessRawInputEvent(0.0f);
|
||||
|
||||
NotifyUpdateChannelIfNotIdle(systemCursorChannel, nullptr);
|
||||
NotifyUpdateChannelIfNotIdle(movementXChannel, nullptr);
|
||||
@@ -358,14 +353,13 @@ namespace AzToolsFramework
|
||||
|
||||
void QtEventToAzInputMapper::HandleMouseMoveEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
AZ::Vector2 lastCursorPosition = m_cursorPosition->m_normalizedPosition;
|
||||
AZ::Vector2 lastCursorPosition = m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition;
|
||||
|
||||
const QPoint mousePos = mouseEvent->pos();
|
||||
const AZ::Vector2 normalizedPosition = WidgetPositionToNormalizedPosition(mousePos);
|
||||
m_cursorPosition->m_normalizedPositionDelta = normalizedPosition - m_cursorPosition->m_normalizedPosition;
|
||||
m_cursorPosition->m_normalizedPosition = normalizedPosition;
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = normalizedPosition - m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition;
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = normalizedPosition;
|
||||
ProcessPendingMouseEvents();
|
||||
m_mouseChannelsNeedUpdate = true;
|
||||
|
||||
if (m_capturingCursor)
|
||||
{
|
||||
@@ -376,7 +370,7 @@ namespace AzToolsFramework
|
||||
// Even though we just set the cursor position, there are edge cases such as remote desktop that will leave
|
||||
// the cursor position unchanged. For safety, we re-cache our last cursor position for delta generation.
|
||||
QPoint actualWidgetPosition = m_sourceWidget->mapFromGlobal(QCursor::pos());
|
||||
m_cursorPosition->m_normalizedPosition = WidgetPositionToNormalizedPosition(actualWidgetPosition);
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(actualWidgetPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,21 +421,18 @@ namespace AzToolsFramework
|
||||
}
|
||||
cursorZChannel->ProcessRawInputEvent(aznumeric_cast<float>(wheelAngle));
|
||||
NotifyUpdateChannelIfNotIdle(cursorZChannel, wheelEvent);
|
||||
m_mouseChannelsNeedUpdate = true;
|
||||
}
|
||||
|
||||
void QtEventToAzInputMapper::HandleFocusChange(QEvent* event)
|
||||
{
|
||||
for (auto& channelData : m_channels)
|
||||
{
|
||||
// If resetting the input device changed the channel state, submit it to the mapped channel list
|
||||
// for processing.
|
||||
// If resetting the input device changed the channel state, submit it to the mapped channel list for processing.
|
||||
if (channelData.second->IsActive())
|
||||
{
|
||||
channelData.second->UpdateState(false);
|
||||
NotifyUpdateChannelIfNotIdle(channelData.second, event);
|
||||
}
|
||||
}
|
||||
m_mouseChannelsNeedUpdate = false;
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -138,8 +138,6 @@ namespace AzToolsFramework
|
||||
|
||||
// The current keyboard modifier state used by our synthetic key input channels.
|
||||
AZStd::shared_ptr<AzFramework::ModifierKeyStates> m_keyboardModifiers;
|
||||
// The current normalized cursor position used by our synthetic system cursor event.
|
||||
AZStd::shared_ptr<AzFramework::InputChannel::PositionData2D> m_cursorPosition;
|
||||
// A lookup table for Qt key -> AZ input channel.
|
||||
AZStd::unordered_map<Qt::Key, AzFramework::InputChannelId> m_keyMappings;
|
||||
// A lookup table for Qt mouse button -> AZ input channel.
|
||||
@@ -152,8 +150,6 @@ namespace AzToolsFramework
|
||||
AZStd::unordered_map<AzFramework::InputChannelId, AzFramework::InputChannel*> m_channels;
|
||||
// The source widget to map events from, used to calculate the relative mouse position within the widget bounds.
|
||||
QWidget* m_sourceWidget;
|
||||
// Flags when mouse movement channels have been opened and may need to be closed (as there are no movement ended events).
|
||||
bool m_mouseChannelsNeedUpdate = false;
|
||||
// Flags whether or not Qt events should currently be processed.
|
||||
bool m_enabled = true;
|
||||
// Flags whether or not the cursor is being constrained to the source widget (for invisible mouse movement).
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Logger/TraceLogger.h>
|
||||
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzToolsFramework/Logger/TraceLogger.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -25,6 +23,22 @@ namespace AzToolsFramework
|
||||
|
||||
bool TraceLogger::OnOutput(const char* window, const char* message)
|
||||
{
|
||||
for (const auto& filter : m_windowFilters)
|
||||
{
|
||||
if (AZ::StringFunc::Contains(window, filter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& filter : m_messageFilters)
|
||||
{
|
||||
if (AZ::StringFunc::Contains(message, filter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_logFile)
|
||||
{
|
||||
m_logFile->AppendLog(AzFramework::LogFile::SEV_NORMAL, window, message);
|
||||
@@ -36,10 +50,10 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
void TraceLogger::WriteStartupLog(const AZStd::string& logFileName)
|
||||
{
|
||||
void TraceLogger::PrepareLogFile(const AZStd::string& logFileName)
|
||||
{
|
||||
using namespace AzFramework;
|
||||
|
||||
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO != nullptr, "FileIO should be running at this point");
|
||||
|
||||
@@ -71,4 +85,34 @@ namespace AzToolsFramework
|
||||
m_logFile->FlushLog();
|
||||
}
|
||||
}
|
||||
|
||||
void TraceLogger::AddWindowFilter(const AZStd::string& filter)
|
||||
{
|
||||
m_windowFilters.insert(filter);
|
||||
}
|
||||
|
||||
void TraceLogger::RemoveWindowFilter(const AZStd::string& filter)
|
||||
{
|
||||
m_windowFilters.erase(filter);
|
||||
}
|
||||
|
||||
void TraceLogger::ClearWindowFilter()
|
||||
{
|
||||
m_windowFilters.clear();
|
||||
}
|
||||
|
||||
void TraceLogger::AddMessageFilter(const AZStd::string& filter)
|
||||
{
|
||||
m_messageFilters.insert(filter);
|
||||
}
|
||||
|
||||
void TraceLogger::RemoveMessageFilter(const AZStd::string& filter)
|
||||
{
|
||||
m_messageFilters.erase(filter);
|
||||
}
|
||||
|
||||
void TraceLogger::ClearMessageFilter()
|
||||
{
|
||||
m_messageFilters.clear();
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -22,8 +22,26 @@ namespace AzToolsFramework
|
||||
TraceLogger();
|
||||
~TraceLogger();
|
||||
|
||||
//! Intalize logging for O3DEToolsApplications
|
||||
void WriteStartupLog(const AZStd::string& logFileName);
|
||||
//! Open log file and dump log sink into it
|
||||
void PrepareLogFile(const AZStd::string& logFileName);
|
||||
|
||||
//! Add filter to ignore messages for windows with matching names
|
||||
void AddWindowFilter(const AZStd::string& filter);
|
||||
|
||||
//! Remove window filter
|
||||
void RemoveWindowFilter(const AZStd::string& filter);
|
||||
|
||||
//! Clear window filters
|
||||
void ClearWindowFilter();
|
||||
|
||||
//! Add filter to ignore messages with matching names
|
||||
void AddMessageFilter(const AZStd::string& filter);
|
||||
|
||||
//! Remove message filter
|
||||
void RemoveMessageFilter(const AZStd::string& filter);
|
||||
|
||||
//! Clear message filters
|
||||
void ClearMessageFilter();
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -38,6 +56,8 @@ namespace AzToolsFramework
|
||||
AZStd::string message;
|
||||
};
|
||||
AZStd::vector<LogMessage> m_startupLogSink;
|
||||
AZStd::unordered_set<AZStd::string> m_windowFilters;
|
||||
AZStd::unordered_set<AZStd::string> m_messageFilters;
|
||||
AZStd::unique_ptr<AzFramework::LogFile> m_logFile;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+29
@@ -27,6 +27,35 @@ using namespace AzToolsFramework;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
void MousePressAndMove(
|
||||
QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, const Qt::MouseButton mouseButton)
|
||||
{
|
||||
QPoint position = widget->mapToGlobal(initialPositionWidget);
|
||||
QTest::mousePress(widget, mouseButton, Qt::NoModifier, position);
|
||||
|
||||
MouseMove(widget, initialPositionWidget, mouseDelta, mouseButton);
|
||||
}
|
||||
|
||||
// Note: There are a series of bugs in Qt that appear to be preventing mouseMove events
|
||||
// firing when sent through the QTest framework. This is a work around for our version
|
||||
// of Qt. In future this can hopefully be simplified. See ^1 for workaround.
|
||||
// More info: Issues with mouse move in Qt
|
||||
// - https://bugreports.qt.io/browse/QTBUG-5232
|
||||
// - https://bugreports.qt.io/browse/QTBUG-69414
|
||||
// - https://lists.qt-project.org/pipermail/development/2019-July/036873.html
|
||||
void MouseMove(QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, const Qt::MouseButton mouseButton)
|
||||
{
|
||||
QPoint nextPosition = widget->mapToGlobal(initialPositionWidget + mouseDelta);
|
||||
|
||||
// ^1 To ensure a mouse move event is fired we must call the test mouse move function
|
||||
// and also send a mouse move event that matches. Each on their own do not appear to
|
||||
// work - please see the links above for more context.
|
||||
QTest::mouseMove(widget, nextPosition);
|
||||
QMouseEvent mouseMoveEvent(
|
||||
QEvent::MouseMove, QPointF(nextPosition), QPointF(nextPosition), Qt::NoButton, mouseButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(widget, &mouseMoveEvent);
|
||||
}
|
||||
|
||||
bool TestWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
AZ_UNUSED(watched);
|
||||
|
||||
+15
@@ -59,6 +59,21 @@ namespace UnitTest
|
||||
{
|
||||
constexpr AZStd::string_view prefabSystemSetting = "/Amazon/Preferences/EnablePrefabSystem";
|
||||
|
||||
/// Performs a mouse press and move event on the provided widget.
|
||||
/// @param widget The widget to perform the mouse press and move on.
|
||||
/// @param initialPositionWidget The position of the mouse relative to the widget (will be remapped to a global position internally).
|
||||
/// @param mouseDelta How far to move the mouse.
|
||||
/// @param mouseButton The button to be used during the press and move.
|
||||
void MousePressAndMove(
|
||||
QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, Qt::MouseButton mouseButton = Qt::LeftButton);
|
||||
|
||||
/// Performs a mouse move event on the provided widget.
|
||||
/// @param widget The widget to perform the mouse move on.
|
||||
/// @param initialPositionWidget The position of the mouse relative to the widget (will be remapped to a global position internally).
|
||||
/// @param mouseDelta How far to move the mouse (note: mouseDelta may be zero and the mouse will only be moved to initialPosition).
|
||||
/// @param mouseButton The button to be held during the move.
|
||||
void MouseMove(QWidget* widget, const QPoint& initialPosition, const QPoint& mouseDelta, Qt::MouseButton mouseButton = Qt::NoButton);
|
||||
|
||||
/// Test widget to store QActions generated by EditorTransformComponentSelection.
|
||||
class TestWidget : public QWidget
|
||||
{
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace AzToolsFramework
|
||||
//! Utility function to return EntityContextId.
|
||||
inline AzFramework::EntityContextId GetEntityContextId()
|
||||
{
|
||||
AzFramework::EntityContextId entityContextId;
|
||||
auto entityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(entityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
return entityContextId;
|
||||
|
||||
@@ -60,6 +60,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PUBLIC
|
||||
AZ::AzTestShared
|
||||
PRIVATE
|
||||
3rdParty::Qt::Test
|
||||
3rdParty::googletest::GMock
|
||||
3rdParty::GoogleBenchmark
|
||||
AZ::AzToolsFramework
|
||||
@@ -76,8 +77,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PRIVATE
|
||||
Tests
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
PUBLIC
|
||||
AZ::AzTestShared
|
||||
PRIVATE
|
||||
3rdParty::Qt::Test
|
||||
AZ::AzFrameworkTestShared
|
||||
AZ::AzToolsFramework
|
||||
|
||||
@@ -107,31 +107,6 @@ namespace UnitTest
|
||||
EXPECT_THAT(m_doubleSpinBoxWithLineEdit, Ne(nullptr));
|
||||
}
|
||||
|
||||
// Note: There are a series of bugs in Qt that appear to be preventing mouseMove events
|
||||
// firing when sent through the QTest framework. This is a work around for our version
|
||||
// of Qt. In future this can hopefully be simplified. See ^1 for workaround.
|
||||
// More info: Issues with mouse move in Qt
|
||||
// - https://bugreports.qt.io/browse/QTBUG-5232
|
||||
// - https://bugreports.qt.io/browse/QTBUG-69414
|
||||
// - https://lists.qt-project.org/pipermail/development/2019-July/036873.html
|
||||
void MousePressAndMove(
|
||||
QWidget* widget, const QPoint& widgetScreenPosition, const QPoint& mouseDelta)
|
||||
{
|
||||
QPoint position = widget->mapToGlobal(widgetScreenPosition);
|
||||
QPoint nextPosition = widget->mapToGlobal(widgetScreenPosition + mouseDelta);
|
||||
|
||||
QTest::mousePress(widget, Qt::LeftButton, Qt::NoModifier, position);
|
||||
|
||||
// ^1 To ensure a mouse move event is fired we must call the test mouse move function
|
||||
// and also send a mouse move event that matches. Each on their own do not appear to
|
||||
// work - please see the links above for more context.
|
||||
QTest::mouseMove(widget, nextPosition);
|
||||
QMouseEvent mouseMoveEvent(
|
||||
QEvent::MouseMove, QPointF(nextPosition), QPointF(nextPosition),
|
||||
Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(widget, &mouseMoveEvent);
|
||||
}
|
||||
|
||||
TEST_F(SpinBoxFixture, SpinBoxMousePressAndMoveRightScrollsValue)
|
||||
{
|
||||
m_doubleSpinBox->setValue(10.0);
|
||||
|
||||
@@ -851,7 +851,8 @@ bool CLog::LogToMainThread(const char* szString, ELogType logType, bool bAdd, SL
|
||||
{
|
||||
// When logging from other thread then main, push all log strings to queue.
|
||||
SLogMsg msg;
|
||||
azstrcpy(msg.msg, AZ_ARRAY_SIZE(msg.msg), szString);
|
||||
constexpr size_t maxArraySize = AZ_ARRAY_SIZE(msg.msg);
|
||||
azstrncpy(msg.msg, maxArraySize, szString, maxArraySize - 1);
|
||||
msg.bAdd = bAdd;
|
||||
msg.destination = destination;
|
||||
msg.logType = logType;
|
||||
|
||||
@@ -21,11 +21,16 @@ namespace AZ
|
||||
{
|
||||
|
||||
AssImpMaterialWrapper::AssImpMaterialWrapper(aiMaterial* aiMaterial)
|
||||
:SDKMaterial::MaterialWrapper(aiMaterial)
|
||||
:m_assImpMaterial(aiMaterial)
|
||||
{
|
||||
AZ_Assert(aiMaterial, "Asset Importer Material cannot be null");
|
||||
}
|
||||
|
||||
aiMaterial* AssImpMaterialWrapper::GetAssImpMaterial() const
|
||||
{
|
||||
return m_assImpMaterial;
|
||||
}
|
||||
|
||||
AZStd::string AssImpMaterialWrapper::GetName() const
|
||||
{
|
||||
return m_assImpMaterial->GetName().C_Str();
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace AZ
|
||||
AZ_RTTI(AssImpMaterialWrapper, "{66992628-CFCE-441B-8849-9344A49AFAC9}", SDKMaterial::MaterialWrapper);
|
||||
AssImpMaterialWrapper(aiMaterial* aiMaterial);
|
||||
~AssImpMaterialWrapper() override = default;
|
||||
aiMaterial* GetAssImpMaterial() const;
|
||||
AZStd::string GetName() const override;
|
||||
AZ::u64 GetUniqueId() const override;
|
||||
AZ::Vector3 GetDiffuseColor() const override;
|
||||
@@ -38,6 +39,9 @@ namespace AZ
|
||||
AZStd::optional<bool> GetUseEmissiveMap() const;
|
||||
AZStd::optional<float> GetEmissiveIntensity() const;
|
||||
AZStd::optional<bool> GetUseAOMap() const;
|
||||
|
||||
protected:
|
||||
aiMaterial* m_assImpMaterial = nullptr;
|
||||
};
|
||||
} // namespace AssImpSDKWrapper
|
||||
}// namespace AZ
|
||||
|
||||
@@ -17,14 +17,16 @@ namespace AZ
|
||||
namespace AssImpSDKWrapper
|
||||
{
|
||||
AssImpNodeWrapper::AssImpNodeWrapper(aiNode* sourceNode)
|
||||
:SDKNode::NodeWrapper(sourceNode)
|
||||
: m_assImpNode(sourceNode)
|
||||
{
|
||||
AZ_Assert(m_assImpNode, "Asset Importer Node cannot be null");
|
||||
}
|
||||
|
||||
AssImpNodeWrapper::~AssImpNodeWrapper()
|
||||
aiNode* AssImpNodeWrapper::GetAssImpNode() const
|
||||
{
|
||||
return m_assImpNode;
|
||||
}
|
||||
|
||||
const char* AssImpNodeWrapper::GetName() const
|
||||
{
|
||||
return m_assImpNode->mName.C_Str();
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace AZ
|
||||
public:
|
||||
AZ_RTTI(AssImpNodeWrapper, "{1043260B-9076-49B7-AD38-EF62E85F7C1D}", SDKNode::NodeWrapper);
|
||||
AssImpNodeWrapper(aiNode* sourceNode);
|
||||
~AssImpNodeWrapper() override;
|
||||
~AssImpNodeWrapper() override = default;
|
||||
aiNode* GetAssImpNode() const;
|
||||
const char* GetName() const override;
|
||||
AZ::u64 GetUniqueId() const override;
|
||||
int GetChildCount() const override;
|
||||
@@ -28,6 +29,9 @@ namespace AZ
|
||||
const bool ContainsMesh();
|
||||
bool ContainsBones(const aiScene& scene) const;
|
||||
int GetMaterialCount() const override;
|
||||
|
||||
protected:
|
||||
aiNode* m_assImpNode = nullptr;
|
||||
};
|
||||
} // namespace AssImpSDKWrapper
|
||||
}// namespace AZ
|
||||
|
||||
@@ -25,15 +25,10 @@ namespace AZ
|
||||
namespace AssImpSDKWrapper
|
||||
{
|
||||
AssImpSceneWrapper::AssImpSceneWrapper()
|
||||
: SDKScene::SceneWrapperBase()
|
||||
{
|
||||
}
|
||||
AssImpSceneWrapper::AssImpSceneWrapper(aiScene* aiScene)
|
||||
: SDKScene::SceneWrapperBase(aiScene)
|
||||
{
|
||||
}
|
||||
|
||||
AssImpSceneWrapper::~AssImpSceneWrapper()
|
||||
: m_assImpScene(aiScene)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -114,6 +109,11 @@ namespace AZ
|
||||
m_importer.FreeScene();
|
||||
}
|
||||
|
||||
const aiScene* AssImpSceneWrapper::GetAssImpScene() const
|
||||
{
|
||||
return m_assImpScene;
|
||||
}
|
||||
|
||||
AZStd::pair<AssImpSceneWrapper::AxisVector, int32_t> AssImpSceneWrapper::GetUpVectorAndSign() const
|
||||
{
|
||||
AZStd::pair<AssImpSceneWrapper::AxisVector, int32_t> result(AxisVector::Z, 1);
|
||||
|
||||
@@ -21,13 +21,14 @@ namespace AZ
|
||||
AZ_RTTI(AssImpSceneWrapper, "{43A61F62-DCD4-4132-B80B-F2FBC80740BC}", SDKScene::SceneWrapperBase);
|
||||
AssImpSceneWrapper();
|
||||
AssImpSceneWrapper(aiScene* aiScene);
|
||||
~AssImpSceneWrapper();
|
||||
~AssImpSceneWrapper() override = default;
|
||||
|
||||
bool LoadSceneFromFile(const char* fileName) override;
|
||||
bool LoadSceneFromFile(const AZStd::string& fileName) override;
|
||||
|
||||
const std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() const override;
|
||||
std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() override;
|
||||
virtual const aiScene* GetAssImpScene() const;
|
||||
void Clear() override;
|
||||
|
||||
enum class AxisVector
|
||||
@@ -43,7 +44,7 @@ namespace AZ
|
||||
|
||||
AZStd::string GetSceneFileName() const { return m_sceneFileName; }
|
||||
protected:
|
||||
|
||||
const aiScene* m_assImpScene = nullptr;
|
||||
Assimp::Importer m_importer;
|
||||
|
||||
// FBX SDK automatically resolved relative paths to textures based on the current file location.
|
||||
|
||||
@@ -12,21 +12,6 @@ namespace AZ
|
||||
{
|
||||
namespace SDKMaterial
|
||||
{
|
||||
MaterialWrapper::MaterialWrapper(aiMaterial* assImpMaterial)
|
||||
: m_assImpMaterial(assImpMaterial)
|
||||
{
|
||||
}
|
||||
|
||||
MaterialWrapper::~MaterialWrapper()
|
||||
{
|
||||
m_assImpMaterial = nullptr;
|
||||
}
|
||||
|
||||
aiMaterial* MaterialWrapper::GetAssImpMaterial()
|
||||
{
|
||||
return m_assImpMaterial;
|
||||
}
|
||||
|
||||
AZStd::string MaterialWrapper::GetName() const
|
||||
{
|
||||
return AZStd::string();
|
||||
|
||||
@@ -34,10 +34,7 @@ namespace AZ
|
||||
BaseColor
|
||||
};
|
||||
|
||||
MaterialWrapper(aiMaterial* assImpmaterial);
|
||||
virtual ~MaterialWrapper();
|
||||
|
||||
aiMaterial* GetAssImpMaterial();
|
||||
virtual ~MaterialWrapper() = default;
|
||||
|
||||
virtual AZStd::string GetName() const;
|
||||
virtual AZ::u64 GetUniqueId() const;
|
||||
@@ -47,9 +44,6 @@ namespace AZ
|
||||
virtual AZ::Vector3 GetEmissiveColor() const;
|
||||
virtual float GetOpacity() const;
|
||||
virtual float GetShininess() const;
|
||||
|
||||
protected:
|
||||
aiMaterial* m_assImpMaterial = nullptr;
|
||||
};
|
||||
} // namespace SDKMaterial
|
||||
} // namespace AZ
|
||||
|
||||
@@ -12,21 +12,6 @@ namespace AZ
|
||||
{
|
||||
namespace SDKNode
|
||||
{
|
||||
NodeWrapper::NodeWrapper(aiNode* aiNode)
|
||||
: m_assImpNode(aiNode)
|
||||
{
|
||||
}
|
||||
|
||||
NodeWrapper::~NodeWrapper()
|
||||
{
|
||||
m_assImpNode = nullptr;
|
||||
}
|
||||
|
||||
aiNode* NodeWrapper::GetAssImpNode()
|
||||
{
|
||||
return m_assImpNode;
|
||||
}
|
||||
|
||||
const char* NodeWrapper::GetName() const
|
||||
{
|
||||
return "";
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace AZ
|
||||
public:
|
||||
AZ_RTTI(NodeWrapper, "{5EB0897B-9728-44B7-B056-BA34AAF14715}");
|
||||
|
||||
NodeWrapper() = default;
|
||||
NodeWrapper(aiNode* aiNode);
|
||||
virtual ~NodeWrapper();
|
||||
virtual ~NodeWrapper() = default;
|
||||
|
||||
enum CurveNodeComponent
|
||||
{
|
||||
@@ -31,16 +29,12 @@ namespace AZ
|
||||
Component_Z
|
||||
};
|
||||
|
||||
aiNode* GetAssImpNode();
|
||||
|
||||
virtual const char* GetName() const;
|
||||
virtual AZ::u64 GetUniqueId() const;
|
||||
virtual int GetMaterialCount() const;
|
||||
|
||||
virtual int GetChildCount()const;
|
||||
virtual const std::shared_ptr<NodeWrapper> GetChild(int childIndex) const;
|
||||
|
||||
aiNode* m_assImpNode = nullptr;
|
||||
};
|
||||
} //namespace Node
|
||||
} //namespace AZ
|
||||
|
||||
@@ -13,12 +13,6 @@ namespace AZ
|
||||
{
|
||||
const char* SceneWrapperBase::s_defaultSceneName = "myScene";
|
||||
|
||||
SceneWrapperBase::SceneWrapperBase(aiScene* aiScene)
|
||||
: m_assImpScene(aiScene)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool SceneWrapperBase::LoadSceneFromFile([[maybe_unused]] const char* fileName)
|
||||
{
|
||||
return false;
|
||||
@@ -40,12 +34,5 @@ namespace AZ
|
||||
void SceneWrapperBase::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
const aiScene* SceneWrapperBase::GetAssImpScene() const
|
||||
{
|
||||
return m_assImpScene;
|
||||
}
|
||||
|
||||
|
||||
} //namespace Scene
|
||||
}// namespace AZ
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace AZ
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(SceneWrapperBase, "{703CD344-2C75-4F30-8CE2-6BDEF2511AFD}");
|
||||
SceneWrapperBase() = default;
|
||||
virtual ~SceneWrapperBase() = default;
|
||||
SceneWrapperBase(aiScene* aiScene);
|
||||
|
||||
virtual bool LoadSceneFromFile(const char* fileName);
|
||||
virtual bool LoadSceneFromFile(const AZStd::string& fileName);
|
||||
@@ -31,10 +29,6 @@ namespace AZ
|
||||
virtual std::shared_ptr<SDKNode::NodeWrapper> GetRootNode();
|
||||
|
||||
virtual void Clear();
|
||||
|
||||
virtual const aiScene* GetAssImpScene() const;
|
||||
|
||||
const aiScene* m_assImpScene = nullptr;
|
||||
|
||||
static const char* s_defaultSceneName;
|
||||
};
|
||||
|
||||
@@ -56,9 +56,9 @@ namespace AZ
|
||||
Events::ProcessingResultCombiner combinedMaterialImportResults;
|
||||
|
||||
AZStd::unordered_map<int, AZStd::shared_ptr<SceneData::GraphData::MaterialData>> materialMap;
|
||||
for (unsigned int idx = 0; idx < context.m_sourceNode.m_assImpNode->mNumMeshes; ++idx)
|
||||
for (unsigned int idx = 0; idx < context.m_sourceNode.GetAssImpNode()->mNumMeshes; ++idx)
|
||||
{
|
||||
int meshIndex = context.m_sourceNode.m_assImpNode->mMeshes[idx];
|
||||
int meshIndex = context.m_sourceNode.GetAssImpNode()->mMeshes[idx];
|
||||
const aiMesh* assImpMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshIndex];
|
||||
AZ_Assert(assImpMesh, "Asset Importer Mesh should not be null.");
|
||||
int materialIndex = assImpMesh->mMaterialIndex;
|
||||
|
||||
@@ -222,7 +222,12 @@ namespace AZ
|
||||
int childCount = node.m_node->GetChildCount();
|
||||
for (int i = 0; i < childCount; ++i)
|
||||
{
|
||||
std::shared_ptr<AssImpSDKWrapper::AssImpNodeWrapper> child = std::make_shared<AssImpSDKWrapper::AssImpNodeWrapper>(node.m_node->GetChild(i)->GetAssImpNode());
|
||||
const std::shared_ptr<SDKNode::NodeWrapper> nodeWrapper = node.m_node->GetChild(i);
|
||||
auto assImpNodeWrapper = azrtti_cast<AssImpSDKWrapper::AssImpNodeWrapper*>(nodeWrapper.get());
|
||||
|
||||
AZ_Assert(assImpNodeWrapper, "Child node is not the expected AssImpNodeWrapper type");
|
||||
|
||||
std::shared_ptr<AssImpSDKWrapper::AssImpNodeWrapper> child = std::make_shared<AssImpSDKWrapper::AssImpNodeWrapper>(assImpNodeWrapper->GetAssImpNode());
|
||||
if (child)
|
||||
{
|
||||
nodes.emplace(AZStd::move(child), newNode);
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> AssetImportRequest::LoadSceneFromVerifiedPath(const AZStd::string& assetFilePath, const Uuid& sourceGuid,
|
||||
RequestingApplication requester)
|
||||
RequestingApplication requester, const Uuid& loadingComponentUuid)
|
||||
{
|
||||
AZStd::string sceneName;
|
||||
AzFramework::StringFunc::Path::GetFileName(assetFilePath.c_str(), sceneName);
|
||||
@@ -113,7 +113,7 @@ namespace AZ
|
||||
|
||||
// Unique pointer, will deactivate and clean up once going out of scope.
|
||||
SceneCore::EntityConstructor::EntityPointer loaders =
|
||||
SceneCore::EntityConstructor::BuildEntity("Scene Loading", SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
SceneCore::EntityConstructor::BuildEntity("Scene Loading", loadingComponentUuid);
|
||||
|
||||
ProcessingResultCombiner areAllPrepared;
|
||||
AssetImportRequestBus::BroadcastResult(areAllPrepared, &AssetImportRequestBus::Events::PrepareForAssetLoading, *scene, requester);
|
||||
|
||||
@@ -102,8 +102,9 @@ namespace AZ
|
||||
//! @param sourceGuid The guid assigned to the source file (not the manifest).
|
||||
//! @param requester The application making the request to load the file. This can be used to optimize the type and amount of data
|
||||
//! to load.
|
||||
//! @param loadingComponentUuid The UUID assigned to the loading component.
|
||||
static AZStd::shared_ptr<Containers::Scene> LoadSceneFromVerifiedPath(const AZStd::string& assetFilePath,
|
||||
const Uuid&sourceGuid, RequestingApplication requester);
|
||||
const Uuid& sourceGuid, RequestingApplication requester, const Uuid& loadingComponentUuid);
|
||||
|
||||
//! Utility function to determine if a given file path points to a scene manifest file (.assetinfo).
|
||||
//! @param filePath A relative or absolute path to the file to check.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Math/Guid.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
||||
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
|
||||
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
|
||||
#include <SceneAPI/SceneCore/Mocks/Events/MockAssetImportRequest.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -184,7 +185,7 @@ namespace AZ
|
||||
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> result =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic, SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
EXPECT_EQ(nullptr, result);
|
||||
}
|
||||
|
||||
@@ -207,7 +208,7 @@ namespace AZ
|
||||
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> result =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic, SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
EXPECT_EQ(nullptr, result);
|
||||
}
|
||||
|
||||
@@ -230,7 +231,7 @@ namespace AZ
|
||||
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> result =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic, SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
EXPECT_EQ(nullptr, result);
|
||||
}
|
||||
|
||||
@@ -253,7 +254,7 @@ namespace AZ
|
||||
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> result =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic, SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
EXPECT_EQ(nullptr, result);
|
||||
}
|
||||
|
||||
@@ -285,7 +286,7 @@ namespace AZ
|
||||
EXPECT_CALL(manifestHandler, UpdateManifest(_, _, _)).Times(1);
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> result =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic, SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
EXPECT_EQ(nullptr, result);
|
||||
}
|
||||
|
||||
@@ -313,7 +314,7 @@ namespace AZ
|
||||
EXPECT_CALL(manifestHandler, UpdateManifest(_, _, _)).Times(1);
|
||||
|
||||
AZStd::shared_ptr<Containers::Scene> result =
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
|
||||
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic, SceneCore::LoadingComponent::TYPEINFO_Uuid());
|
||||
EXPECT_NE(nullptr, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace AZ
|
||||
// Register Shader Asset Builder
|
||||
AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor;
|
||||
shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder";
|
||||
shaderAssetBuilderDescriptor.m_version = 102; // ATOM-15472
|
||||
shaderAssetBuilderDescriptor.m_version = 103; // ATOM-15058
|
||||
// .shader file changes trigger rebuilds
|
||||
shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
||||
shaderAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderAssetBuilder>();
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
|
||||
#define MCPP_DLL_IMPORT 1
|
||||
#define MCPP_DONT_USE_SHORT_NAMES 1
|
||||
#include <mcpp_lib.h>
|
||||
#undef MCPP_DLL_IMPORT
|
||||
|
||||
#include <CommonFiles/Preprocessor.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
@@ -31,8 +26,6 @@
|
||||
|
||||
#include <AtomCore/Serialization/Json/JsonUtils.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace ShaderBuilder
|
||||
@@ -83,124 +76,125 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
//! Binder helper to Matsui C-Pre-Processor library
|
||||
class McppBinder
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// McppBinder starts
|
||||
bool McppBinder::StartPreprocessWithCommandLine(int argc, const char* argv[])
|
||||
{
|
||||
public:
|
||||
McppBinder(PreprocessorData& out, bool plugERR)
|
||||
: m_outputData(out),
|
||||
m_plugERR(plugERR)
|
||||
int errorCode = mcpp_lib_main(argc, argv);
|
||||
// convert from std::ostringstring to AZStd::string
|
||||
m_outputData.code = m_outStream.str().c_str();
|
||||
m_outputData.diagnostics = m_errStream.str().c_str();
|
||||
return errorCode == 0;
|
||||
}
|
||||
|
||||
int McppBinder::Putc_StaticHinge(int c, MCPP_OUTDEST od)
|
||||
{
|
||||
char asString[2] = { aznumeric_cast<char>(c), 0 };
|
||||
return Fputs_StaticHinge(asString, od);
|
||||
}
|
||||
|
||||
int McppBinder::Fputs_StaticHinge(const char* s, MCPP_OUTDEST od)
|
||||
{
|
||||
if (!OkToLog(od))
|
||||
{
|
||||
// single live instance
|
||||
s_mcppExclusiveProtection.lock();
|
||||
s_currentInstance = this;
|
||||
SetupMcppCallbacks();
|
||||
return 0;
|
||||
}
|
||||
~McppBinder()
|
||||
// chose the proper stream
|
||||
auto& selectedStream = od == MCPP_OUT ? s_currentInstance->m_outStream : s_currentInstance->m_errStream;
|
||||
auto tellBefore = selectedStream.tellp();
|
||||
// append that message to it
|
||||
selectedStream << s;
|
||||
return aznumeric_cast<int>(selectedStream.tellp() - tellBefore);
|
||||
}
|
||||
|
||||
int McppBinder::Fprintf_StaticHinge(MCPP_OUTDEST od, const char* format, ...)
|
||||
{
|
||||
if (!OkToLog(od))
|
||||
{
|
||||
s_currentInstance = nullptr;
|
||||
s_mcppExclusiveProtection.unlock();
|
||||
return 0;
|
||||
}
|
||||
// run the formatting on stack memory first, in case it's enough
|
||||
char localBuffer[DefaultFprintfBufferSize];
|
||||
|
||||
bool StartPreprocessWithCommandLine(int argc, const char* argv[])
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
int count = azvsnprintf(localBuffer, DefaultFprintfBufferSize, format, args);
|
||||
va_end(args);
|
||||
|
||||
char* result = localBuffer;
|
||||
|
||||
// @result will be bound to @biggerData in case @localBuffer is not big enough.
|
||||
std::unique_ptr<char[]> biggerData;
|
||||
// ">=" is the right comparison because in case count == bufferSize
|
||||
// We will need an extra byte to accomodate the '\0' ending character.
|
||||
if (count >= DefaultFprintfBufferSize)
|
||||
{
|
||||
int errorCode = mcpp_lib_main(argc, argv);
|
||||
// convert from std::ostringstring to AZStd::string
|
||||
m_outputData.code = m_outStream.str().c_str();
|
||||
m_outputData.diagnostics = m_errStream.str().c_str();
|
||||
return errorCode == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// ====== C-API compatible "Static Hinges" (plain free functions) ======
|
||||
// : capturing-lambdas, function-objects, bind-expression; can't be decayed to function pointers,
|
||||
// because they hold runtime-dynamic type-erased states. So we need intermediates
|
||||
|
||||
// entry point from mcpp. hijacking its output
|
||||
static int Putc_StaticHinge(int c, MCPP_OUTDEST od)
|
||||
{
|
||||
char asString[2] = { aznumeric_cast<char>(c), 0 };
|
||||
return Fputs_StaticHinge(asString, od);
|
||||
}
|
||||
|
||||
// entry point from mcpp. hijacking its output
|
||||
static int Fputs_StaticHinge(const char* s, MCPP_OUTDEST od)
|
||||
{
|
||||
if (!OkToLog(od))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// chose the proper stream
|
||||
auto& selectedStream = od == MCPP_OUT ? s_currentInstance->m_outStream : s_currentInstance->m_errStream;
|
||||
auto tellBefore = selectedStream.tellp();
|
||||
// append that message to it
|
||||
selectedStream << s;
|
||||
return aznumeric_cast<int>(selectedStream.tellp() - tellBefore);
|
||||
}
|
||||
|
||||
// entry point from mcpp. hijacking its output
|
||||
static int Fprintf_StaticHinge(MCPP_OUTDEST od, const char* format, ...)
|
||||
{
|
||||
if (!OkToLog(od))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// run the formatting on stack memory first, in case it's enough
|
||||
constexpr int bufferSize = 256;
|
||||
char localBuffer[bufferSize];
|
||||
va_list args;
|
||||
// There wasn't enough space in the local store.
|
||||
count++; // vsnprintf returns a size that doesn't include the null character.
|
||||
biggerData.reset(new char[count]);
|
||||
result = &biggerData[0];
|
||||
|
||||
// Remark: for MacOS & Linux it is important to call va_start again before
|
||||
// each call to azvsnprintf. Not required for Windows.
|
||||
va_start(args, format);
|
||||
int count = azvsnprintf(localBuffer, 256, format, args);
|
||||
AZStd::unique_ptr<char[]> biggerData; // will be bound to a bigger array if necessary.
|
||||
char* result = localBuffer;
|
||||
if (count > bufferSize)
|
||||
{ // there wasn't enough space in the local store.
|
||||
biggerData.reset(new char[count]);
|
||||
result = &biggerData[0]; // change `result`'s pointee
|
||||
count = azvsnprintf(result, count, format, args);
|
||||
}
|
||||
AZ_Error("Preprocessor", count >= 0, "String formatting of pre-precessor output failed");
|
||||
count = azvsnprintf(result, count, format, args);
|
||||
va_end(args);
|
||||
return Fputs_StaticHinge(result, od);
|
||||
}
|
||||
|
||||
static void IncludeReport_StaticHinge(FILE*, const char*, const char*, const char* path)
|
||||
else if (count == -1)
|
||||
{
|
||||
s_currentInstance->m_outputData.includedPaths.insert(path);
|
||||
// In Windows azvsnprintf will always return -1 if @localBuffer is not big enough,
|
||||
// But it will write in @localBuffer what it could.
|
||||
// See:
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l?view=msvc-160
|
||||
// In particular: "If the number of characters to write is greater than count,
|
||||
// these functions return -1 indicating that output has been truncated."
|
||||
|
||||
// There wasn't enough space in the local store.
|
||||
// Remark: for MacOS & Linux it is important to call va_start again before
|
||||
// each call to azvsnprintf. Not required for Windows.
|
||||
va_start(args, format);
|
||||
count = azvscprintf(format, args) + 1; // vscprintf returns a size that doesn't include the null character.
|
||||
va_end(args);
|
||||
|
||||
biggerData.reset(new char[count]);
|
||||
result = &biggerData[0];
|
||||
|
||||
va_start(args, format);
|
||||
count = azvsnprintf(result, count, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// ====== utility methods =====
|
||||
AZ_Error("Preprocessor", count >= 0, "String formatting of pre-precessor output failed");
|
||||
return Fputs_StaticHinge(result, od);
|
||||
}
|
||||
|
||||
static bool OkToLog(MCPP_OUTDEST od)
|
||||
{
|
||||
bool isErrButOk = od == MCPP_ERR && s_currentInstance->m_plugERR;
|
||||
return od == MCPP_OUT || isErrButOk;
|
||||
}
|
||||
void McppBinder::IncludeReport_StaticHinge(FILE*, const char*, const char*, const char* path)
|
||||
{
|
||||
s_currentInstance->m_outputData.includedPaths.insert(path);
|
||||
}
|
||||
|
||||
static void SetupMcppCallbacks()
|
||||
{
|
||||
// callback for header included notification
|
||||
mcpp_set_report_include_callback(IncludeReport_StaticHinge);
|
||||
// callback for output redirection
|
||||
mcpp_set_out_func(Putc_StaticHinge, Fputs_StaticHinge, Fprintf_StaticHinge);
|
||||
}
|
||||
bool McppBinder::OkToLog(MCPP_OUTDEST od)
|
||||
{
|
||||
bool isErrButOk = od == MCPP_ERR && s_currentInstance->m_plugERR;
|
||||
return od == MCPP_OUT || isErrButOk;
|
||||
}
|
||||
|
||||
// ====== instance data ======
|
||||
PreprocessorData& m_outputData;
|
||||
std::ostringstream m_outStream, m_errStream;
|
||||
bool m_plugERR;
|
||||
|
||||
// ====== shared data ======
|
||||
// MCPP is a library with tons of non TLS global states, it can only be accessed by one client at a time.
|
||||
static AZStd::mutex s_mcppExclusiveProtection;
|
||||
static McppBinder* s_currentInstance;
|
||||
};
|
||||
void McppBinder::SetupMcppCallbacks()
|
||||
{
|
||||
// callback for header included notification
|
||||
mcpp_set_report_include_callback(IncludeReport_StaticHinge);
|
||||
// callback for output redirection
|
||||
mcpp_set_out_func(Putc_StaticHinge, Fputs_StaticHinge, Fprintf_StaticHinge);
|
||||
}
|
||||
|
||||
// definitions for the linker
|
||||
AZStd::mutex McppBinder::s_mcppExclusiveProtection;
|
||||
McppBinder* McppBinder::s_currentInstance = nullptr;
|
||||
|
||||
// McppBinder ends
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PreprocessFile(const AZStd::string& fullPath, PreprocessorData& outputData, const PreprocessorOptions& options
|
||||
, bool collectDiagnostics, bool preprocessIncludedFiles)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,18 @@
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/Serialization/DataPatch.h>
|
||||
|
||||
#define MCPP_DLL_IMPORT 1
|
||||
#define MCPP_DONT_USE_SHORT_NAMES 1
|
||||
#include <mcpp_lib.h>
|
||||
#undef MCPP_DLL_IMPORT
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class McppBinderTests;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace ShaderBuilder
|
||||
@@ -93,5 +105,64 @@ namespace AZ
|
||||
AZStd::string& sourceCode,
|
||||
AZStd::string newFileOrigin);
|
||||
|
||||
//! Binder helper to Matsui C-Pre-Processor library
|
||||
class McppBinder
|
||||
{
|
||||
public:
|
||||
McppBinder(PreprocessorData& out, bool plugERR)
|
||||
: m_outputData(out)
|
||||
, m_plugERR(plugERR)
|
||||
{
|
||||
// single live instance
|
||||
s_mcppExclusiveProtection.lock();
|
||||
s_currentInstance = this;
|
||||
SetupMcppCallbacks();
|
||||
}
|
||||
~McppBinder()
|
||||
{
|
||||
s_currentInstance = nullptr;
|
||||
s_mcppExclusiveProtection.unlock();
|
||||
}
|
||||
|
||||
// This constant is in the header so McppBinderTests can see it.
|
||||
static constexpr int DefaultFprintfBufferSize = 256;
|
||||
|
||||
bool StartPreprocessWithCommandLine(int argc, const char* argv[]);
|
||||
|
||||
private:
|
||||
friend class ::UnitTest::McppBinderTests;
|
||||
|
||||
// ====== C-API compatible "Static Hinges" (plain free functions) ======
|
||||
// : capturing-lambdas, function-objects, bind-expression; can't be decayed to function pointers,
|
||||
// because they hold runtime-dynamic type-erased states. So we need intermediates
|
||||
|
||||
// entry point from mcpp. hijacking its output
|
||||
static int Putc_StaticHinge(int c, MCPP_OUTDEST od);
|
||||
|
||||
// entry point from mcpp. hijacking its output
|
||||
static int Fputs_StaticHinge(const char* s, MCPP_OUTDEST od);
|
||||
|
||||
// entry point from mcpp. hijacking its output
|
||||
static int Fprintf_StaticHinge(MCPP_OUTDEST od, const char* format, ...);
|
||||
|
||||
static void IncludeReport_StaticHinge(FILE*, const char*, const char*, const char* path);
|
||||
|
||||
// ====== utility methods =====
|
||||
|
||||
static bool OkToLog(MCPP_OUTDEST od);
|
||||
|
||||
static void SetupMcppCallbacks();
|
||||
|
||||
// ====== instance data ======
|
||||
PreprocessorData& m_outputData;
|
||||
std::ostringstream m_outStream, m_errStream;
|
||||
bool m_plugERR;
|
||||
|
||||
// ====== shared data ======
|
||||
// MCPP is a library with tons of non TLS global states, it can only be accessed by one client at a time.
|
||||
static AZStd::mutex s_mcppExclusiveProtection;
|
||||
static McppBinder* s_currentInstance;
|
||||
};
|
||||
|
||||
} // ShaderBuilder
|
||||
} // AZ
|
||||
|
||||
@@ -226,11 +226,9 @@ namespace AZ
|
||||
|
||||
if (!hasRasterProgram && !hasComputeProgram && !hasRayTracingProgram)
|
||||
{
|
||||
AZStd::string entryPointNames = ShaderBuilderUtility::GetAcceptableDefaultEntryPointNames(azslData);
|
||||
return AZ::Failure(
|
||||
AZStd::string::format( "Shader asset descriptor has a program variant that does not define any entry points. Either declare entry "
|
||||
"points in the .shader file, or use one of the available default names (not case-sensitive): [%s]",
|
||||
entryPointNames.c_str()));
|
||||
AZStd::string( "Shader asset descriptor has a program variant that does not define any entry points."
|
||||
" Please declare entry points in the .shader file."));
|
||||
}
|
||||
|
||||
return AZ::Success(attributeMaps);
|
||||
@@ -478,21 +476,18 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
// Discover entry points & type of programs.
|
||||
MapOfStringToStageType shaderEntryPoints;
|
||||
if (shaderSourceData.m_programSettings.m_entryPoints.empty())
|
||||
{
|
||||
AZ_TracePrintf(
|
||||
ShaderAssetBuilderName,
|
||||
"ProgramSettings do not specify entry points, will use GetDefaultEntryPointsFromShader()\n");
|
||||
ShaderBuilderUtility::GetDefaultEntryPointsFromFunctionDataList(azslData.m_functions, shaderEntryPoints);
|
||||
AZ_Error( ShaderAssetBuilderName, false, "ProgramSettings must specify entry points.");
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// Discover entry points & type of programs.
|
||||
MapOfStringToStageType shaderEntryPoints;
|
||||
for (const auto& entryPoint : shaderSourceData.m_programSettings.m_entryPoints)
|
||||
{
|
||||
for (const auto& entryPoint : shaderSourceData.m_programSettings.m_entryPoints)
|
||||
{
|
||||
shaderEntryPoints[entryPoint.m_name] = entryPoint.m_type;
|
||||
}
|
||||
shaderEntryPoints[entryPoint.m_name] = entryPoint.m_type;
|
||||
}
|
||||
|
||||
bool hasRasterProgram = false;
|
||||
|
||||
@@ -809,91 +809,6 @@ namespace AZ
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
//! Returns a list of acceptable default entry point names
|
||||
static void GetAcceptableDefaultEntryPoints(
|
||||
const AZStd::vector<FunctionData>& azslFunctionDataList,
|
||||
AZStd::unordered_map<AZStd::string, RPI::ShaderStageType>& defaultEntryPoints)
|
||||
{
|
||||
for (const auto& func : azslFunctionDataList)
|
||||
{
|
||||
if (!func.m_hasShaderStageVaryings)
|
||||
{
|
||||
// Not declaring any semantics for a shader entry is valid, but unusual.
|
||||
// A shader entry with no semantics must be explicitly listed and won't be selected by default.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (func.m_name.starts_with("VS") || func.m_name.ends_with("VS"))
|
||||
{
|
||||
defaultEntryPoints[func.m_name] = RPI::ShaderStageType::Vertex;
|
||||
AZ_TracePrintf(
|
||||
ShaderBuilderUtilityName, "Assuming \"%s\" is a valid Vertex shader entry point.\n", func.m_name.c_str());
|
||||
}
|
||||
else if (func.m_name.starts_with("PS") || func.m_name.ends_with("PS"))
|
||||
{
|
||||
defaultEntryPoints[func.m_name] = RPI::ShaderStageType::Fragment;
|
||||
AZ_TracePrintf(
|
||||
ShaderBuilderUtilityName, "Assuming \"%s\" is a valid Fragment shader entry point.\n",
|
||||
func.m_name.c_str());
|
||||
}
|
||||
else if (func.m_name.starts_with("CS") || func.m_name.ends_with("CS"))
|
||||
{
|
||||
defaultEntryPoints[func.m_name] = RPI::ShaderStageType::Compute;
|
||||
AZ_TracePrintf(
|
||||
ShaderBuilderUtilityName, "Assuming \"%s\" is a valid Compute shader entry point.\n", func.m_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DEPRECATED [ATOM-15472
|
||||
//! Returns a list of acceptable default entry point names
|
||||
//! This function
|
||||
static void GetAcceptableDefaultEntryPoints(
|
||||
const AzslData& azslData, AZStd::unordered_map<AZStd::string, RPI::ShaderStageType>& defaultEntryPoints)
|
||||
{
|
||||
return GetAcceptableDefaultEntryPoints(azslData.m_functions, defaultEntryPoints);
|
||||
}
|
||||
|
||||
|
||||
void GetDefaultEntryPointsFromFunctionDataList(
|
||||
const AZStd::vector<FunctionData> azslFunctionDataList,
|
||||
AZStd::unordered_map<AZStd::string, RPI::ShaderStageType>& shaderEntryPoints)
|
||||
{
|
||||
AZStd::unordered_map<AZStd::string, RPI::ShaderStageType> defaultEntryPoints;
|
||||
GetAcceptableDefaultEntryPoints(azslFunctionDataList, defaultEntryPoints);
|
||||
|
||||
for (const auto& functionData : azslFunctionDataList)
|
||||
{
|
||||
for (const auto& defaultEntryPoint : defaultEntryPoints)
|
||||
{
|
||||
// Equal defaults to case insensitive compares...
|
||||
if (AzFramework::StringFunc::Equal(defaultEntryPoint.first.c_str(), functionData.m_name.c_str()))
|
||||
{
|
||||
shaderEntryPoints[defaultEntryPoint.first] = defaultEntryPoint.second;
|
||||
break; // stop looping default entry points and go to the next shader function
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string GetAcceptableDefaultEntryPointNames(const AzslData& azslData)
|
||||
{
|
||||
AZStd::unordered_map<AZStd::string, RPI::ShaderStageType> defaultEntryPointList;
|
||||
GetAcceptableDefaultEntryPoints(azslData, defaultEntryPointList);
|
||||
|
||||
AZStd::vector<AZStd::string> defaultEntryPointNamesList;
|
||||
for (const auto& shaderEntryPoint : defaultEntryPointList)
|
||||
{
|
||||
defaultEntryPointNamesList.push_back(shaderEntryPoint.first);
|
||||
}
|
||||
AZStd::string shaderEntryPoints;
|
||||
AzFramework::StringFunc::Join(
|
||||
shaderEntryPoints, defaultEntryPointNamesList.begin(), defaultEntryPointNamesList.end(), ", ");
|
||||
return AZStd::move(shaderEntryPoints);
|
||||
}
|
||||
|
||||
} // namespace ShaderBuilderUtility
|
||||
} // namespace ShaderBuilder
|
||||
} // AZ
|
||||
|
||||
@@ -94,10 +94,6 @@ namespace AZ
|
||||
RPI::ShaderOutputContract& shaderOutputContract, size_t& colorAttachmentCount);
|
||||
|
||||
|
||||
//! Returns a list of acceptable default entry point names as a single string for debug messages.
|
||||
AZStd::string GetAcceptableDefaultEntryPointNames(const AzslData& shaderData);
|
||||
|
||||
|
||||
//! Create a file from a string's content.
|
||||
//! That file will be named filename.api.azslin
|
||||
//! This is meant to be used at this stage:
|
||||
@@ -138,10 +134,6 @@ namespace AZ
|
||||
AZStd::vector<RPI::ShaderSourceData::SupervariantInfo> GetSupervariantListFromShaderSourceData(
|
||||
const RPI::ShaderSourceData& shaderSourceData);
|
||||
|
||||
void GetDefaultEntryPointsFromFunctionDataList(
|
||||
const AZStd::vector<FunctionData> azslFunctionDataList,
|
||||
AZStd::unordered_map<AZStd::string, RPI::ShaderStageType>& shaderEntryPoints);
|
||||
|
||||
void LogProfilingData(const char* builderName, AZStd::string_view shaderPath);
|
||||
|
||||
//! Returns the asset path of a product artifact produced by ShaderAssetBuilder.
|
||||
|
||||
@@ -843,17 +843,14 @@ namespace AZ
|
||||
MapOfStringToStageType shaderEntryPoints;
|
||||
if (shaderSourceDescriptor.m_programSettings.m_entryPoints.empty())
|
||||
{
|
||||
AZ_TracePrintf(
|
||||
ShaderVariantAssetBuilderName,
|
||||
"ProgramSettings do not specify entry points, will use GetDefaultEntryPointsFromShader()\n");
|
||||
ShaderBuilderUtility::GetDefaultEntryPointsFromFunctionDataList(azslFunctions, shaderEntryPoints);
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "ProgramSettings must specify entry points.");
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
for (const auto& entryPoint : shaderSourceDescriptor.m_programSettings.m_entryPoints)
|
||||
{
|
||||
for (const auto& entryPoint : shaderSourceDescriptor.m_programSettings.m_entryPoints)
|
||||
{
|
||||
shaderEntryPoints[entryPoint.m_name] = entryPoint.m_type;
|
||||
}
|
||||
shaderEntryPoints[entryPoint.m_name] = entryPoint.m_type;
|
||||
}
|
||||
|
||||
// 3- hlslCode
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include "Common/ShaderBuilderTestFixture.h"
|
||||
|
||||
#include <CommonFiles/Preprocessor.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace AZ;
|
||||
|
||||
// The main purpose of this class is to test ShaderBuilder::McppBinder::Fprintf_StaticHinge()
|
||||
// Which has three common scenarios to validate.
|
||||
// 1- The formatted string is expected to yield less bytes than McppBinder::DefaultFprintfBufferSize.
|
||||
// 2- The formatted string is expected to yield exactly McppBinder::DefaultFprintfBufferSize number of bytes.
|
||||
// 3- The formatted string is expectedc to yield more bytes than McppBinder::DefaultFprintfBufferSize.
|
||||
class McppBinderTests : public ShaderBuilderTestFixture
|
||||
{
|
||||
public:
|
||||
|
||||
// Fills @buffer with 'a' to 'z' for up to @bufferSize number of bytes.
|
||||
// This function will null('\0') char terminate @buffer.
|
||||
void FillBufferWithAlphabet(char* buffer, int bufferSize)
|
||||
{
|
||||
for (int bufferPos = 0, rollback = 0; bufferPos < (bufferSize - 1); ++bufferPos)
|
||||
{
|
||||
const char value = 'a' + rollback++;
|
||||
buffer[bufferPos] = value;
|
||||
if (value == 'z')
|
||||
{
|
||||
rollback = 0;
|
||||
}
|
||||
}
|
||||
buffer[bufferSize - 1] = '\0';
|
||||
}
|
||||
|
||||
// Pushes the null terminated string, @inputString, into McppBinder capture stream
|
||||
// using McppBinder::Fprintf_StaticHinge().
|
||||
// Returns the content of the McppBinder capture stream as a string.
|
||||
AZStd::string PrintStringThroughStaticHinge(const char* inputString)
|
||||
{
|
||||
ShaderBuilder::PreprocessorData preprocessorData;
|
||||
ShaderBuilder::McppBinder mcppBinder(preprocessorData, false);
|
||||
ShaderBuilder::McppBinder::Fprintf_StaticHinge(MCPP_OUTDEST::MCPP_OUT, "%s", inputString);
|
||||
// convert from std::ostringstring to AZStd::string
|
||||
return AZStd::string(mcppBinder.m_outStream.str().c_str());
|
||||
}
|
||||
}; // class McppBinderTests
|
||||
|
||||
|
||||
TEST_F(McppBinderTests, ShouldPrintLessBytesThanDefaultSize)
|
||||
{
|
||||
constexpr int bufferSize = (ShaderBuilder::McppBinder::DefaultFprintfBufferSize / 2) + 1;
|
||||
EXPECT_TRUE(bufferSize > 0);
|
||||
char buffer[bufferSize] = "";
|
||||
FillBufferWithAlphabet(buffer, bufferSize);
|
||||
auto printedString = PrintStringThroughStaticHinge(buffer);
|
||||
EXPECT_EQ(AZStd::string(buffer), printedString);
|
||||
}
|
||||
|
||||
TEST_F(McppBinderTests, ShouldPrintSameBytesAsDefaultSize)
|
||||
{
|
||||
constexpr int bufferSize = ShaderBuilder::McppBinder::DefaultFprintfBufferSize + 1;
|
||||
EXPECT_TRUE(bufferSize > 0);
|
||||
char buffer[bufferSize] = "";
|
||||
FillBufferWithAlphabet(buffer, bufferSize);
|
||||
auto printedString = PrintStringThroughStaticHinge(buffer);
|
||||
EXPECT_EQ(AZStd::string(buffer), printedString);
|
||||
}
|
||||
|
||||
TEST_F(McppBinderTests, ShouldPrintMoreBytesThanDefaultSize)
|
||||
{
|
||||
constexpr int bufferSize = (ShaderBuilder::McppBinder::DefaultFprintfBufferSize * 2) + 1;
|
||||
EXPECT_TRUE(bufferSize > 0);
|
||||
char buffer[bufferSize] = "";
|
||||
FillBufferWithAlphabet(buffer, bufferSize);
|
||||
auto printedString = PrintStringThroughStaticHinge(buffer);
|
||||
EXPECT_EQ(AZStd::string(buffer), printedString);
|
||||
}
|
||||
|
||||
} //namespace UnitTest
|
||||
|
||||
//AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
|
||||
@@ -10,4 +10,5 @@ set(FILES
|
||||
Tests/Common/ShaderBuilderTestFixture.h
|
||||
Tests/Common/ShaderBuilderTestFixture.cpp
|
||||
Tests/SupervariantCmdArgumentTests.cpp
|
||||
Tests/McppBinderTests.cpp
|
||||
)
|
||||
|
||||
@@ -18,5 +18,20 @@
|
||||
"BlendOp": "Add"
|
||||
},
|
||||
|
||||
"ProgramSettings" :
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "ShadowCatcherVS",
|
||||
"type" : "Vertex"
|
||||
},
|
||||
{
|
||||
"name": "ShadowCatcherPS",
|
||||
"type" : "Fragment"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"DrawList": "transparent"
|
||||
}
|
||||
|
||||
@@ -9,5 +9,16 @@
|
||||
"DisableOptimizations" : false
|
||||
},
|
||||
|
||||
"ProgramSettings" :
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "DepthPassVS",
|
||||
"type" : "Vertex"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"DrawList" : "depth"
|
||||
}
|
||||
|
||||
@@ -13,5 +13,16 @@
|
||||
"CompilerHints" : {
|
||||
},
|
||||
|
||||
"ProgramSettings" :
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "DepthPassVS",
|
||||
"type" : "Vertex"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"DrawList" : "depthTransparentMax"
|
||||
}
|
||||
|
||||
@@ -11,5 +11,16 @@
|
||||
"DisableOptimizations" : false
|
||||
},
|
||||
|
||||
"ProgramSettings" :
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "DepthPassVS",
|
||||
"type" : "Vertex"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"DrawList" : "depthTransparentMin"
|
||||
}
|
||||
|
||||
@@ -1235,7 +1235,8 @@ namespace AZ
|
||||
// ProductMesh. That large buffer gets set on the LOD directly
|
||||
// rather than a Mesh in the LOD.
|
||||
ProductMeshContentAllocInfo lodBufferInfo;
|
||||
|
||||
|
||||
bool isFirstMesh = true;
|
||||
for (const ProductMeshContent& mesh : lodMeshList)
|
||||
{
|
||||
if (lodBufferInfo.m_uvSetFloatCounts.size() < mesh.m_uvSets.size())
|
||||
@@ -1347,6 +1348,14 @@ namespace AZ
|
||||
|
||||
if (!mesh.m_skinJointIndices.empty() && !mesh.m_skinWeights.empty())
|
||||
{
|
||||
if (!isFirstMesh && lodBufferInfo.m_skinInfluencesCount == 0)
|
||||
{
|
||||
AZ_Error(
|
||||
s_builderName, false,
|
||||
"Attempting to merge a mix of static and skinned meshes, this will fail on buffer generation later. Mesh with "
|
||||
"name %s is skinned, but previous meshes were not skinned.",
|
||||
mesh.m_name.GetCStr());
|
||||
}
|
||||
AZ_Assert(mesh.m_skinJointIndices.size() == mesh.m_skinWeights.size(),
|
||||
"Number of skin influence joint indices (%d) should match the number of weights (%d).",
|
||||
mesh.m_skinJointIndices.size(), mesh.m_skinWeights.size());
|
||||
@@ -1363,6 +1372,11 @@ namespace AZ
|
||||
|
||||
lodBufferInfo.m_skinInfluencesCount += numNewSkinInfluences;
|
||||
}
|
||||
else if (lodBufferInfo.m_skinInfluencesCount > 0)
|
||||
{
|
||||
AZ_Error(s_builderName, false, "Attempting to merge a mix of static and skinned meshes, this will fail on buffer generation later. Mesh with name %s is not skinned, but previous meshes were skinned.",
|
||||
mesh.m_name.GetCStr());
|
||||
}
|
||||
|
||||
if (!mesh.m_morphTargetVertexData.empty())
|
||||
{
|
||||
@@ -1375,6 +1389,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
meshViews.emplace_back(AZStd::move(meshView));
|
||||
isFirstMesh = false;
|
||||
}
|
||||
|
||||
// Now that we have the views settled, we can just merge the mesh
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 <AzCore/RTTI/RTTI.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
/**
|
||||
* AtomToolsDocument provides an API for modifying and saving documents.
|
||||
*/
|
||||
class AtomToolsDocument
|
||||
: public AtomToolsDocumentRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AtomToolsDocument, "{8992DF74-88EC-438C-B280-6E71D4C0880B}");
|
||||
AZ_CLASS_ALLOCATOR(AtomToolsDocument, AZ::SystemAllocator, 0);
|
||||
AZ_DISABLE_COPY(AtomToolsDocument);
|
||||
|
||||
AtomToolsDocument();
|
||||
virtual ~AtomToolsDocument();
|
||||
|
||||
const AZ::Uuid& GetId() const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AtomToolsDocumentRequestBus::Handler implementation
|
||||
AZStd::string_view GetAbsolutePath() const override;
|
||||
AZStd::string_view GetRelativePath() const override;
|
||||
const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const override;
|
||||
const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const override;
|
||||
bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override;
|
||||
void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) override;
|
||||
bool Open(AZStd::string_view loadPath) override;
|
||||
bool Reopen() override;
|
||||
bool Save() override;
|
||||
bool SaveAsCopy(AZStd::string_view savePath) override;
|
||||
bool SaveAsChild(AZStd::string_view savePath) override;
|
||||
bool Close() override;
|
||||
bool IsOpen() const override;
|
||||
bool IsModified() const override;
|
||||
bool IsSavable() const override;
|
||||
bool CanUndo() const override;
|
||||
bool CanRedo() const override;
|
||||
bool Undo() override;
|
||||
bool Redo() override;
|
||||
bool BeginEdit() override;
|
||||
bool EndEdit() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
|
||||
// Unique id of this document
|
||||
AZ::Uuid m_id = AZ::Uuid::CreateRandom();
|
||||
|
||||
// Relative path to the material source file
|
||||
AZStd::string m_relativePath;
|
||||
|
||||
// Absolute path to the material source file
|
||||
AZStd::string m_absolutePath;
|
||||
|
||||
AZStd::any m_invalidValue;
|
||||
|
||||
AtomToolsFramework::DynamicProperty m_invalidProperty;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+28
-31
@@ -7,80 +7,77 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/std/any.h>
|
||||
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
class MaterialDocumentNotifications
|
||||
class AtomToolsDocumentNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
|
||||
//! Signal that a material document was created
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was created
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentCreated([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was destroyed
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was destroyed
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentDestroyed([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was opened
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was opened
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentOpened([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was closed
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was closed
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentClosed([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was saved
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was saved
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentSaved([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was selected
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was selected
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentSelected([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was modified
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was modified
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentModified([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document dependency was modified
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document dependency was modified
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentDependencyModified([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document was modified externally
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document was modified externally
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentExternallyModified([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material document undo state was updated
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a document undo state was updated
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
virtual void OnDocumentUndoStateChanged([[maybe_unused]] const AZ::Uuid& documentId) {}
|
||||
|
||||
//! Signal that a material property changed
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! Signal that a property changed
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
//! @param property object containing the property value and configuration that was modified
|
||||
virtual void OnDocumentPropertyValueModified([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AtomToolsFramework::DynamicProperty& property) {}
|
||||
|
||||
//! Signal that the property configuration has been changed.
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
//! @param property object containing the property value and configuration that was modified
|
||||
virtual void OnDocumentPropertyConfigModified([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AtomToolsFramework::DynamicProperty& property) {}
|
||||
|
||||
//! Signal that the property group visibility has been changed.
|
||||
//! @param documentId unique id of material document for which the notification is sent
|
||||
//! @param documentId unique id of document for which the notification is sent
|
||||
//! @param groupId id of the group that changed
|
||||
//! @param visible whether the property group is visible
|
||||
virtual void OnDocumentPropertyGroupVisibilityChanged([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AZ::Name& groupId, [[maybe_unused]] bool visible) {}
|
||||
};
|
||||
|
||||
using MaterialDocumentNotificationBus = AZ::EBus<MaterialDocumentNotifications>;
|
||||
} // namespace MaterialEditor
|
||||
using AtomToolsDocumentNotificationBus = AZ::EBus<AtomToolsDocumentNotifications>;
|
||||
} // namespace AtomToolsFramework
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 <AzCore/std/any.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
class AtomToolsDocumentRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
typedef AZ::Uuid BusIdType;
|
||||
|
||||
//! Get absolute path of document
|
||||
virtual AZStd::string_view GetAbsolutePath() const = 0;
|
||||
|
||||
//! Get relative path of document
|
||||
virtual AZStd::string_view GetRelativePath() const = 0;
|
||||
|
||||
//! Return property value
|
||||
//! If the document is not open or the id can't be found, an invalid value is returned instead.
|
||||
virtual const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const = 0;
|
||||
|
||||
//! Returns a property object
|
||||
//! If the document is not open or the id can't be found, an invalid property is returned.
|
||||
virtual const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const = 0;
|
||||
|
||||
//! Returns whether a property group is visible
|
||||
//! If the document is not open or the id can't be found, returns false.
|
||||
virtual bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const = 0;
|
||||
|
||||
//! Modify document property value
|
||||
virtual void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) = 0;
|
||||
|
||||
//! Load document and related data
|
||||
//! @param loadPath absolute path of document to load
|
||||
virtual bool Open(AZStd::string_view loadPath) = 0;
|
||||
|
||||
//! Reopen document preserving edits
|
||||
virtual bool Reopen() = 0;
|
||||
|
||||
//! Save document to file
|
||||
virtual bool Save() = 0;
|
||||
|
||||
//! Save document copy
|
||||
//! @param savePath absolute path where document is saved
|
||||
virtual bool SaveAsCopy(AZStd::string_view savePath) = 0;
|
||||
|
||||
//! Save document to a new source file derived from of the open document
|
||||
//! @param savePath absolute path where document is saved
|
||||
virtual bool SaveAsChild(AZStd::string_view savePath) = 0;
|
||||
|
||||
//! Close document and reset its data
|
||||
virtual bool Close() = 0;
|
||||
|
||||
//! Document is loaded
|
||||
virtual bool IsOpen() const = 0;
|
||||
|
||||
//! Document has changes pending
|
||||
virtual bool IsModified() const = 0;
|
||||
|
||||
//! Can the document be saved
|
||||
virtual bool IsSavable() const = 0;
|
||||
|
||||
//! Returns true if there are reversible modifications to the document
|
||||
virtual bool CanUndo() const = 0;
|
||||
|
||||
//! Returns true if there are changes that were reversed and can be re-applied to the document
|
||||
virtual bool CanRedo() const = 0;
|
||||
|
||||
//! Restores the previous state of the document
|
||||
virtual bool Undo() = 0;
|
||||
|
||||
//! Restores the next state of the document
|
||||
virtual bool Redo() = 0;
|
||||
|
||||
//! Signal that editing is about to begin, like beginning to drag a slider control
|
||||
virtual bool BeginEdit() = 0;
|
||||
|
||||
//! Signal that editing has completed, like after releasing the mouse button after continuously dragging a slider control
|
||||
virtual bool EndEdit() = 0;
|
||||
};
|
||||
|
||||
using AtomToolsDocumentRequestBus = AZ::EBus<AtomToolsDocumentRequests>;
|
||||
} // namespace AtomToolsFramework
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
class AtomToolsDocument;
|
||||
|
||||
//! AtomToolsDocumentSystemRequestBus provides high level requests for menus, scripts, etc.
|
||||
class AtomToolsDocumentSystemRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
|
||||
//! Register a document factory function used to create specific document types
|
||||
virtual void RegisterDocumentType(AZStd::function<AtomToolsDocument*()> documentCreator) = 0;
|
||||
|
||||
//! Create a document object
|
||||
//! @return Uuid of new document, or null Uuid if failed
|
||||
virtual AZ::Uuid CreateDocument() = 0;
|
||||
|
||||
//! Destroy a document object with the specified id
|
||||
//! @return true if Uuid was found and removed, otherwise false
|
||||
virtual bool DestroyDocument(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Open a document for editing
|
||||
//! @param sourcePath document to open.
|
||||
//! @return unique id of new document if successful, otherwise null Uuid
|
||||
virtual AZ::Uuid OpenDocument(AZStd::string_view sourcePath) = 0;
|
||||
|
||||
//! Create a new document by specifying a source and prompting the user for destination path.
|
||||
//! @param sourcePath document to open.
|
||||
//! @param targetPath location where document is saved.
|
||||
//! @return unique id of new document if successful, otherwise null Uuid
|
||||
virtual AZ::Uuid CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath) = 0;
|
||||
|
||||
//! Close the specified document
|
||||
//! @param documentId unique id of document to close
|
||||
virtual bool CloseDocument(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Close all documents
|
||||
virtual bool CloseAllDocuments() = 0;
|
||||
|
||||
//! Close all documents except for documentId
|
||||
//! @param documentId unique id of document to not close
|
||||
virtual bool CloseAllDocumentsExcept(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Save the specified document
|
||||
//! @param documentId unique id of document to save
|
||||
virtual bool SaveDocument(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Save the specified document to a different file
|
||||
//! @param documentId unique id of document to save
|
||||
//! @param targetPath location where document is saved.
|
||||
virtual bool SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath) = 0;
|
||||
|
||||
//! Save the specified document to a different file, referencing the original document as its parent
|
||||
//! @param documentId unique id of document to save
|
||||
//! @param targetPath location where document is saved.
|
||||
virtual bool SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath) = 0;
|
||||
|
||||
//! Save all documents
|
||||
virtual bool SaveAllDocuments() = 0;
|
||||
};
|
||||
|
||||
using AtomToolsDocumentSystemRequestBus = AZ::EBus<AtomToolsDocumentSystemRequests>;
|
||||
|
||||
} // namespace AtomToolsFramework
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/UserSettings/UserSettings.h>
|
||||
#endif
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
struct AtomToolsDocumentSystemSettings
|
||||
: public AZ::UserSettings
|
||||
{
|
||||
AZ_RTTI(AtomToolsDocumentSystemSettings, "{9E576D4F-A74A-4326-9135-C07284D0A3B9}", AZ::UserSettings);
|
||||
AZ_CLASS_ALLOCATOR(AtomToolsDocumentSystemSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
bool m_showReloadDocumentPrompt = true;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
@@ -7,15 +7,15 @@
|
||||
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AtomToolsFramework/Application/AtomToolsApplication.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AtomToolsFramework/Window/AtomToolsMainWindowFactoryRequestBus.h>
|
||||
#include <AtomToolsFramework/Window/AtomToolsMainWindowRequestBus.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/Asset/AssetSystemComponent.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/Network/AssetProcessorConnection.h>
|
||||
@@ -66,6 +66,9 @@ namespace AtomToolsFramework
|
||||
this->PumpSystemEventLoopUntilEmpty();
|
||||
this->Tick();
|
||||
});
|
||||
|
||||
// Suppress spam from the Source Control system
|
||||
m_traceLogger.AddWindowFilter(AzToolsFramework::SCC_WINDOW);
|
||||
}
|
||||
|
||||
AtomToolsApplication ::~AtomToolsApplication()
|
||||
@@ -396,7 +399,7 @@ namespace AtomToolsFramework
|
||||
|
||||
AZStd::string fileName = GetBuildTargetName() + ".log";
|
||||
|
||||
m_traceLogger.WriteStartupLog(fileName.c_str());
|
||||
m_traceLogger.PrepareLogFile(fileName.c_str());
|
||||
|
||||
if (!LaunchDiscoveryService())
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AtomToolsFrameworkModule.h>
|
||||
#include <AtomToolsFrameworkSystemComponent.h>
|
||||
#include <Document/AtomToolsDocumentSystemComponent.h>
|
||||
#include <Window/AtomToolsMainWindowSystemComponent.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
@@ -16,6 +17,7 @@ namespace AtomToolsFramework
|
||||
{
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
AtomToolsFrameworkSystemComponent::CreateDescriptor(),
|
||||
AtomToolsDocumentSystemComponent::CreateDescriptor(),
|
||||
AtomToolsMainWindowSystemComponent::CreateDescriptor(),
|
||||
});
|
||||
}
|
||||
@@ -24,6 +26,7 @@ namespace AtomToolsFramework
|
||||
{
|
||||
return AZ::ComponentTypeList{
|
||||
azrtti_typeid<AtomToolsFrameworkSystemComponent>(),
|
||||
azrtti_typeid<AtomToolsDocumentSystemComponent>(),
|
||||
azrtti_typeid<AtomToolsMainWindowSystemComponent>(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Document/AtomToolsDocument.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
AtomToolsDocument::AtomToolsDocument()
|
||||
{
|
||||
AtomToolsDocumentRequestBus::Handler::BusConnect(m_id);
|
||||
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentCreated, m_id);
|
||||
}
|
||||
|
||||
AtomToolsDocument::~AtomToolsDocument()
|
||||
{
|
||||
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
|
||||
AtomToolsDocumentRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
const AZ::Uuid& AtomToolsDocument::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
AZStd::string_view AtomToolsDocument::GetAbsolutePath() const
|
||||
{
|
||||
return m_absolutePath;
|
||||
}
|
||||
|
||||
AZStd::string_view AtomToolsDocument::GetRelativePath() const
|
||||
{
|
||||
return m_relativePath;
|
||||
}
|
||||
|
||||
const AZStd::any& AtomToolsDocument::GetPropertyValue(const AZ::Name& propertyFullName) const
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return m_invalidValue;
|
||||
}
|
||||
|
||||
const AtomToolsFramework::DynamicProperty& AtomToolsDocument::GetProperty(const AZ::Name& propertyFullName) const
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return m_invalidProperty;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
void AtomToolsDocument::SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value)
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Open(AZStd::string_view loadPath)
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Reopen()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Save()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::SaveAsCopy(AZStd::string_view savePath)
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AtomToolsDocument::SaveAsChild(AZStd::string_view savePath)
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Close()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::IsOpen() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::IsModified() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::IsSavable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::CanUndo() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::CanRedo() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Undo()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Redo()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::BeginEdit()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::EndEdit()
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+511
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Debug/TraceRecorder.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <Document/AtomToolsDocumentSystemComponent.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
AtomToolsDocumentSystemComponent::AtomToolsDocumentSystemComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AtomToolsDocumentSystemSettings::Reflect(context);
|
||||
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<AtomToolsDocumentSystemComponent, AZ::Component>()
|
||||
->Version(0);
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
ec->Class<AtomToolsDocumentSystemComponent>("AtomToolsDocumentSystemComponent", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<AtomToolsDocumentSystemRequestBus>("AtomToolsDocumentSystemRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "atomtools")
|
||||
->Event("CreateDocument", &AtomToolsDocumentSystemRequestBus::Events::CreateDocument)
|
||||
->Event("DestroyDocument", &AtomToolsDocumentSystemRequestBus::Events::DestroyDocument)
|
||||
->Event("OpenDocument", &AtomToolsDocumentSystemRequestBus::Events::OpenDocument)
|
||||
->Event("CreateDocumentFromFile", &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile)
|
||||
->Event("CloseDocument", &AtomToolsDocumentSystemRequestBus::Events::CloseDocument)
|
||||
->Event("CloseAllDocuments", &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments)
|
||||
->Event("CloseAllDocumentsExcept", &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept)
|
||||
->Event("SaveDocument", &AtomToolsDocumentSystemRequestBus::Events::SaveDocument)
|
||||
->Event("SaveDocumentAsCopy", &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy)
|
||||
->Event("SaveDocumentAsChild", &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild)
|
||||
->Event("SaveAllDocuments", &AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<AtomToolsDocumentRequestBus>("AtomToolsDocumentRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "atomtools")
|
||||
->Event("GetAbsolutePath", &AtomToolsDocumentRequestBus::Events::GetAbsolutePath)
|
||||
->Event("GetRelativePath", &AtomToolsDocumentRequestBus::Events::GetRelativePath)
|
||||
->Event("GetPropertyValue", &AtomToolsDocumentRequestBus::Events::GetPropertyValue)
|
||||
->Event("SetPropertyValue", &AtomToolsDocumentRequestBus::Events::SetPropertyValue)
|
||||
->Event("Open", &AtomToolsDocumentRequestBus::Events::Open)
|
||||
->Event("Reopen", &AtomToolsDocumentRequestBus::Events::Reopen)
|
||||
->Event("Close", &AtomToolsDocumentRequestBus::Events::Close)
|
||||
->Event("Save", &AtomToolsDocumentRequestBus::Events::Save)
|
||||
->Event("SaveAsChild", &AtomToolsDocumentRequestBus::Events::SaveAsChild)
|
||||
->Event("SaveAsCopy", &AtomToolsDocumentRequestBus::Events::SaveAsCopy)
|
||||
->Event("IsOpen", &AtomToolsDocumentRequestBus::Events::IsOpen)
|
||||
->Event("IsModified", &AtomToolsDocumentRequestBus::Events::IsModified)
|
||||
->Event("IsSavable", &AtomToolsDocumentRequestBus::Events::IsSavable)
|
||||
->Event("CanUndo", &AtomToolsDocumentRequestBus::Events::CanUndo)
|
||||
->Event("CanRedo", &AtomToolsDocumentRequestBus::Events::CanRedo)
|
||||
->Event("Undo", &AtomToolsDocumentRequestBus::Events::Undo)
|
||||
->Event("Redo", &AtomToolsDocumentRequestBus::Events::Redo)
|
||||
->Event("BeginEdit", &AtomToolsDocumentRequestBus::Events::BeginEdit)
|
||||
->Event("EndEdit", &AtomToolsDocumentRequestBus::Events::EndEdit)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("AtomToolsDocumentSystemService"));
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("AtomToolsDocumentSystemService"));
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::Activate()
|
||||
{
|
||||
m_documentMap.clear();
|
||||
m_settings = AZ::UserSettings::CreateFind<AtomToolsDocumentSystemSettings>(AZ_CRC_CE("AtomToolsDocumentSystemSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
AtomToolsDocumentSystemRequestBus::Handler::BusConnect();
|
||||
AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::Deactivate()
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AtomToolsDocumentSystemRequestBus::Handler::BusDisconnect();
|
||||
m_documentMap.clear();
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::RegisterDocumentType(AZStd::function<AtomToolsDocument*()> documentCreator)
|
||||
{
|
||||
m_documentCreator = documentCreator;
|
||||
}
|
||||
|
||||
AZ::Uuid AtomToolsDocumentSystemComponent::CreateDocument()
|
||||
{
|
||||
if (!m_documentCreator)
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "Failed to create new document");
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AtomToolsDocument> document(m_documentCreator());
|
||||
if (!document)
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "Failed to create new document");
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
AZ::Uuid documentId = document->GetId();
|
||||
m_documentMap.emplace(documentId, document.release());
|
||||
return documentId;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::DestroyDocument(const AZ::Uuid& documentId)
|
||||
{
|
||||
return m_documentMap.erase(documentId) != 0;
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::OnDocumentExternallyModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
m_documentIdsToReopen.insert(documentId);
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::OnDocumentDependencyModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
m_documentIdsToReopen.insert(documentId);
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void AtomToolsDocumentSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
for (const AZ::Uuid& documentId : m_documentIdsToReopen)
|
||||
{
|
||||
AZStd::string documentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (m_settings->m_showReloadDocumentPrompt &&
|
||||
(QMessageBox::question(QApplication::activeWindow(),
|
||||
QString("Document was externally modified"),
|
||||
QString("Would you like to reopen the document:\n%1?").arg(documentPath.c_str()),
|
||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool openResult = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Open, documentPath);
|
||||
if (!openResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be opened"),
|
||||
QString("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const AZ::Uuid& documentId : m_documentIdsToReopen)
|
||||
{
|
||||
AZStd::string documentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (m_settings->m_showReloadDocumentPrompt &&
|
||||
(QMessageBox::question(QApplication::activeWindow(),
|
||||
QString("Document dependencies have changed"),
|
||||
QString("Would you like to update the document with these changes:\n%1?").arg(documentPath.c_str()),
|
||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool openResult = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Reopen);
|
||||
if (!openResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be opened"),
|
||||
QString("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
}
|
||||
}
|
||||
|
||||
m_documentIdsToReopen.clear();
|
||||
m_documentIdsToReopen.clear();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZ::Uuid AtomToolsDocumentSystemComponent::OpenDocument(AZStd::string_view sourcePath)
|
||||
{
|
||||
return OpenDocumentImpl(sourcePath, true);
|
||||
}
|
||||
|
||||
AZ::Uuid AtomToolsDocumentSystemComponent::CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath)
|
||||
{
|
||||
const AZ::Uuid documentId = OpenDocumentImpl(sourcePath, false);
|
||||
if (documentId.IsNull())
|
||||
{
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
if (!SaveDocumentAsChild(documentId, targetPath))
|
||||
{
|
||||
CloseDocument(documentId);
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
// Send document open notification after creating new one
|
||||
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
|
||||
return documentId;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::CloseDocument(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool isOpen = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen);
|
||||
if (!isOpen)
|
||||
{
|
||||
// immediately destroy unopened documents
|
||||
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::string documentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
bool isModified = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified);
|
||||
if (isModified)
|
||||
{
|
||||
auto selection = QMessageBox::question(QApplication::activeWindow(),
|
||||
QString("Document has unsaved changes"),
|
||||
QString("Do you want to save changes to\n%1?").arg(documentPath.c_str()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
if (selection == QMessageBox::Cancel)
|
||||
{
|
||||
AZ_TracePrintf("AtomToolsDocument", "Close document canceled: %s", documentPath.c_str());
|
||||
return false;
|
||||
}
|
||||
if (selection == QMessageBox::Yes)
|
||||
{
|
||||
if (!SaveDocument(documentId))
|
||||
{
|
||||
AZ_Error("AtomToolsDocument", false, "Close document failed because document was not saved: %s", documentPath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool closeResult = true;
|
||||
AtomToolsDocumentRequestBus::EventResult(closeResult, documentId, &AtomToolsDocumentRequestBus::Events::Close);
|
||||
if (!closeResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be closed"),
|
||||
QString("Failed to close: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::CloseAllDocuments()
|
||||
{
|
||||
bool result = true;
|
||||
auto documentMap = m_documentMap;
|
||||
for (const auto& documentPair : documentMap)
|
||||
{
|
||||
if (!CloseDocument(documentPair.first))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::CloseAllDocumentsExcept(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool result = true;
|
||||
auto documentMap = m_documentMap;
|
||||
for (const auto& documentPair : documentMap)
|
||||
{
|
||||
if (documentPair.first != documentId)
|
||||
{
|
||||
if (!CloseDocument(documentPair.first))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::SaveDocument(const AZ::Uuid& documentId)
|
||||
{
|
||||
AZStd::string saveDocumentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(saveDocumentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (saveDocumentPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveDocumentPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo saveInfo(saveDocumentPath.c_str());
|
||||
if (saveInfo.exists() && !saveInfo.isWritable())
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool result = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Save);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be saved"),
|
||||
QString("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath)
|
||||
{
|
||||
AZStd::string saveDocumentPath = targetPath;
|
||||
if (saveDocumentPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveDocumentPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo saveInfo(saveDocumentPath.c_str());
|
||||
if (saveInfo.exists() && !saveInfo.isWritable())
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool result = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::SaveAsCopy, saveDocumentPath);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be saved"),
|
||||
QString("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath)
|
||||
{
|
||||
AZStd::string saveDocumentPath = targetPath;
|
||||
if (saveDocumentPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveDocumentPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo saveInfo(saveDocumentPath.c_str());
|
||||
if (saveInfo.exists() && !saveInfo.isWritable())
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool result = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::SaveAsChild, saveDocumentPath);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be saved"),
|
||||
QString("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtomToolsDocumentSystemComponent::SaveAllDocuments()
|
||||
{
|
||||
bool result = true;
|
||||
for (const auto& documentPair : m_documentMap)
|
||||
{
|
||||
if (!SaveDocument(documentPair.first))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AZ::Uuid AtomToolsDocumentSystemComponent::OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen)
|
||||
{
|
||||
AZStd::string requestedPath = sourcePath;
|
||||
if (requestedPath.empty())
|
||||
{
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
if (!AzFramework::StringFunc::Path::Normalize(requestedPath))
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document path is invalid:\n%1").arg(requestedPath.c_str()));
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
// Determine if the file is already open and select it
|
||||
if (checkIfAlreadyOpen)
|
||||
{
|
||||
for (const auto& documentPair : m_documentMap)
|
||||
{
|
||||
AZStd::string openDocumentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(openDocumentPath, documentPair.first, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
if (openDocumentPath == requestedPath)
|
||||
{
|
||||
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentPair.first);
|
||||
return documentPair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
AZ::Uuid documentId = AZ::Uuid::CreateNull();
|
||||
AtomToolsDocumentSystemRequestBus::BroadcastResult(documentId, &AtomToolsDocumentSystemRequestBus::Events::CreateDocument);
|
||||
if (documentId.IsNull())
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be created"),
|
||||
QString("Failed to create: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
traceRecorder.GetDump().clear();
|
||||
|
||||
bool openResult = false;
|
||||
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Open, requestedPath);
|
||||
if (!openResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Document could not be opened"),
|
||||
QString("Failed to open: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
return documentId;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocument.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! AtomToolsDocumentSystemComponent is the central component of the Material Editor Core gem
|
||||
class AtomToolsDocumentSystemComponent
|
||||
: public AZ::Component
|
||||
, private AZ::TickBus::Handler
|
||||
, private AtomToolsDocumentNotificationBus::Handler
|
||||
, private AtomToolsDocumentSystemRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AtomToolsDocumentSystemComponent, "{343A3383-6A59-4343-851B-BF84FC6CB18E}");
|
||||
|
||||
AtomToolsDocumentSystemComponent();
|
||||
~AtomToolsDocumentSystemComponent() = default;
|
||||
AtomToolsDocumentSystemComponent(const AtomToolsDocumentSystemComponent&) = delete;
|
||||
AtomToolsDocumentSystemComponent& operator=(const AtomToolsDocumentSystemComponent&) = delete;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AtomToolsDocumentNotificationBus::Handler overrides...
|
||||
void OnDocumentDependencyModified(const AZ::Uuid& documentId) override;
|
||||
void OnDocumentExternallyModified(const AZ::Uuid& documentId) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::TickBus::Handler overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AtomToolsDocumentSystemRequestBus::Handler overrides...
|
||||
void RegisterDocumentType(AZStd::function<AtomToolsDocument*()> documentCreator) override;
|
||||
AZ::Uuid CreateDocument() override;
|
||||
bool DestroyDocument(const AZ::Uuid& documentId) override;
|
||||
AZ::Uuid OpenDocument(AZStd::string_view sourcePath) override;
|
||||
AZ::Uuid CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath) override;
|
||||
bool CloseDocument(const AZ::Uuid& documentId) override;
|
||||
bool CloseAllDocuments() override;
|
||||
bool CloseAllDocumentsExcept(const AZ::Uuid& documentId) override;
|
||||
bool SaveDocument(const AZ::Uuid& documentId) override;
|
||||
bool SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath) override;
|
||||
bool SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath) override;
|
||||
bool SaveAllDocuments() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AZ::Uuid OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen);
|
||||
|
||||
AZStd::intrusive_ptr<AtomToolsDocumentSystemSettings> m_settings;
|
||||
AZStd::function<AtomToolsDocument*()> m_documentCreator;
|
||||
AZStd::unordered_map<AZ::Uuid, AZStd::shared_ptr<AtomToolsDocument>> m_documentMap;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsToRebuild;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsToReopen;
|
||||
const size_t m_maxMessageBoxLineCount = 15;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
void AtomToolsDocumentSystemSettings::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AtomToolsDocumentSystemSettings, AZ::UserSettings>()
|
||||
->Version(1)
|
||||
->Field("showReloadDocumentPrompt", &AtomToolsDocumentSystemSettings::m_showReloadDocumentPrompt)
|
||||
;
|
||||
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<AtomToolsDocumentSystemSettings>(
|
||||
"AtomToolsDocumentSystemSettings", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AtomToolsDocumentSystemSettings::m_showReloadDocumentPrompt, "Show Reload Document Prompt", "")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AtomToolsDocumentSystemSettings>("AtomToolsDocumentSystemSettings")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "atomtools")
|
||||
->Constructor()
|
||||
->Constructor<const AtomToolsDocumentSystemSettings&>()
|
||||
->Property("showReloadDocumentPrompt", BehaviorValueProperty(&AtomToolsDocumentSystemSettings::m_showReloadDocumentPrompt))
|
||||
;
|
||||
}
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
@@ -11,6 +11,11 @@ set(FILES
|
||||
Include/AtomToolsFramework/Communication/LocalServer.h
|
||||
Include/AtomToolsFramework/Communication/LocalSocket.h
|
||||
Include/AtomToolsFramework/Debug/TraceRecorder.h
|
||||
Include/AtomToolsFramework/Document/AtomToolsDocument.h
|
||||
Include/AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h
|
||||
Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h
|
||||
Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h
|
||||
Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h
|
||||
Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h
|
||||
Include/AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h
|
||||
Include/AtomToolsFramework/Inspector/InspectorWidget.h
|
||||
@@ -32,6 +37,10 @@ set(FILES
|
||||
Source/Communication/LocalServer.cpp
|
||||
Source/Communication/LocalSocket.cpp
|
||||
Source/Debug/TraceRecorder.cpp
|
||||
Source/Document/AtomToolsDocument.cpp
|
||||
Source/Document/AtomToolsDocumentSystemSettings.cpp
|
||||
Source/Document/AtomToolsDocumentSystemComponent.cpp
|
||||
Source/Document/AtomToolsDocumentSystemComponent.h
|
||||
Source/DynamicProperty/DynamicProperty.cpp
|
||||
Source/DynamicProperty/DynamicPropertyGroup.cpp
|
||||
Source/Inspector/InspectorWidget.cpp
|
||||
|
||||
-36
@@ -1,36 +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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AtomCore/Instance/InstanceId.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
//! MaterialDocumentFactoryRequestBus provides a factory interface for creating and destroying material documents (in memory)
|
||||
class MaterialDocumentFactoryRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
// Only a single handler is allowed
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
//! Create a material document object
|
||||
//! @return Uuid of new material document, or null Uuid if failed
|
||||
virtual AZ::Uuid CreateDocument() = 0;
|
||||
|
||||
//! Destroy a material document object with the specified id
|
||||
//! @return true if Uuid was found and removed, otherwise false
|
||||
virtual bool DestroyDocument(const AZ::Uuid& documentId) = 0;
|
||||
};
|
||||
|
||||
using MaterialDocumentFactoryRequestBus = AZ::EBus<MaterialDocumentFactoryRequests>;
|
||||
|
||||
} // namespace MaterialEditor
|
||||
+1
-75
@@ -7,15 +7,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/std/any.h>
|
||||
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -39,12 +34,6 @@ namespace MaterialEditor
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
typedef AZ::Uuid BusIdType;
|
||||
|
||||
//! Get absolute path of material source file
|
||||
virtual AZStd::string_view GetAbsolutePath() const = 0;
|
||||
|
||||
//! Get relative path of material source file
|
||||
virtual AZStd::string_view GetRelativePath() const = 0;
|
||||
|
||||
//! Get material asset created by MaterialDocument
|
||||
virtual AZ::Data::Asset<AZ::RPI::MaterialAsset> GetAsset() const = 0;
|
||||
|
||||
@@ -56,69 +45,6 @@ namespace MaterialEditor
|
||||
|
||||
//! Get the internal material type source data
|
||||
virtual const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const = 0;
|
||||
|
||||
//! Return property value
|
||||
//! If the document is not open or the id can't be found, an invalid value is returned instead.
|
||||
virtual const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const = 0;
|
||||
|
||||
//! Returns a property object
|
||||
//! If the document is not open or the id can't be found, an invalid property is returned.
|
||||
virtual const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const = 0;
|
||||
|
||||
//! Returns whether a property group is visible
|
||||
//! If the document is not open or the id can't be found, returns false.
|
||||
virtual bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const = 0;
|
||||
|
||||
//! Modify material property value
|
||||
virtual void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) = 0;
|
||||
|
||||
//! Load source material and related data
|
||||
//! @param loadPath Absolute path of material to load
|
||||
virtual bool Open(AZStd::string_view loadPath) = 0;
|
||||
|
||||
//! Reload document preserving edits
|
||||
virtual bool Rebuild() = 0;
|
||||
|
||||
//! Save material to source file
|
||||
virtual bool Save() = 0;
|
||||
|
||||
//! Save material to a new source file
|
||||
//! @param savePath Absolute path where material is saved
|
||||
virtual bool SaveAsCopy(AZStd::string_view savePath) = 0;
|
||||
|
||||
//! Save material to a new source file as a child of the open material
|
||||
//! @param savePath Absolute path where material is saved
|
||||
virtual bool SaveAsChild(AZStd::string_view savePath) = 0;
|
||||
|
||||
//! Close material document and reset its data
|
||||
virtual bool Close() = 0;
|
||||
|
||||
//! Material is loaded
|
||||
virtual bool IsOpen() const = 0;
|
||||
|
||||
//! Material has changes pending
|
||||
virtual bool IsModified() const = 0;
|
||||
|
||||
//! Can the document be saved
|
||||
virtual bool IsSavable() const = 0;
|
||||
|
||||
//! Returns true if there are reversible modifications to the material document
|
||||
virtual bool CanUndo() const = 0;
|
||||
|
||||
//! Returns true if there are changes that were reversed and can be re-applied to the material document
|
||||
virtual bool CanRedo() const = 0;
|
||||
|
||||
//! Restores the previous state of the material document
|
||||
virtual bool Undo() = 0;
|
||||
|
||||
//! Restores the next state of the material document
|
||||
virtual bool Redo() = 0;
|
||||
|
||||
//! Signal that property editing is about to begin, like beginning to drag a slider control
|
||||
virtual bool BeginEdit() = 0;
|
||||
|
||||
//! Signal that property editing has completed, like after releasing the mouse button after continuously dragging a slider control
|
||||
virtual bool EndEdit() = 0;
|
||||
};
|
||||
|
||||
using MaterialDocumentRequestBus = AZ::EBus<MaterialDocumentRequests>;
|
||||
|
||||
+1
-2
@@ -20,12 +20,11 @@ namespace MaterialEditor
|
||||
struct MaterialDocumentSettings
|
||||
: public AZ::UserSettings
|
||||
{
|
||||
AZ_RTTI(MaterialDocumentSettings, "{FA4F4BF3-BF39-4753-AAF7-AF383B868881}", AZ::UserSettings);
|
||||
AZ_RTTI(MaterialDocumentSettings, "{12E8461F-65AD-4AD2-8A1D-82C3B1183522}", AZ::UserSettings);
|
||||
AZ_CLASS_ALLOCATOR(MaterialDocumentSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
bool m_showReloadDocumentPrompt = true;
|
||||
AZStd::string m_defaultMaterialTypeName = "StandardPBR";
|
||||
};
|
||||
} // namespace MaterialEditor
|
||||
|
||||
-78
@@ -1,78 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
static const char* MaterialExtension = "material";
|
||||
static const char* MaterialTypeExtension = "materialtype";
|
||||
|
||||
//! MaterialDocumentSystemRequestBus provides high level file requests for menus, scripts, etc.
|
||||
class MaterialDocumentSystemRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
|
||||
//! Create a material document object
|
||||
//! @return Uuid of new material document, or null Uuid if failed
|
||||
virtual AZ::Uuid CreateDocument() = 0;
|
||||
|
||||
//! Destroy a material document object with the specified id
|
||||
//! @return true if Uuid was found and removed, otherwise false
|
||||
virtual bool DestroyDocument(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Open a material document for editing
|
||||
//! @param sourcePath material document to open.
|
||||
//! @return unique id of new material document if successful, otherwise null Uuid
|
||||
virtual AZ::Uuid OpenDocument(AZStd::string_view sourcePath) = 0;
|
||||
|
||||
//! Create a new document by specifying a source and prompting the user for destination path.
|
||||
//! If the source file is a material type then this results in creating a new material based on that type.
|
||||
//! If the source file is a material this results in creating a child material with the source file as its parent.
|
||||
//! @param sourcePath material document to open.
|
||||
//! @param targetPath location where document is saved.
|
||||
//! @return unique id of new material document if successful, otherwise null Uuid
|
||||
virtual AZ::Uuid CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath) = 0;
|
||||
|
||||
//! Close the specified material document
|
||||
//! @param documentId unique id of material document to close
|
||||
virtual bool CloseDocument(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Close all material documents
|
||||
virtual bool CloseAllDocuments() = 0;
|
||||
|
||||
//! Close all material documents except for documentId
|
||||
//! @param documentId unique id of material document to not close
|
||||
virtual bool CloseAllDocumentsExcept(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Save the specified material document
|
||||
//! @param documentId unique id of material document to save
|
||||
virtual bool SaveDocument(const AZ::Uuid& documentId) = 0;
|
||||
|
||||
//! Save the specified material document to a different file
|
||||
//! @param documentId unique id of material document to save
|
||||
//! @param targetPath location where document is saved.
|
||||
virtual bool SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath) = 0;
|
||||
|
||||
//! Save the specified material document to a different file, referencing the original material as its parent
|
||||
//! @param documentId unique id of material document to save
|
||||
//! @param targetPath location where document is saved.
|
||||
virtual bool SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath) = 0;
|
||||
|
||||
//! Save all material documents
|
||||
virtual bool SaveAllDocuments() = 0;
|
||||
};
|
||||
|
||||
using MaterialDocumentSystemRequestBus = AZ::EBus<MaterialDocumentSystemRequests>;
|
||||
|
||||
} // namespace MaterialEditor
|
||||
@@ -6,53 +6,39 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceData.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/RPI.Reflect/Image/Image.h>
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
#include <Document/MaterialDocument.h>
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
|
||||
#include <Document/MaterialDocument.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
MaterialDocument::MaterialDocument()
|
||||
: AtomToolsFramework::AtomToolsDocument()
|
||||
{
|
||||
MaterialDocumentRequestBus::Handler::BusConnect(m_id);
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentCreated, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentCreated, m_id);
|
||||
}
|
||||
|
||||
MaterialDocument::~MaterialDocument()
|
||||
{
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
|
||||
MaterialDocumentRequestBus::Handler::BusDisconnect();
|
||||
Clear();
|
||||
}
|
||||
|
||||
const AZ::Uuid& MaterialDocument::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
AZStd::string_view MaterialDocument::GetAbsolutePath() const
|
||||
{
|
||||
return m_absolutePath;
|
||||
}
|
||||
|
||||
AZStd::string_view MaterialDocument::GetRelativePath() const
|
||||
{
|
||||
return m_relativePath;
|
||||
}
|
||||
|
||||
AZ::Data::Asset<AZ::RPI::MaterialAsset> MaterialDocument::GetAsset() const
|
||||
{
|
||||
return m_materialAsset;
|
||||
@@ -170,17 +156,17 @@ namespace MaterialEditor
|
||||
EditorMaterialFunctorResult result = RunEditorMaterialFunctors(dirtyFlags);
|
||||
for (const Name& changedPropertyGroupName : result.m_updatedPropertyGroups)
|
||||
{
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyGroupVisibilityChanged, m_id, changedPropertyGroupName, IsPropertyGroupVisible(changedPropertyGroupName));
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentPropertyGroupVisibilityChanged, m_id, changedPropertyGroupName, IsPropertyGroupVisible(changedPropertyGroupName));
|
||||
}
|
||||
for (const Name& changedPropertyName : result.m_updatedProperties)
|
||||
{
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyConfigModified, m_id, GetProperty(changedPropertyName));
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentPropertyConfigModified, m_id, GetProperty(changedPropertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyValueModified, m_id, property);
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentModified, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentPropertyValueModified, m_id, property);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
|
||||
}
|
||||
|
||||
bool MaterialDocument::Open(AZStd::string_view loadPath)
|
||||
@@ -192,11 +178,11 @@ namespace MaterialEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentOpened, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, m_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialDocument::Rebuild()
|
||||
bool MaterialDocument::Reopen()
|
||||
{
|
||||
// Store history and property changes that should be reapplied after reload
|
||||
auto undoHistoryToRestore = m_undoHistory;
|
||||
@@ -222,7 +208,7 @@ namespace MaterialEditor
|
||||
RestorePropertyValues(propertyValuesToRestore);
|
||||
AZStd::swap(undoHistoryToRestore, m_undoHistory);
|
||||
AZStd::swap(undoHistoryIndexToRestore, m_undoHistoryIndex);
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentOpened, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, m_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -285,7 +271,7 @@ namespace MaterialEditor
|
||||
|
||||
AZ_TracePrintf("MaterialDocument", "Material document saved: '%s'.\n", m_absolutePath.data());
|
||||
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentSaved, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentSaved, m_id);
|
||||
|
||||
m_saveTriggeredInternally = true;
|
||||
return true;
|
||||
@@ -348,7 +334,7 @@ namespace MaterialEditor
|
||||
|
||||
AZ_TracePrintf("MaterialDocument", "Material document saved: '%s'.\n", normalizedSavePath.c_str());
|
||||
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentSaved, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentSaved, m_id);
|
||||
|
||||
// If the document is saved to a new file we need to reopen the new document to update assets, paths, property deltas.
|
||||
if (!Open(normalizedSavePath))
|
||||
@@ -424,7 +410,7 @@ namespace MaterialEditor
|
||||
|
||||
AZ_TracePrintf("MaterialDocument", "Material document saved: '%s'.\n", normalizedSavePath.c_str());
|
||||
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentSaved, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentSaved, m_id);
|
||||
|
||||
// If the document is saved to a new file we need to reopen the new document to update assets, paths, property deltas.
|
||||
if (!Open(normalizedSavePath))
|
||||
@@ -450,7 +436,7 @@ namespace MaterialEditor
|
||||
|
||||
AZ_TracePrintf("MaterialDocument", "Material document closed: '%s'.\n", m_absolutePath.c_str());
|
||||
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentClosed, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentClosed, m_id);
|
||||
|
||||
// Clearing after notification so paths are still available
|
||||
Clear();
|
||||
@@ -496,7 +482,7 @@ namespace MaterialEditor
|
||||
// The history index is one beyond the last executed command. Decrement the index then execute undo.
|
||||
m_undoHistory[--m_undoHistoryIndex].first();
|
||||
AZ_TracePrintf("MaterialDocument", "Material document undo: '%s'.\n", m_absolutePath.c_str());
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -509,7 +495,7 @@ namespace MaterialEditor
|
||||
// Execute the current redo command then move the history index to the next position.
|
||||
m_undoHistory[m_undoHistoryIndex++].second();
|
||||
AZ_TracePrintf("MaterialDocument", "Material document redo: '%s'.\n", m_absolutePath.c_str());
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -557,7 +543,7 @@ namespace MaterialEditor
|
||||
|
||||
// Assign the index to the end of history
|
||||
m_undoHistoryIndex = aznumeric_cast<int>(m_undoHistory.size());
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
|
||||
}
|
||||
|
||||
m_propertyValuesBeforeEdit.clear();
|
||||
@@ -584,7 +570,7 @@ namespace MaterialEditor
|
||||
if (!m_saveTriggeredInternally)
|
||||
{
|
||||
AZ_TracePrintf("MaterialDocument", "Material document changed externally: '%s'.\n", m_absolutePath.c_str());
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id);
|
||||
}
|
||||
m_saveTriggeredInternally = false;
|
||||
}
|
||||
@@ -595,7 +581,7 @@ namespace MaterialEditor
|
||||
if (m_dependentAssetIds.find(asset->GetId()) != m_dependentAssetIds.end())
|
||||
{
|
||||
AZ_TracePrintf("MaterialDocument", "Material document dependency changed: '%s'.\n", m_absolutePath.c_str());
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocument.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
@@ -27,7 +26,8 @@ namespace MaterialEditor
|
||||
* MaterialDocument provides an API for modifying and saving material document properties.
|
||||
*/
|
||||
class MaterialDocument
|
||||
: public MaterialDocumentRequestBus::Handler
|
||||
: public AtomToolsFramework::AtomToolsDocument
|
||||
, public MaterialDocumentRequestBus::Handler
|
||||
, private AZ::TickBus::Handler
|
||||
, private AZ::Data::AssetBus::MultiHandler
|
||||
, private AzToolsFramework::AssetSystemBus::Handler
|
||||
@@ -40,22 +40,15 @@ namespace MaterialEditor
|
||||
MaterialDocument();
|
||||
virtual ~MaterialDocument();
|
||||
|
||||
const AZ::Uuid& GetId() const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// MaterialDocumentRequestBus::Handler implementation
|
||||
AZStd::string_view GetAbsolutePath() const override;
|
||||
AZStd::string_view GetRelativePath() const override;
|
||||
AZ::Data::Asset<AZ::RPI::MaterialAsset> GetAsset() const override;
|
||||
AZ::Data::Instance<AZ::RPI::Material> GetInstance() const override;
|
||||
const AZ::RPI::MaterialSourceData* GetMaterialSourceData() const override;
|
||||
const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const override;
|
||||
// AtomToolsFramework::AtomToolsDocument
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const override;
|
||||
const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const override;
|
||||
bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override;
|
||||
void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) override;
|
||||
bool Open(AZStd::string_view loadPath) override;
|
||||
bool Rebuild() override;
|
||||
bool Reopen() override;
|
||||
bool Save() override;
|
||||
bool SaveAsCopy(AZStd::string_view savePath) override;
|
||||
bool SaveAsChild(AZStd::string_view savePath) override;
|
||||
@@ -71,6 +64,14 @@ namespace MaterialEditor
|
||||
bool EndEdit() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// MaterialDocumentRequestBus::Handler implementation
|
||||
AZ::Data::Asset<AZ::RPI::MaterialAsset> GetAsset() const override;
|
||||
AZ::Data::Instance<AZ::RPI::Material> GetInstance() const override;
|
||||
const AZ::RPI::MaterialSourceData* GetMaterialSourceData() const override;
|
||||
const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
|
||||
// Predicate for evaluating properties
|
||||
@@ -130,21 +131,12 @@ namespace MaterialEditor
|
||||
// @return names for the set of properties and groups that have been changed or need update.
|
||||
EditorMaterialFunctorResult RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags);
|
||||
|
||||
// Unique id of this material document
|
||||
AZ::Uuid m_id = AZ::Uuid::CreateRandom();
|
||||
|
||||
// Underlying material asset
|
||||
AZ::Data::Asset<AZ::RPI::MaterialAsset> m_materialAsset;
|
||||
|
||||
// Material instance being edited
|
||||
AZ::Data::Instance<AZ::RPI::Material> m_materialInstance;
|
||||
|
||||
// Relative path to the material source file
|
||||
AZStd::string m_relativePath;
|
||||
|
||||
// Absolute path to the material source file
|
||||
AZStd::string m_absolutePath;
|
||||
|
||||
// Asset used to open document
|
||||
AZ::Data::AssetId m_sourceAssetId;
|
||||
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
*/
|
||||
|
||||
#include <Atom/Document/MaterialDocumentModule.h>
|
||||
#include <Document/MaterialDocumentSystemComponent.h>
|
||||
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyManagerComponent.h>
|
||||
#include <AzToolsFramework/Asset/AssetSystemComponent.h>
|
||||
#include <Document/MaterialDocumentSystemComponent.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace MaterialEditor
|
||||
{
|
||||
serializeContext->Class<MaterialDocumentSettings, AZ::UserSettings>()
|
||||
->Version(1)
|
||||
->Field("showReloadDocumentPrompt", &MaterialDocumentSettings::m_showReloadDocumentPrompt)
|
||||
->Field("defaultMaterialTypeName", &MaterialDocumentSettings::m_defaultMaterialTypeName)
|
||||
;
|
||||
|
||||
@@ -28,7 +27,6 @@ namespace MaterialEditor
|
||||
"MaterialDocumentSettings", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialDocumentSettings::m_showReloadDocumentPrompt, "Show Reload Document Prompt", "")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialDocumentSettings::m_defaultMaterialTypeName, "Default Material Type Name", "")
|
||||
;
|
||||
}
|
||||
@@ -39,10 +37,9 @@ namespace MaterialEditor
|
||||
behaviorContext->Class<MaterialDocumentSettings>("MaterialDocumentSettings")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
->Attribute(AZ::Script::Attributes::Module, "materialeditor")
|
||||
->Constructor()
|
||||
->Constructor<const MaterialDocumentSettings&>()
|
||||
->Property("showReloadDocumentPrompt", BehaviorValueProperty(&MaterialDocumentSettings::m_showReloadDocumentPrompt))
|
||||
->Property("defaultMaterialTypeName", BehaviorValueProperty(&MaterialDocumentSettings::m_defaultMaterialTypeName))
|
||||
;
|
||||
}
|
||||
|
||||
+17
-448
@@ -6,40 +6,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Document/MaterialDocumentSystemComponent.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
#include <Atom/Document/MaterialDocumentSettings.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <AtomToolsFramework/Debug/TraceRecorder.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QApplication>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QStyle>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#include <Document/MaterialDocument.h>
|
||||
#include <Document/MaterialDocumentSystemComponent.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
MaterialDocumentSystemComponent::MaterialDocumentSystemComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
MaterialDocumentSettings::Reflect(context);
|
||||
@@ -53,7 +30,7 @@ namespace MaterialEditor
|
||||
{
|
||||
ec->Class<MaterialDocumentSystemComponent>("MaterialDocumentSystemComponent", "Tool for editing Atom material files")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
@@ -61,66 +38,31 @@ namespace MaterialEditor
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<MaterialDocumentSystemRequestBus>("MaterialDocumentSystemRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "materialeditor")
|
||||
->Event("CreateDocument", &MaterialDocumentSystemRequestBus::Events::CreateDocument)
|
||||
->Event("DestroyDocument", &MaterialDocumentSystemRequestBus::Events::DestroyDocument)
|
||||
->Event("OpenDocument", &MaterialDocumentSystemRequestBus::Events::OpenDocument)
|
||||
->Event("CreateDocumentFromFile", &MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile)
|
||||
->Event("CloseDocument", &MaterialDocumentSystemRequestBus::Events::CloseDocument)
|
||||
->Event("CloseAllDocuments", &MaterialDocumentSystemRequestBus::Events::CloseAllDocuments)
|
||||
->Event("CloseAllDocumentsExcept", &MaterialDocumentSystemRequestBus::Events::CloseAllDocumentsExcept)
|
||||
->Event("SaveDocument", &MaterialDocumentSystemRequestBus::Events::SaveDocument)
|
||||
->Event("SaveDocumentAsCopy", &MaterialDocumentSystemRequestBus::Events::SaveDocumentAsCopy)
|
||||
->Event("SaveDocumentAsChild", &MaterialDocumentSystemRequestBus::Events::SaveDocumentAsChild)
|
||||
->Event("SaveAllDocuments", &MaterialDocumentSystemRequestBus::Events::SaveAllDocuments)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<MaterialDocumentRequestBus>("MaterialDocumentRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "materialeditor")
|
||||
->Event("GetAbsolutePath", &MaterialDocumentRequestBus::Events::GetAbsolutePath)
|
||||
->Event("GetRelativePath", &MaterialDocumentRequestBus::Events::GetRelativePath)
|
||||
->Event("GetPropertyValue", &MaterialDocumentRequestBus::Events::GetPropertyValue)
|
||||
->Event("SetPropertyValue", &MaterialDocumentRequestBus::Events::SetPropertyValue)
|
||||
->Event("Open", &MaterialDocumentRequestBus::Events::Open)
|
||||
->Event("Rebuild", &MaterialDocumentRequestBus::Events::Rebuild)
|
||||
->Event("Close", &MaterialDocumentRequestBus::Events::Close)
|
||||
->Event("Save", &MaterialDocumentRequestBus::Events::Save)
|
||||
->Event("SaveAsChild", &MaterialDocumentRequestBus::Events::SaveAsChild)
|
||||
->Event("SaveAsCopy", &MaterialDocumentRequestBus::Events::SaveAsCopy)
|
||||
->Event("IsOpen", &MaterialDocumentRequestBus::Events::IsOpen)
|
||||
->Event("IsModified", &MaterialDocumentRequestBus::Events::IsModified)
|
||||
->Event("IsSavable", &MaterialDocumentRequestBus::Events::IsSavable)
|
||||
->Event("CanUndo", &MaterialDocumentRequestBus::Events::CanUndo)
|
||||
->Event("CanRedo", &MaterialDocumentRequestBus::Events::CanRedo)
|
||||
->Event("Undo", &MaterialDocumentRequestBus::Events::Undo)
|
||||
->Event("Redo", &MaterialDocumentRequestBus::Events::Redo)
|
||||
->Event("BeginEdit", &MaterialDocumentRequestBus::Events::BeginEdit)
|
||||
->Event("EndEdit", &MaterialDocumentRequestBus::Events::EndEdit)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("AssetProcessorToolsConnection", 0x734669bc));
|
||||
required.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601));
|
||||
required.push_back(AZ_CRC("PropertyManagerService", 0x63a3d7ad));
|
||||
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
|
||||
required.push_back(AZ_CRC_CE("AtomToolsDocumentSystemService"));
|
||||
required.push_back(AZ_CRC_CE("AssetProcessorToolsConnection"));
|
||||
required.push_back(AZ_CRC_CE("AssetDatabaseService"));
|
||||
required.push_back(AZ_CRC_CE("PropertyManagerService"));
|
||||
required.push_back(AZ_CRC_CE("RPISystem"));
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("MaterialDocumentSystemService"));
|
||||
provided.push_back(AZ_CRC_CE("MaterialDocumentSystemService"));
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("MaterialDocumentSystemService"));
|
||||
incompatible.push_back(AZ_CRC_CE("MaterialDocumentSystemService"));
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::Init()
|
||||
@@ -129,388 +71,15 @@ namespace MaterialEditor
|
||||
|
||||
void MaterialDocumentSystemComponent::Activate()
|
||||
{
|
||||
m_documentMap.clear();
|
||||
m_settings = AZ::UserSettings::CreateFind<MaterialDocumentSettings>(AZ::Crc32("MaterialDocumentSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
MaterialDocumentSystemRequestBus::Handler::BusConnect();
|
||||
MaterialDocumentNotificationBus::Handler::BusConnect();
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
|
||||
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType,
|
||||
[]()
|
||||
{
|
||||
return aznew MaterialDocument();
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::Deactivate()
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
MaterialDocumentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialDocumentSystemRequestBus::Handler::BusDisconnect();
|
||||
m_documentMap.clear();
|
||||
}
|
||||
|
||||
AZ::Uuid MaterialDocumentSystemComponent::CreateDocument()
|
||||
{
|
||||
auto document = AZStd::make_unique<MaterialDocument>();
|
||||
if (!document)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Failed to create new document");
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
AZ::Uuid documentId = document->GetId();
|
||||
m_documentMap.emplace(documentId, document.release());
|
||||
return documentId;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::DestroyDocument(const AZ::Uuid& documentId)
|
||||
{
|
||||
return m_documentMap.erase(documentId) != 0;
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::OnDocumentExternallyModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
m_documentIdsToReopen.insert(documentId);
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::OnDocumentDependencyModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
m_documentIdsToRebuild.insert(documentId);
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialDocumentSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
for (const AZ::Uuid& documentId : m_documentIdsToReopen)
|
||||
{
|
||||
AZStd::string documentPath;
|
||||
MaterialDocumentRequestBus::EventResult(documentPath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (m_settings->m_showReloadDocumentPrompt &&
|
||||
(QMessageBox::question(QApplication::activeWindow(),
|
||||
QString("Material document was externally modified"),
|
||||
QString("Would you like to reopen the document:\n%1?").arg(documentPath.c_str()),
|
||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool openResult = false;
|
||||
MaterialDocumentRequestBus::EventResult(openResult, documentId, &MaterialDocumentRequestBus::Events::Open, documentPath);
|
||||
if (!openResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be opened"),
|
||||
QString("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const AZ::Uuid& documentId : m_documentIdsToRebuild)
|
||||
{
|
||||
AZStd::string documentPath;
|
||||
MaterialDocumentRequestBus::EventResult(documentPath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (m_settings->m_showReloadDocumentPrompt &&
|
||||
(QMessageBox::question(QApplication::activeWindow(),
|
||||
QString("Material document dependencies have changed"),
|
||||
QString("Would you like to update the document with these changes:\n%1?").arg(documentPath.c_str()),
|
||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool openResult = false;
|
||||
MaterialDocumentRequestBus::EventResult(openResult, documentId, &MaterialDocumentRequestBus::Events::Rebuild);
|
||||
if (!openResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be opened"),
|
||||
QString("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
}
|
||||
}
|
||||
|
||||
m_documentIdsToRebuild.clear();
|
||||
m_documentIdsToReopen.clear();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZ::Uuid MaterialDocumentSystemComponent::OpenDocument(AZStd::string_view sourcePath)
|
||||
{
|
||||
return OpenDocumentImpl(sourcePath, true);
|
||||
}
|
||||
|
||||
AZ::Uuid MaterialDocumentSystemComponent::CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath)
|
||||
{
|
||||
const AZ::Uuid documentId = OpenDocumentImpl(sourcePath, false);
|
||||
if (documentId.IsNull())
|
||||
{
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
if (!SaveDocumentAsChild(documentId, targetPath))
|
||||
{
|
||||
CloseDocument(documentId);
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
// Send document open notification after creating new material
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentOpened, documentId);
|
||||
return documentId;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::CloseDocument(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool isOpen = false;
|
||||
MaterialDocumentRequestBus::EventResult(isOpen, documentId, &MaterialDocumentRequestBus::Events::IsOpen);
|
||||
if (!isOpen)
|
||||
{
|
||||
// immediately destroy unopened documents
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::DestroyDocument, documentId);
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::string documentPath;
|
||||
MaterialDocumentRequestBus::EventResult(documentPath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
bool isModified = false;
|
||||
MaterialDocumentRequestBus::EventResult(isModified, documentId, &MaterialDocumentRequestBus::Events::IsModified);
|
||||
if (isModified)
|
||||
{
|
||||
auto selection = QMessageBox::question(QApplication::activeWindow(),
|
||||
QString("Material document has unsaved changes"),
|
||||
QString("Do you want to save changes to\n%1?").arg(documentPath.c_str()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
if (selection == QMessageBox::Cancel)
|
||||
{
|
||||
AZ_TracePrintf("MaterialDocument", "Close document canceled: %s", documentPath.c_str());
|
||||
return false;
|
||||
}
|
||||
if (selection == QMessageBox::Yes)
|
||||
{
|
||||
if (!SaveDocument(documentId))
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Close document failed because document was not saved: %s", documentPath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool closeResult = true;
|
||||
MaterialDocumentRequestBus::EventResult(closeResult, documentId, &MaterialDocumentRequestBus::Events::Close);
|
||||
if (!closeResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be closed"),
|
||||
QString("Failed to close: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::DestroyDocument, documentId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::CloseAllDocuments()
|
||||
{
|
||||
bool result = true;
|
||||
auto documentMap = m_documentMap;
|
||||
for (const auto& documentPair : documentMap)
|
||||
{
|
||||
if (!CloseDocument(documentPair.first))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::CloseAllDocumentsExcept(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool result = true;
|
||||
auto documentMap = m_documentMap;
|
||||
for (const auto& documentPair : documentMap)
|
||||
{
|
||||
if (documentPair.first != documentId)
|
||||
{
|
||||
if (!CloseDocument(documentPair.first))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::SaveDocument(const AZ::Uuid& documentId)
|
||||
{
|
||||
AZStd::string saveMaterialPath;
|
||||
MaterialDocumentRequestBus::EventResult(saveMaterialPath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (saveMaterialPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveMaterialPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo saveInfo(saveMaterialPath.c_str());
|
||||
if (saveInfo.exists() && !saveInfo.isWritable())
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Material document could not be overwritten:\n%1").arg(saveMaterialPath.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool result = false;
|
||||
MaterialDocumentRequestBus::EventResult(result, documentId, &MaterialDocumentRequestBus::Events::Save);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be saved"),
|
||||
QString("Failed to save: \n%1\n\n%2").arg(saveMaterialPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath)
|
||||
{
|
||||
AZStd::string saveMaterialPath = targetPath;
|
||||
if (saveMaterialPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveMaterialPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo saveInfo(saveMaterialPath.c_str());
|
||||
if (saveInfo.exists() && !saveInfo.isWritable())
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Material document could not be overwritten:\n%1").arg(saveMaterialPath.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool result = false;
|
||||
MaterialDocumentRequestBus::EventResult(result, documentId, &MaterialDocumentRequestBus::Events::SaveAsCopy, saveMaterialPath);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be saved"),
|
||||
QString("Failed to save: \n%1\n\n%2").arg(saveMaterialPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath)
|
||||
{
|
||||
AZStd::string saveMaterialPath = targetPath;
|
||||
if (saveMaterialPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveMaterialPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo saveInfo(saveMaterialPath.c_str());
|
||||
if (saveInfo.exists() && !saveInfo.isWritable())
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Material document could not be overwritten:\n%1").arg(saveMaterialPath.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool result = false;
|
||||
MaterialDocumentRequestBus::EventResult(result, documentId, &MaterialDocumentRequestBus::Events::SaveAsChild, saveMaterialPath);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be saved"),
|
||||
QString("Failed to save: \n%1\n\n%2").arg(saveMaterialPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialDocumentSystemComponent::SaveAllDocuments()
|
||||
{
|
||||
bool result = true;
|
||||
for (const auto& documentPair : m_documentMap)
|
||||
{
|
||||
if (!SaveDocument(documentPair.first))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AZ::Uuid MaterialDocumentSystemComponent::OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen)
|
||||
{
|
||||
AZStd::string requestedPath = sourcePath;
|
||||
if (requestedPath.empty())
|
||||
{
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
if (!AzFramework::StringFunc::Path::Normalize(requestedPath))
|
||||
{
|
||||
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Material document path is invalid:\n%1").arg(requestedPath.c_str()));
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
// Determine if the file is already open and select it
|
||||
if (checkIfAlreadyOpen)
|
||||
{
|
||||
for (const auto& documentPair : m_documentMap)
|
||||
{
|
||||
AZStd::string openMaterialPath;
|
||||
MaterialDocumentRequestBus::EventResult(openMaterialPath, documentPair.first, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
if (openMaterialPath == requestedPath)
|
||||
{
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentOpened, documentPair.first);
|
||||
return documentPair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
AZ::Uuid documentId = AZ::Uuid::CreateNull();
|
||||
MaterialDocumentSystemRequestBus::BroadcastResult(documentId, &MaterialDocumentSystemRequestBus::Events::CreateDocument);
|
||||
if (documentId.IsNull())
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be created"),
|
||||
QString("Failed to create: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
traceRecorder.GetDump().clear();
|
||||
|
||||
bool openResult = false;
|
||||
MaterialDocumentRequestBus::EventResult(openResult, documentId, &MaterialDocumentRequestBus::Events::Open, requestedPath);
|
||||
if (!openResult)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QApplication::activeWindow(), QString("Material document could not be opened"),
|
||||
QString("Failed to open: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::DestroyDocument, documentId);
|
||||
return AZ::Uuid::CreateNull();
|
||||
}
|
||||
|
||||
return documentId;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-54
@@ -9,34 +9,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <Atom/Document/MaterialDocumentSettings.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/RPI.Public/WindowContext.h>
|
||||
#include <Document/MaterialDocument.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
//! MaterialDocumentSystemComponent is the central component of the Material Editor Core gem
|
||||
//! MaterialDocumentSystemComponent
|
||||
class MaterialDocumentSystemComponent
|
||||
: public AZ::Component
|
||||
, private AZ::TickBus::Handler
|
||||
, private MaterialDocumentNotificationBus::Handler
|
||||
, private MaterialDocumentSystemRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(MaterialDocumentSystemComponent, "{58ABE0AE-2710-41E2-ADFD-E2D67407427D}");
|
||||
AZ_COMPONENT(MaterialDocumentSystemComponent, "{E011DA51-855D-45FA-87A3-1C1CD6379091}");
|
||||
|
||||
MaterialDocumentSystemComponent();
|
||||
MaterialDocumentSystemComponent() = default;
|
||||
~MaterialDocumentSystemComponent() = default;
|
||||
MaterialDocumentSystemComponent(const MaterialDocumentSystemComponent&) = delete;
|
||||
MaterialDocumentSystemComponent& operator=(const MaterialDocumentSystemComponent&) = delete;
|
||||
@@ -54,39 +37,5 @@ namespace MaterialEditor
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MaterialDocumentNotificationBus::Handler overrides...
|
||||
void OnDocumentDependencyModified(const AZ::Uuid& documentId) override;
|
||||
void OnDocumentExternallyModified(const AZ::Uuid& documentId) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::TickBus::Handler overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// MaterialDocumentSystemRequestBus::Handler overrides...
|
||||
AZ::Uuid CreateDocument() override;
|
||||
bool DestroyDocument(const AZ::Uuid& documentId) override;
|
||||
AZ::Uuid OpenDocument(AZStd::string_view sourcePath) override;
|
||||
AZ::Uuid CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath) override;
|
||||
bool CloseDocument(const AZ::Uuid& documentId) override;
|
||||
bool CloseAllDocuments() override;
|
||||
bool CloseAllDocumentsExcept(const AZ::Uuid& documentId) override;
|
||||
bool SaveDocument(const AZ::Uuid& documentId) override;
|
||||
bool SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath) override;
|
||||
bool SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath) override;
|
||||
bool SaveAllDocuments() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AZ::Uuid OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen);
|
||||
|
||||
AZStd::intrusive_ptr<MaterialDocumentSettings> m_settings;
|
||||
AZStd::unordered_map<AZ::Uuid, AZStd::shared_ptr<MaterialDocument>> m_documentMap;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsToRebuild;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsToReopen;
|
||||
const size_t m_maxMessageBoxLineCount = 15;
|
||||
};
|
||||
} // namespace MaterialEditor
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
#include <Atom/Document/MaterialDocumentModule.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/Viewport/MaterialViewportModule.h>
|
||||
#include <Atom/Window/MaterialEditorWindowModule.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <MaterialEditorApplication.h>
|
||||
#include <MaterialEditor_Traits_Platform.h>
|
||||
@@ -68,7 +68,7 @@ namespace MaterialEditor
|
||||
const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex);
|
||||
|
||||
AZ_Printf(GetBuildTargetName().c_str(), "Opening document: %s", openDocumentPath.c_str());
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
|
||||
}
|
||||
|
||||
Base::ProcessCommandLine(commandLine);
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <AtomToolsFramework/Application/AtomToolsApplication.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace MaterialEditor
|
||||
OnFieldOfViewChanged(viewportSettings->m_fieldOfView);
|
||||
OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType);
|
||||
|
||||
MaterialDocumentNotificationBus::Handler::BusConnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
MaterialViewportNotificationBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId());
|
||||
@@ -255,7 +255,7 @@ namespace MaterialEditor
|
||||
AzFramework::WindowSystemRequestBus::Handler::BusDisconnect();
|
||||
AZ::TransformNotificationBus::MultiHandler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
MaterialDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialViewportNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
|
||||
|
||||
@@ -8,16 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/Viewport/MaterialViewportNotificationBus.h>
|
||||
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
#include <Viewport/InputController/MaterialEditorViewportInputController.h>
|
||||
|
||||
@@ -45,7 +43,7 @@ namespace MaterialEditor
|
||||
class MaterialViewportRenderer
|
||||
: public AZ::Data::AssetBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
, public MaterialDocumentNotificationBus::Handler
|
||||
, public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
|
||||
, public MaterialViewportNotificationBus::Handler
|
||||
, public AZ::TransformNotificationBus::MultiHandler
|
||||
, public AzFramework::WindowSystemRequestBus::Handler
|
||||
@@ -60,7 +58,7 @@ namespace MaterialEditor
|
||||
|
||||
private:
|
||||
|
||||
// MaterialDocumentNotificationBus::Handler interface overrides...
|
||||
// AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides...
|
||||
void OnDocumentOpened(const AZ::Uuid& documentId) override;
|
||||
|
||||
// MaterialViewportNotificationBus::Handler interface overrides...
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace MaterialEditor
|
||||
behaviorContext->Class<MaterialViewportSettings>("MaterialViewportSettings")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
->Attribute(AZ::Script::Attributes::Module, "materialeditor")
|
||||
->Constructor()
|
||||
->Constructor<const MaterialViewportSettings&>()
|
||||
->Property("enableGrid", BehaviorValueProperty(&MaterialViewportSettings::m_enableGrid))
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
*/
|
||||
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
@@ -18,9 +21,8 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Search/Filter.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.h>
|
||||
|
||||
#include <Source/Window/MaterialBrowserWidget.h>
|
||||
#include <Source/Window/ui_MaterialBrowserWidget.h>
|
||||
#include <Window/MaterialBrowserWidget.h>
|
||||
#include <Window/ui_MaterialBrowserWidget.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QAction>
|
||||
@@ -91,14 +93,14 @@ namespace MaterialEditor
|
||||
}
|
||||
});
|
||||
|
||||
MaterialDocumentNotificationBus::Handler::BusConnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
MaterialBrowserWidget::~MaterialBrowserWidget()
|
||||
{
|
||||
// Maintains the tree expansion state between runs
|
||||
m_ui->m_assetBrowserTreeViewWidget->SaveState();
|
||||
MaterialDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -144,13 +146,13 @@ namespace MaterialEditor
|
||||
{
|
||||
if (entry)
|
||||
{
|
||||
if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialExtension))
|
||||
if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), AZ::RPI::MaterialSourceData::Extension))
|
||||
{
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, entry->GetFullPath());
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, entry->GetFullPath());
|
||||
}
|
||||
else if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialTypeExtension))
|
||||
else if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), AZ::RPI::MaterialTypeSourceData::Extension))
|
||||
{
|
||||
//ignore MaterialTypeExtension
|
||||
//ignore AZ::RPI::MaterialTypeSourceData::Extension
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -163,7 +165,7 @@ namespace MaterialEditor
|
||||
void MaterialBrowserWidget::OnDocumentOpened(const AZ::Uuid& documentId)
|
||||
{
|
||||
AZStd::string absolutePath;
|
||||
MaterialDocumentRequestBus::EventResult(absolutePath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
if (!absolutePath.empty())
|
||||
{
|
||||
// Selecting a new asset in the browser is not guaranteed to happen immediately.
|
||||
@@ -230,4 +232,4 @@ namespace MaterialEditor
|
||||
|
||||
} // namespace MaterialEditor
|
||||
|
||||
#include <Source/Window/moc_MaterialBrowserWidget.cpp>
|
||||
#include <Window/moc_MaterialBrowserWidget.cpp>
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Search/Filter.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QWidget>
|
||||
#include <QByteArray>
|
||||
#include <QWidget>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
#endif
|
||||
@@ -45,7 +45,7 @@ namespace MaterialEditor
|
||||
class MaterialBrowserWidget
|
||||
: public QWidget
|
||||
, protected AZ::TickBus::Handler
|
||||
, protected MaterialDocumentNotificationBus::Handler
|
||||
, protected AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -56,7 +56,7 @@ namespace MaterialEditor
|
||||
AzToolsFramework::AssetBrowser::FilterConstType CreateFilter() const;
|
||||
void OpenSelectedEntries();
|
||||
|
||||
// MaterialDocumentNotificationBus::Handler implementation
|
||||
// AtomToolsDocumentNotificationBus::Handler implementation
|
||||
void OnDocumentOpened(const AZ::Uuid& documentId) override;
|
||||
|
||||
// AZ::TickBus::Handler
|
||||
|
||||
+25
-29
@@ -6,32 +6,28 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QMenu>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/SourceControlThumbnail.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
|
||||
#include <Window/MaterialEditorBrowserInteractions.h>
|
||||
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
#include <AzToolsFramework/Thumbnails/SourceControlThumbnail.h>
|
||||
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
|
||||
#include <Window/MaterialEditorBrowserInteractions.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
@@ -66,11 +62,11 @@ namespace MaterialEditor
|
||||
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
|
||||
{
|
||||
const auto source = azalias_cast<const SourceAssetBrowserEntry*>(entry);
|
||||
if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialExtension))
|
||||
if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), AZ::RPI::MaterialSourceData::Extension))
|
||||
{
|
||||
AddContextMenuActionsForMaterialSource(caller, menu, source);
|
||||
}
|
||||
else if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialTypeExtension))
|
||||
else if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), AZ::RPI::MaterialTypeSourceData::Extension))
|
||||
{
|
||||
AddContextMenuActionsForMaterialTypeSource(caller, menu, source);
|
||||
}
|
||||
@@ -115,7 +111,7 @@ namespace MaterialEditor
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
|
||||
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
|
||||
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
entry->GetFullPath(), AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
|
||||
});
|
||||
|
||||
@@ -157,7 +153,7 @@ namespace MaterialEditor
|
||||
{
|
||||
menu->addAction("Open", [entry]()
|
||||
{
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, entry->GetFullPath());
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, entry->GetFullPath());
|
||||
});
|
||||
|
||||
menu->addAction("Duplicate...", [entry, caller]()
|
||||
@@ -191,7 +187,7 @@ namespace MaterialEditor
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
|
||||
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
|
||||
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
entry->GetFullPath(), AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
|
||||
});
|
||||
|
||||
@@ -258,7 +254,7 @@ namespace MaterialEditor
|
||||
!createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() &&
|
||||
!createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty())
|
||||
{
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(),
|
||||
createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData());
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/Window/MaterialEditorWindowSettings.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AtomToolsFramework/Window/AtomToolsMainWindowNotificationBus.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
@@ -15,11 +19,6 @@
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
|
||||
#include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/Window/MaterialEditorWindowSettings.h>
|
||||
|
||||
#include <Viewport/MaterialViewportWidget.h>
|
||||
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
|
||||
#include <Window/HelpDialog/HelpDialog.h>
|
||||
@@ -106,13 +105,13 @@ namespace MaterialEditor
|
||||
m_advancedDockManager->restoreState(windowState);
|
||||
}
|
||||
|
||||
MaterialDocumentNotificationBus::Handler::BusConnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
OnDocumentOpened(AZ::Uuid::CreateNull());
|
||||
}
|
||||
|
||||
MaterialEditorWindow::~MaterialEditorWindow()
|
||||
{
|
||||
MaterialDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +149,7 @@ namespace MaterialEditor
|
||||
void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent)
|
||||
{
|
||||
bool didClose = true;
|
||||
MaterialDocumentSystemRequestBus::BroadcastResult(didClose, &MaterialDocumentSystemRequestBus::Events::CloseAllDocuments);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments);
|
||||
if (!didClose)
|
||||
{
|
||||
closeEvent->ignore();
|
||||
@@ -171,17 +170,17 @@ namespace MaterialEditor
|
||||
void MaterialEditorWindow::OnDocumentOpened(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool isOpen = false;
|
||||
MaterialDocumentRequestBus::EventResult(isOpen, documentId, &MaterialDocumentRequestBus::Events::IsOpen);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen);
|
||||
bool isSavable = false;
|
||||
MaterialDocumentRequestBus::EventResult(isSavable, documentId, &MaterialDocumentRequestBus::Events::IsSavable);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsSavable);
|
||||
bool isModified = false;
|
||||
MaterialDocumentRequestBus::EventResult(isModified, documentId, &MaterialDocumentRequestBus::Events::IsModified);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified);
|
||||
bool canUndo = false;
|
||||
MaterialDocumentRequestBus::EventResult(canUndo, documentId, &MaterialDocumentRequestBus::Events::CanUndo);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo);
|
||||
bool canRedo = false;
|
||||
MaterialDocumentRequestBus::EventResult(canRedo, documentId, &MaterialDocumentRequestBus::Events::CanRedo);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo);
|
||||
AZStd::string absolutePath;
|
||||
MaterialDocumentRequestBus::EventResult(absolutePath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename);
|
||||
|
||||
@@ -238,7 +237,7 @@ namespace MaterialEditor
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
if (!documentPath.isEmpty())
|
||||
{
|
||||
const QString status = QString("Document closed: %1").arg(documentPath);
|
||||
const QString status = QString("Document opened: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"White\">%1</font>").arg(status));
|
||||
}
|
||||
}
|
||||
@@ -255,9 +254,9 @@ namespace MaterialEditor
|
||||
void MaterialEditorWindow::OnDocumentModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool isModified = false;
|
||||
MaterialDocumentRequestBus::EventResult(isModified, documentId, &MaterialDocumentRequestBus::Events::IsModified);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified);
|
||||
AZStd::string absolutePath;
|
||||
MaterialDocumentRequestBus::EventResult(absolutePath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename);
|
||||
UpdateTabForDocumentId(documentId, filename, absolutePath, isModified);
|
||||
@@ -268,9 +267,9 @@ namespace MaterialEditor
|
||||
if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex()))
|
||||
{
|
||||
bool canUndo = false;
|
||||
MaterialDocumentRequestBus::EventResult(canUndo, documentId, &MaterialDocumentRequestBus::Events::CanUndo);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo);
|
||||
bool canRedo = false;
|
||||
MaterialDocumentRequestBus::EventResult(canRedo, documentId, &MaterialDocumentRequestBus::Events::CanRedo);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo);
|
||||
m_actionUndo->setEnabled(canUndo);
|
||||
m_actionRedo->setEnabled(canRedo);
|
||||
}
|
||||
@@ -279,15 +278,15 @@ namespace MaterialEditor
|
||||
void MaterialEditorWindow::OnDocumentSaved(const AZ::Uuid& documentId)
|
||||
{
|
||||
bool isModified = false;
|
||||
MaterialDocumentRequestBus::EventResult(isModified, documentId, &MaterialDocumentRequestBus::Events::IsModified);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified);
|
||||
AZStd::string absolutePath;
|
||||
MaterialDocumentRequestBus::EventResult(absolutePath, documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename);
|
||||
UpdateTabForDocumentId(documentId, filename, absolutePath, isModified);
|
||||
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
const QString status = QString("Document closed: %1").arg(documentPath);
|
||||
const QString status = QString("Document saved: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"White\">%1</font>").arg(status));
|
||||
}
|
||||
|
||||
@@ -306,7 +305,7 @@ namespace MaterialEditor
|
||||
!createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() &&
|
||||
!createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty())
|
||||
{
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
|
||||
createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(),
|
||||
createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData());
|
||||
}
|
||||
@@ -317,7 +316,7 @@ namespace MaterialEditor
|
||||
const AZStd::string filePath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData();
|
||||
if (!filePath.empty())
|
||||
{
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, filePath);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath);
|
||||
}
|
||||
}, QKeySequence::Open);
|
||||
|
||||
@@ -328,11 +327,11 @@ namespace MaterialEditor
|
||||
m_actionSave = m_menuFile->addAction("&Save", [this]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex());
|
||||
bool result = false;
|
||||
MaterialDocumentSystemRequestBus::BroadcastResult(result, &MaterialDocumentSystemRequestBus::Events::SaveDocument, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId);
|
||||
if (!result)
|
||||
{
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
const QString status = QString("Failed to save document: %1").arg(documentPath);
|
||||
const QString status = QString("Document save failed: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"Red\">%1</font>").arg(status));
|
||||
}
|
||||
}, QKeySequence::Save);
|
||||
@@ -342,11 +341,11 @@ namespace MaterialEditor
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
|
||||
bool result = false;
|
||||
MaterialDocumentSystemRequestBus::BroadcastResult(result, &MaterialDocumentSystemRequestBus::Events::SaveDocumentAsCopy,
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy,
|
||||
documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData());
|
||||
if (!result)
|
||||
{
|
||||
const QString status = QString("Failed to save document: %1").arg(documentPath);
|
||||
const QString status = QString("Document save failed: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"Red\">%1</font>").arg(status));
|
||||
}
|
||||
}, QKeySequence::SaveAs);
|
||||
@@ -356,21 +355,21 @@ namespace MaterialEditor
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
|
||||
bool result = false;
|
||||
MaterialDocumentSystemRequestBus::BroadcastResult(result, &MaterialDocumentSystemRequestBus::Events::SaveDocumentAsChild,
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild,
|
||||
documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData());
|
||||
if (!result)
|
||||
{
|
||||
const QString status = QString("Failed to save document: %1").arg(documentPath);
|
||||
const QString status = QString("Document save failed: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"Red\">%1</font>").arg(status));
|
||||
}
|
||||
});
|
||||
|
||||
m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() {
|
||||
bool result = false;
|
||||
MaterialDocumentSystemRequestBus::BroadcastResult(result, &MaterialDocumentSystemRequestBus::Events::SaveAllDocuments);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments);
|
||||
if (!result)
|
||||
{
|
||||
const QString status = QString("Failed to save documents.");
|
||||
const QString status = QString("Document save all failed.");
|
||||
m_statusMessage->setText(QString("<font color=\"Red\">%1</font>").arg(status));
|
||||
}
|
||||
});
|
||||
@@ -379,16 +378,16 @@ namespace MaterialEditor
|
||||
|
||||
m_actionClose = m_menuFile->addAction("&Close", [this]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex());
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
}, QKeySequence::Close);
|
||||
|
||||
m_actionCloseAll = m_menuFile->addAction("Close All", [this]() {
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseAllDocuments);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments);
|
||||
});
|
||||
|
||||
m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex());
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
|
||||
});
|
||||
|
||||
m_menuFile->addSeparator();
|
||||
@@ -412,11 +411,11 @@ namespace MaterialEditor
|
||||
m_actionUndo = m_menuEdit->addAction("&Undo", [this]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex());
|
||||
bool result = false;
|
||||
MaterialDocumentRequestBus::EventResult(result, documentId, &MaterialDocumentRequestBus::Events::Undo);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo);
|
||||
if (!result)
|
||||
{
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
const QString status = QString("Failed to perform undo on document: %1").arg(documentPath);
|
||||
const QString status = QString("Document undo failed: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"Red\">%1</font>").arg(status));
|
||||
}
|
||||
}, QKeySequence::Undo);
|
||||
@@ -424,11 +423,11 @@ namespace MaterialEditor
|
||||
m_actionRedo = m_menuEdit->addAction("&Redo", [this]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex());
|
||||
bool result = false;
|
||||
MaterialDocumentRequestBus::EventResult(result, documentId, &MaterialDocumentRequestBus::Events::Redo);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo);
|
||||
if (!result)
|
||||
{
|
||||
const QString documentPath = GetDocumentPath(documentId);
|
||||
const QString status = QString("Failed to perform redo on document: %1").arg(documentPath);
|
||||
const QString status = QString("Document redo failed: %1").arg(documentPath);
|
||||
m_statusMessage->setText(QString("<font color=\"Red\">%1</font>").arg(status));
|
||||
}
|
||||
}, QKeySequence::Redo);
|
||||
@@ -501,19 +500,19 @@ namespace MaterialEditor
|
||||
// This should automatically clear the active document
|
||||
connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex);
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentOpened, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
|
||||
});
|
||||
|
||||
connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex);
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
});
|
||||
}
|
||||
|
||||
QString MaterialEditorWindow::GetDocumentPath(const AZ::Uuid& documentId) const
|
||||
{
|
||||
AZStd::string absolutePath;
|
||||
MaterialDocumentRequestBus::EventResult(absolutePath, documentId, &MaterialDocumentRequestBus::Handler::GetAbsolutePath);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath);
|
||||
return absolutePath.c_str();
|
||||
}
|
||||
|
||||
@@ -529,15 +528,15 @@ namespace MaterialEditor
|
||||
const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select";
|
||||
tabMenu.addAction(selectActionName, [this, clickedTabIndex]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex);
|
||||
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentOpened, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
|
||||
});
|
||||
tabMenu.addAction("Close", [this, clickedTabIndex]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex);
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
|
||||
});
|
||||
auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() {
|
||||
const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex);
|
||||
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
|
||||
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
|
||||
});
|
||||
closeOthersAction->setEnabled(tabBar->count() > 1);
|
||||
tabMenu.exec(QCursor::pos());
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Window/AtomToolsMainWindow.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace MaterialEditor
|
||||
*/
|
||||
class MaterialEditorWindow
|
||||
: public AtomToolsFramework::AtomToolsMainWindow
|
||||
, private MaterialDocumentNotificationBus::Handler
|
||||
, private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -46,7 +46,7 @@ namespace MaterialEditor
|
||||
void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override;
|
||||
void UnlockViewportRenderTargetSize() override;
|
||||
|
||||
// MaterialDocumentNotificationBus::Handler overrides...
|
||||
// AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides...
|
||||
void OnDocumentOpened(const AZ::Uuid& documentId) override;
|
||||
void OnDocumentClosed(const AZ::Uuid& documentId) override;
|
||||
void OnDocumentModified(const AZ::Uuid& documentId) override;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace MaterialEditor
|
||||
behaviorContext->Class<MaterialEditorWindowSettings>("MaterialEditorWindowSettings")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
->Attribute(AZ::Script::Attributes::Module, "materialeditor")
|
||||
->Constructor()
|
||||
->Constructor<const MaterialEditorWindowSettings&>()
|
||||
;
|
||||
|
||||
+22
-24
@@ -6,17 +6,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentRequestBus.h>
|
||||
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
|
||||
#include <Window/MaterialInspector/MaterialInspector.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
@@ -27,12 +25,12 @@ namespace MaterialEditor
|
||||
m_windowSettings = AZ::UserSettings::CreateFind<MaterialEditorWindowSettings>(
|
||||
AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
|
||||
MaterialDocumentNotificationBus::Handler::BusConnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
MaterialInspector::~MaterialInspector()
|
||||
{
|
||||
MaterialDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -69,9 +67,9 @@ namespace MaterialEditor
|
||||
m_documentId = documentId;
|
||||
|
||||
bool isOpen = false;
|
||||
MaterialDocumentRequestBus::EventResult(isOpen, m_documentId, &MaterialDocumentRequestBus::Events::IsOpen);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen);
|
||||
|
||||
MaterialDocumentRequestBus::EventResult(m_documentPath, m_documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(m_documentPath, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
|
||||
if (!m_documentId.IsNull() && isOpen)
|
||||
{
|
||||
@@ -113,13 +111,13 @@ namespace MaterialEditor
|
||||
auto& group = m_groups[groupNameId];
|
||||
|
||||
AtomToolsFramework::DynamicProperty property;
|
||||
MaterialDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &MaterialDocumentRequestBus::Events::GetProperty, AZ::Name("overview.materialType"));
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, AZ::Name("overview.materialType"));
|
||||
group.m_properties.push_back(property);
|
||||
|
||||
property = {};
|
||||
MaterialDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &MaterialDocumentRequestBus::Events::GetProperty, AZ::Name("overview.parentMaterial"));
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, AZ::Name("overview.parentMaterial"));
|
||||
group.m_properties.push_back(property);
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
@@ -145,8 +143,8 @@ namespace MaterialEditor
|
||||
for (const auto& uvNamePair : uvNameMap)
|
||||
{
|
||||
AtomToolsFramework::DynamicProperty property;
|
||||
MaterialDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &MaterialDocumentRequestBus::Events::GetProperty,
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty,
|
||||
AZ::RPI::MaterialPropertyId(groupNameId, uvNamePair.m_shaderInput.ToString()).GetFullName());
|
||||
group.m_properties.push_back(property);
|
||||
|
||||
@@ -182,8 +180,8 @@ namespace MaterialEditor
|
||||
for (const auto& propertyDefinition : propertyListItr->second)
|
||||
{
|
||||
AtomToolsFramework::DynamicProperty property;
|
||||
MaterialDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &MaterialDocumentRequestBus::Events::GetProperty,
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty,
|
||||
AZ::RPI::MaterialPropertyId(groupNameId, propertyDefinition.m_nameId).GetFullName());
|
||||
group.m_properties.push_back(property);
|
||||
}
|
||||
@@ -196,8 +194,8 @@ namespace MaterialEditor
|
||||
AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
|
||||
bool isGroupVisible = false;
|
||||
MaterialDocumentRequestBus::EventResult(
|
||||
isGroupVisible, m_documentId, &MaterialDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupNameId});
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
isGroupVisible, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupNameId});
|
||||
SetGroupVisible(groupNameId, isGroupVisible);
|
||||
}
|
||||
}
|
||||
@@ -264,7 +262,7 @@ namespace MaterialEditor
|
||||
if (m_activeProperty != property)
|
||||
{
|
||||
m_activeProperty = property;
|
||||
MaterialDocumentRequestBus::Event(m_documentId, &MaterialDocumentRequestBus::Events::BeginEdit);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::Event(m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::BeginEdit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,8 +274,8 @@ namespace MaterialEditor
|
||||
{
|
||||
if (m_activeProperty == property)
|
||||
{
|
||||
MaterialDocumentRequestBus::Event(
|
||||
m_documentId, &MaterialDocumentRequestBus::Events::SetPropertyValue, property->GetId(), property->GetValue());
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::Event(
|
||||
m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::SetPropertyValue, property->GetId(), property->GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,10 +290,10 @@ namespace MaterialEditor
|
||||
{
|
||||
if (m_activeProperty == property)
|
||||
{
|
||||
MaterialDocumentRequestBus::Event(
|
||||
m_documentId, &MaterialDocumentRequestBus::Events::SetPropertyValue, property->GetId(), property->GetValue());
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::Event(
|
||||
m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::SetPropertyValue, property->GetId(), property->GetValue());
|
||||
|
||||
MaterialDocumentRequestBus::Event(m_documentId, &MaterialDocumentRequestBus::Events::EndEdit);
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::Event(m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::EndEdit);
|
||||
m_activeProperty = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -9,14 +9,12 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
|
||||
|
||||
#include <Atom/Window/MaterialEditorWindowSettings.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentNotificationBus.h>
|
||||
#include <Atom/Window/MaterialEditorWindowSettings.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
|
||||
#endif
|
||||
|
||||
namespace MaterialEditor
|
||||
@@ -25,7 +23,7 @@ namespace MaterialEditor
|
||||
//! The settings can be divided into cards, with each one showing a subset of properties.
|
||||
class MaterialInspector
|
||||
: public AtomToolsFramework::InspectorWidget
|
||||
, public MaterialDocumentNotificationBus::Handler
|
||||
, public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
|
||||
, public AzToolsFramework::IPropertyEditorNotify
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -52,7 +50,7 @@ namespace MaterialEditor
|
||||
void AddUvNamesGroup();
|
||||
void AddPropertiesGroup();
|
||||
|
||||
// MaterialDocumentNotificationBus::Handler implementation
|
||||
// AtomToolsDocumentNotificationBus::Handler implementation
|
||||
void OnDocumentOpened(const AZ::Uuid& documentId) override;
|
||||
void OnDocumentPropertyValueModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override;
|
||||
void OnDocumentPropertyConfigModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override;
|
||||
|
||||
+20
-4
@@ -15,7 +15,9 @@ namespace MaterialEditor
|
||||
: AtomToolsFramework::InspectorWidget(parent)
|
||||
{
|
||||
m_documentSettings =
|
||||
AZ::UserSettings::CreateFind<MaterialDocumentSettings>(AZ::Crc32("MaterialDocumentSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
AZ::UserSettings::CreateFind<MaterialDocumentSettings>(AZ_CRC_CE("MaterialDocumentSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
m_documentSystemSettings = AZ::UserSettings::CreateFind<AtomToolsFramework::AtomToolsDocumentSystemSettings>(
|
||||
AZ_CRC_CE("AtomToolsDocumentSystemSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
}
|
||||
|
||||
SettingsWidget::~SettingsWidget()
|
||||
@@ -26,23 +28,37 @@ namespace MaterialEditor
|
||||
void SettingsWidget::Populate()
|
||||
{
|
||||
AddGroupsBegin();
|
||||
AddDocumentGroup();
|
||||
AddDocumentSystemSettingsGroup();
|
||||
AddDocumentSettingsGroup();
|
||||
AddGroupsEnd();
|
||||
}
|
||||
|
||||
void SettingsWidget::AddDocumentGroup()
|
||||
void SettingsWidget::AddDocumentSettingsGroup()
|
||||
{
|
||||
const AZStd::string groupNameId = "documentSettings";
|
||||
const AZStd::string groupDisplayName = "Document Settings";
|
||||
const AZStd::string groupDescription = "Document Settings";
|
||||
|
||||
const AZ::Crc32 saveStateKey(AZStd::string::format("SettingsWidget::DocumentGroup"));
|
||||
const AZ::Crc32 saveStateKey(AZStd::string::format("SettingsWidget::DocumentSettingsGroup"));
|
||||
AddGroup(
|
||||
groupNameId, groupDisplayName, groupDescription,
|
||||
new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
m_documentSettings.get(), nullptr, m_documentSettings->TYPEINFO_Uuid(), this, this, saveStateKey));
|
||||
}
|
||||
|
||||
void SettingsWidget::AddDocumentSystemSettingsGroup()
|
||||
{
|
||||
const AZStd::string groupNameId = "documentSystemSettings";
|
||||
const AZStd::string groupDisplayName = "Document System Settings";
|
||||
const AZStd::string groupDescription = "Document System Settings";
|
||||
|
||||
const AZ::Crc32 saveStateKey(AZStd::string::format("SettingsWidget::DocumentSystemSettingsGroup"));
|
||||
AddGroup(
|
||||
groupNameId, groupDisplayName, groupDescription,
|
||||
new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
m_documentSystemSettings.get(), nullptr, m_documentSystemSettings->TYPEINFO_Uuid(), this, this, saveStateKey));
|
||||
}
|
||||
|
||||
void SettingsWidget::Reset()
|
||||
{
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user