Merge branch 'development' into cmake/AddressSanitizer

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-08-17 10:43:37 -07:00
113 changed files with 2338 additions and 2205 deletions
@@ -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')
@@ -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)
)
+4
View File
@@ -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.");
+16 -7
View File
@@ -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()
+12 -8
View File
@@ -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
+1
View File
@@ -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
)
@@ -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)
@@ -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
@@ -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);
@@ -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);
+2 -1
View File
@@ -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 "";
+1 -7
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
}
}
@@ -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
@@ -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
@@ -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
@@ -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>;
@@ -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
@@ -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))
;
}
@@ -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;
}
}
@@ -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
@@ -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&>()
;
@@ -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;
}
}
@@ -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;
@@ -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();
@@ -10,6 +10,7 @@
#if !defined(Q_MOC_RUN)
#include <Atom/Document/MaterialDocumentSettings.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
#endif
@@ -31,7 +32,8 @@ namespace MaterialEditor
void Populate();
private:
void AddDocumentGroup();
void AddDocumentSettingsGroup();
void AddDocumentSystemSettingsGroup();
// AtomToolsFramework::InspectorRequestBus::Handler overrides...
void Reset() override;
@@ -46,5 +48,6 @@ namespace MaterialEditor
void PropertySelectionChanged(AzToolsFramework::InstanceDataNode*, bool) override {}
AZStd::intrusive_ptr<MaterialDocumentSettings> m_documentSettings;
AZStd::intrusive_ptr<AtomToolsFramework::AtomToolsDocumentSystemSettings> m_documentSystemSettings;
};
} // namespace MaterialEditor
@@ -8,8 +8,6 @@
set(FILES
Include/Atom/Document/MaterialDocumentModule.h
Include/Atom/Document/MaterialDocumentSystemRequestBus.h
Include/Atom/Document/MaterialDocumentNotificationBus.h
Include/Atom/Document/MaterialDocumentRequestBus.h
Include/Atom/Document/MaterialDocumentSettings.h
Source/Document/MaterialDocumentModule.cpp
@@ -93,11 +93,11 @@ def ToRadians(degrees):
return 3.14159 * degrees / 180.0;
def OpenMaterial(filename):
documentId = azlmbr.materialeditor.MaterialDocumentSystemRequestBus(azlmbr.bus.Broadcast, 'OpenDocument', os.path.join(g_materialTestFolder, filename))
documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(azlmbr.bus.Broadcast, 'OpenDocument', os.path.join(g_materialTestFolder, filename))
return documentId
def CloseMaterial(documentId):
azlmbr.materialeditor.MaterialDocumentSystemRequestBus(azlmbr.bus.Broadcast, 'CloseDocument', documentId)
azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(azlmbr.bus.Broadcast, 'CloseDocument', documentId)
def SelectLightingPreset(presetName):
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, 'SelectLightingPresetByName', presetName)
@@ -1,56 +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/Asset/AssetCommon.h>
#include <AzCore/std/any.h>
namespace ShaderManagementConsole
{
class ShaderManagementConsoleDocumentNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! 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 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 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 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 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 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 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 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) {}
};
using ShaderManagementConsoleDocumentNotificationBus = AZ::EBus<ShaderManagementConsoleDocumentNotifications>;
} // namespace ShaderManagementConsole
@@ -7,18 +7,13 @@
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/any.h>
#include <AzCore/std/string/string_view.h>
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroupLayout.h>
#include <Atom/RPI.Edit/Shader/ShaderSourceData.h>
#include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h>
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroupLayout.h>
#include <AzCore/Asset/AssetCommon.h>
namespace ShaderManagementConsole
{
using ShaderManagementConsoleDocumentResult = AZ::Outcome<AZStd::string, AZStd::string>;
class ShaderManagementConsoleDocumentRequests
: public AZ::EBusTraits
@@ -28,12 +23,6 @@ namespace ShaderManagementConsole
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;
//! Get the number of options
virtual size_t GetShaderOptionCount() const = 0;
@@ -45,47 +34,6 @@ namespace ShaderManagementConsole
//! Get the information for the shader variant at the specified index
virtual const AZ::RPI::ShaderVariantListSourceData::VariantInfo& GetShaderVariantInfo(size_t index) const = 0;
//! Load document and related data
//! @param loadPath Absolute path of document to load
virtual ShaderManagementConsoleDocumentResult Open(AZStd::string_view loadPath) = 0;
//! Save document to file
virtual ShaderManagementConsoleDocumentResult Save() = 0;
//! Save document copy
//! @param savePath Absolute path where document is saved
virtual ShaderManagementConsoleDocumentResult SaveAsCopy(AZStd::string_view savePath) = 0;
//! Close document and reset its data
virtual ShaderManagementConsoleDocumentResult 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 ShaderManagementConsoleDocumentRequestBus = AZ::EBus<ShaderManagementConsoleDocumentRequests>;
@@ -1,57 +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 ShaderManagementConsole
{
//! ShaderManagementConsoleDocumentSystemRequestBus provides high level file requests for menus, scripts, etc.
class ShaderManagementConsoleDocumentSystemRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//! 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 path document to edit.
//! @return unique id of new document if successful, otherwise null Uuid
virtual AZ::Uuid OpenDocument(AZStd::string_view path) = 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;
//! 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
virtual bool SaveDocumentAsCopy(const AZ::Uuid& documentId) = 0;
//! Save all documents
virtual bool SaveAllDocuments() = 0;
};
using ShaderManagementConsoleDocumentSystemRequestBus = AZ::EBus<ShaderManagementConsoleDocumentSystemRequests>;
} // namespace ShaderManagementConsole
@@ -8,48 +8,32 @@
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <Document/ShaderManagementConsoleDocument.h>
#include <Atom/Document/ShaderManagementConsoleDocumentNotificationBus.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
#include <Document/ShaderManagementConsoleDocument.h>
namespace ShaderManagementConsole
{
ShaderManagementConsoleDocument::ShaderManagementConsoleDocument()
: AtomToolsFramework::AtomToolsDocument()
{
ShaderManagementConsoleDocumentRequestBus::Handler::BusConnect(m_id);
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentCreated, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentCreated, m_id);
}
ShaderManagementConsoleDocument::~ShaderManagementConsoleDocument()
{
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
ShaderManagementConsoleDocumentRequestBus::Handler::BusDisconnect();
}
const AZ::Uuid& ShaderManagementConsoleDocument::GetId() const
{
return m_id;
}
AZStd::string_view ShaderManagementConsoleDocument::GetAbsolutePath() const
{
return m_absolutePath;
}
AZStd::string_view ShaderManagementConsoleDocument::GetRelativePath() const
{
return m_relativePath;
Clear();
}
size_t ShaderManagementConsoleDocument::GetShaderOptionCount() const
{
auto layout = m_shaderAsset->GetShaderOptionGroupLayout();
auto& shaderOptionDescriptors = layout->GetShaderOptions();
return shaderOptionDescriptors.size();
}
@@ -57,7 +41,6 @@ namespace ShaderManagementConsole
{
auto layout = m_shaderAsset->GetShaderOptionGroupLayout();
auto& shaderOptionDescriptors = layout->GetShaderOptions();
return shaderOptionDescriptors[index];
}
@@ -71,19 +54,21 @@ namespace ShaderManagementConsole
return m_shaderVariantListSourceData.m_shaderVariants[index];
}
ShaderManagementConsoleDocumentResult ShaderManagementConsoleDocument::Open(AZStd::string_view loadPath)
bool ShaderManagementConsoleDocument::Open(AZStd::string_view loadPath)
{
Clear();
m_absolutePath = loadPath;
if (!AzFramework::StringFunc::Path::Normalize(m_absolutePath))
{
return AZ::Failure(AZStd::string::format("Document path could not be normalized: '%s'.", m_absolutePath.c_str()));
AZ_Error("ShaderManagementConsoleDocument", false, "Document path could not be normalized: '%s'.", m_absolutePath.c_str());
return false;
}
if (AzFramework::StringFunc::Path::IsRelative(m_absolutePath.c_str()))
{
return AZ::Failure(AZStd::string::format("Document path must be absolute: '%s'.", m_absolutePath.c_str()));
AZ_Error("ShaderManagementConsoleDocument", false, "Document path must be absolute: '%s'.", m_absolutePath.c_str());
return false;
}
if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension))
@@ -91,7 +76,8 @@ namespace ShaderManagementConsole
// Load the shader config data and create a shader config asset from it
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_absolutePath, m_shaderVariantListSourceData))
{
return AZ::Failure(AZStd::string::format("Failed loading shader variant list data: '%s.'", m_absolutePath.c_str()));
AZ_Error("ShaderManagementConsoleDocument", false, "Failed loading shader variant list data: '%s.'", m_absolutePath.c_str());
return false;
}
}
@@ -103,13 +89,15 @@ namespace ShaderManagementConsole
watchFolder);
if (!result)
{
return AZ::Failure(AZStd::string::format("Could not find source data: '%s'.", m_absolutePath.c_str()));
AZ_Error("ShaderManagementConsoleDocument", false, "Could not find source data: '%s'.", m_absolutePath.c_str());
return false;
}
m_relativePath = m_shaderVariantListSourceData.m_shaderFilePath;
if (!AzFramework::StringFunc::Path::Normalize(m_relativePath))
{
return AZ::Failure(AZStd::string::format("Shader path could not be normalized: '%s'.", m_relativePath.c_str()));
AZ_Error("ShaderManagementConsoleDocument", false, "Shader path could not be normalized: '%s'.", m_relativePath.c_str());
return false;
}
AZStd::string shaderPath = m_relativePath;
@@ -118,78 +106,28 @@ namespace ShaderManagementConsole
m_shaderAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::ShaderAsset>(shaderPath.c_str());
if (!m_shaderAsset)
{
return AZ::Failure(AZStd::string::format("Could not load shader asset: %s.", shaderPath.c_str()));
AZ_Error("ShaderManagementConsoleDocument", false, "Could not load shader asset: %s.", shaderPath.c_str());
return false;
}
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentOpened, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, m_id);
return AZ::Success(AZStd::string::format("Document loaded: '%s'", m_absolutePath.c_str()));
AZ_TracePrintf("ShaderManagementConsoleDocument", "Document opened: '%s'\n", m_absolutePath.c_str());
return true;
}
ShaderManagementConsoleDocumentResult ShaderManagementConsoleDocument::Save()
bool ShaderManagementConsoleDocument::Close()
{
if (!IsOpen())
{
return AZ::Failure(AZStd::string::format("Document is not open to be saved: '%s'.", m_absolutePath.c_str()));
}
if (!IsSavable())
{
return AZ::Failure(AZStd::string::format("Document can not be saved: '%s'.", m_absolutePath.c_str()));
}
return AZ::Failure(AZStd::string::format("%s is not implemented!", __FUNCTION__));
// Auto add or checkout saved file
//AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit,
// m_absolutePath.c_str(), true,
// [](bool, const AzToolsFramework::SourceControlFileInfo&) {});
//ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentSaved, m_id);
//return AZ::Success(AZStd::string::format("Document saved: %s", m_absolutePath.data()));
}
ShaderManagementConsoleDocumentResult ShaderManagementConsoleDocument::SaveAsCopy(AZStd::string_view savePath)
{
if (!IsOpen())
{
return AZ::Failure(AZStd::string::format("Document is not open to be saved: '%s'.", m_absolutePath.c_str()));
}
if (!IsSavable())
{
return AZ::Failure(AZStd::string::format("Document can not be saved: '%s'.", m_absolutePath.c_str()));
}
AZStd::string normalizedSavePath = savePath;
if (!AzFramework::StringFunc::Path::Normalize(normalizedSavePath))
{
return AZ::Failure(AZStd::string::format("Document save path could not be normalized: '%s'.", normalizedSavePath.c_str()));
}
return AZ::Failure(AZStd::string::format("%s is not implemented!", __FUNCTION__));
// Auto add or checkout saved file
//AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit,
// normalizedSavePath.c_str(), true,
// [](bool, const AzToolsFramework::SourceControlFileInfo&) {});
//ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentSaved, m_id);
//return AZ::Success(AZStd::string::format("Document saved: %s", normalizedSavePath.c_str()));
}
ShaderManagementConsoleDocumentResult ShaderManagementConsoleDocument::Close()
{
if (!IsOpen())
{
return AZ::Failure(AZStd::string("Document is not open"));
AZ_Error("ShaderManagementConsoleDocument", false, "Document is not open");
return false;
}
Clear();
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentClosed, m_id);
return AZ::Success(AZStd::string("Document was closed"));
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentClosed, m_id);
AZ_TracePrintf("ShaderManagementConsoleDocument", "Document closed\n");
return true;
}
bool ShaderManagementConsoleDocument::IsOpen() const
@@ -197,77 +135,11 @@ namespace ShaderManagementConsole
return !m_absolutePath.empty() && !m_relativePath.empty();
}
bool ShaderManagementConsoleDocument::IsModified() const
{
return false;
}
bool ShaderManagementConsoleDocument::IsSavable() const
{
return true;
}
bool ShaderManagementConsoleDocument::CanUndo() const
{
// Undo will only be allowed if something has been recorded and we're not at the beginning of history
return IsOpen() && !m_undoHistory.empty() && m_undoHistoryIndex > 0;
}
bool ShaderManagementConsoleDocument::CanRedo() const
{
// Redo will only be allowed if something has been recorded and we're not at the end of history
return IsOpen() && !m_undoHistory.empty() && m_undoHistoryIndex < m_undoHistory.size();
}
bool ShaderManagementConsoleDocument::Undo()
{
if (CanUndo())
{
// The history index is one beyond the last executed command. Decrement the index then execute undo.
m_undoHistory[--m_undoHistoryIndex].first();
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
return true;
}
return false;
}
bool ShaderManagementConsoleDocument::Redo()
{
if (CanRedo())
{
// Execute the current redo command then move the history index to the next position.
m_undoHistory[m_undoHistoryIndex++].second();
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
return true;
}
return false;
}
bool ShaderManagementConsoleDocument::BeginEdit()
{
return true;
}
bool ShaderManagementConsoleDocument::EndEdit()
{
// Wipe any state beyond the current history index
m_undoHistory.erase(m_undoHistory.begin() + m_undoHistoryIndex, m_undoHistory.end());
// Add undo and redo operations using lambdas that will capture property state and restore it when executed
m_undoHistory.emplace_back(
[this]() { /**/ },
[this]() { /**/ });
// Assign the index to the end of history
m_undoHistoryIndex = aznumeric_cast<int>(m_undoHistory.size());
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
return true;
}
void ShaderManagementConsoleDocument::Clear()
{
m_absolutePath.clear();
m_relativePath.clear();
m_shaderVariantListSourceData = {};
m_shaderAsset = {};
}
} // namespace ShaderManagementConsole
@@ -7,13 +7,12 @@
*/
#pragma once
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Asset/AssetCommon.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h>
#include <Atom/Document/ShaderManagementConsoleDocumentRequestBus.h>
#include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <AtomToolsFramework/Document/AtomToolsDocument.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/RTTI.h>
namespace ShaderManagementConsole
{
@@ -21,7 +20,8 @@ namespace ShaderManagementConsole
* ShaderManagementConsoleDocument provides an API for modifying and saving document properties.
*/
class ShaderManagementConsoleDocument
: public ShaderManagementConsoleDocumentRequestBus::Handler
: public AtomToolsFramework::AtomToolsDocument
, public ShaderManagementConsoleDocumentRequestBus::Handler
{
public:
AZ_RTTI(ShaderManagementConsoleDocument, "{DBA269AE-892B-415C-8FA1-166B94B0E045}");
@@ -31,29 +31,20 @@ namespace ShaderManagementConsole
ShaderManagementConsoleDocument();
virtual ~ShaderManagementConsoleDocument();
const AZ::Uuid& GetId() const;
////////////////////////////////////////////////////////////////////////
// AtomToolsFramework::AtomToolsDocument
////////////////////////////////////////////////////////////////////////
bool Open(AZStd::string_view loadPath) override;
bool Close() override;
bool IsOpen() const override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// ShaderManagementConsoleDocumentRequestBus::Handler implementation
AZStd::string_view GetAbsolutePath() const override;
AZStd::string_view GetRelativePath() const override;
size_t GetShaderOptionCount() const override;
const AZ::RPI::ShaderOptionDescriptor& GetShaderOptionDescriptor(size_t index) const override;
size_t GetShaderVariantCount() const override;
const AZ::RPI::ShaderVariantListSourceData::VariantInfo& GetShaderVariantInfo(size_t index) const override;
ShaderManagementConsoleDocumentResult Open(AZStd::string_view loadPath) override;
ShaderManagementConsoleDocumentResult Save() override;
ShaderManagementConsoleDocumentResult SaveAsCopy(AZStd::string_view savePath) override;
ShaderManagementConsoleDocumentResult 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;
////////////////////////////////////////////////////////////////////////
private:
@@ -67,28 +58,11 @@ namespace ShaderManagementConsole
using UndoRedoHistory = AZStd::vector<UndoRedoFunctionPair>;
void Clear();
// Unique id of this document
AZ::Uuid m_id = AZ::Uuid::CreateRandom();
// Relative path to the document
AZStd::string m_relativePath;
// Absolute path to the document
AZStd::string m_absolutePath;
// Source data for shader variant list
AZ::RPI::ShaderVariantListSourceData m_shaderVariantListSourceData;
// Shader asset for the corresponding shader variant list
AZ::Data::Asset<AZ::RPI::ShaderAsset> m_shaderAsset;
// Variables needed for tracking the undo and redo state of this document
// Container of undo commands
UndoRedoHistory m_undoHistory;
// The current position in the undo redo history
int m_undoHistoryIndex = 0;
};
} // namespace ShaderManagementConsole
@@ -7,10 +7,8 @@
*/
#include <Atom/Document/ShaderManagementConsoleDocumentModule.h>
#include <Document/ShaderManagementConsoleDocumentSystemComponent.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyManagerComponent.h>
#include <AzToolsFramework/Asset/AssetSystemComponent.h>
#include <Document/ShaderManagementConsoleDocumentSystemComponent.h>
namespace ShaderManagementConsole
{
@@ -6,39 +6,16 @@
*
*/
#include <Document/ShaderManagementConsoleDocumentSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzFramework/Asset/AssetSystemBus.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/API/ViewPaneOptions.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AtomToolsFramework/Util/Util.h>
#include <Atom/Document/ShaderManagementConsoleDocumentSystemRequestBus.h>
#include <Atom/Document/ShaderManagementConsoleDocumentRequestBus.h>
#include <Atom/Document/ShaderManagementConsoleDocumentNotificationBus.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QApplication>
#include <QStyle>
#include <QMessageBox>
#include <QFileDialog>
AZ_POP_DISABLE_WARNING
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Document/ShaderManagementConsoleDocument.h>
#include <Document/ShaderManagementConsoleDocumentSystemComponent.h>
namespace ShaderManagementConsole
{
ShaderManagementConsoleDocumentSystemComponent::ShaderManagementConsoleDocumentSystemComponent()
{
}
void ShaderManagementConsoleDocumentSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
@@ -50,7 +27,7 @@ namespace ShaderManagementConsole
{
ec->Class<ShaderManagementConsoleDocumentSystemComponent>("ShaderManagementConsoleDocumentSystemComponent", "Manages documents")
->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)
;
}
@@ -58,63 +35,35 @@ namespace ShaderManagementConsole
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<ShaderManagementConsoleDocumentSystemRequestBus>("ShaderManagementConsoleDocumentSystemRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole")
->Event("CreateDocument", &ShaderManagementConsoleDocumentSystemRequestBus::Events::CreateDocument)
->Event("DestroyDocument", &ShaderManagementConsoleDocumentSystemRequestBus::Events::DestroyDocument)
->Event("OpenDocument", &ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument)
->Event("CloseDocument", &ShaderManagementConsoleDocumentSystemRequestBus::Events::CloseDocument)
->Event("CloseAllDocuments", &ShaderManagementConsoleDocumentSystemRequestBus::Events::CloseAllDocuments)
->Event("SaveDocument", &ShaderManagementConsoleDocumentSystemRequestBus::Events::SaveDocument)
->Event("SaveDocumentAsCopy", &ShaderManagementConsoleDocumentSystemRequestBus::Events::SaveDocumentAsCopy)
->Event("SaveAllDocuments", &ShaderManagementConsoleDocumentSystemRequestBus::Events::SaveAllDocuments)
;
behaviorContext->EBus<ShaderManagementConsoleDocumentRequestBus>("ShaderManagementConsoleDocumentRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole")
->Event("GetAbsolutePath", &ShaderManagementConsoleDocumentRequestBus::Events::GetAbsolutePath)
->Event("GetRelativePath", &ShaderManagementConsoleDocumentRequestBus::Events::GetRelativePath)
->Event("GetShaderOptionCount", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount)
->Event("GetShaderOptionDescriptor", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor)
->Event("GetShaderVariantCount", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount)
->Event("GetShaderVariantInfo", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo)
->Event("Open", &ShaderManagementConsoleDocumentRequestBus::Events::Open)
->Event("Close", &ShaderManagementConsoleDocumentRequestBus::Events::Close)
->Event("Save", &ShaderManagementConsoleDocumentRequestBus::Events::Save)
->Event("SaveAsCopy", &ShaderManagementConsoleDocumentRequestBus::Events::SaveAsCopy)
->Event("IsOpen", &ShaderManagementConsoleDocumentRequestBus::Events::IsOpen)
->Event("IsModified", &ShaderManagementConsoleDocumentRequestBus::Events::IsModified)
->Event("IsSavable", &ShaderManagementConsoleDocumentRequestBus::Events::IsSavable)
->Event("CanUndo", &ShaderManagementConsoleDocumentRequestBus::Events::CanUndo)
->Event("CanRedo", &ShaderManagementConsoleDocumentRequestBus::Events::CanRedo)
->Event("Undo", &ShaderManagementConsoleDocumentRequestBus::Events::Undo)
->Event("Redo", &ShaderManagementConsoleDocumentRequestBus::Events::Redo)
->Event("BeginEdit", &ShaderManagementConsoleDocumentRequestBus::Events::BeginEdit)
->Event("EndEdit", &ShaderManagementConsoleDocumentRequestBus::Events::EndEdit)
;
}
}
void ShaderManagementConsoleDocumentSystemComponent::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 ShaderManagementConsoleDocumentSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ShaderManagementConsoleDocumentSystemService"));
provided.push_back(AZ_CRC_CE("ShaderManagementConsoleDocumentSystemService"));
}
void ShaderManagementConsoleDocumentSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("ShaderManagementConsoleDocumentSystemService"));
incompatible.push_back(AZ_CRC_CE("ShaderManagementConsoleDocumentSystemService"));
}
void ShaderManagementConsoleDocumentSystemComponent::Init()
@@ -123,203 +72,15 @@ namespace ShaderManagementConsole
void ShaderManagementConsoleDocumentSystemComponent::Activate()
{
m_documentMap.clear();
ShaderManagementConsoleDocumentSystemRequestBus::Handler::BusConnect();
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType,
[]()
{
return aznew ShaderManagementConsoleDocument();
});
}
void ShaderManagementConsoleDocumentSystemComponent::Deactivate()
{
ShaderManagementConsoleDocumentSystemRequestBus::Handler::BusDisconnect();
m_documentMap.clear();
}
AZ::Uuid ShaderManagementConsoleDocumentSystemComponent::CreateDocument()
{
auto document = AZStd::make_unique<ShaderManagementConsoleDocument>();
if (!document)
{
AZ_Error("ShaderManagementConsoleDocument", false, "Failed to create new document");
return AZ::Uuid::CreateNull();
}
AZ::Uuid documentId = document->GetId();
m_documentMap.emplace(documentId, document.release());
return documentId;
}
bool ShaderManagementConsoleDocumentSystemComponent::DestroyDocument(const AZ::Uuid& documentId)
{
return m_documentMap.erase(documentId) != 0;
}
AZ::Uuid ShaderManagementConsoleDocumentSystemComponent::OpenDocument(AZStd::string_view path)
{
return OpenDocumentImpl(path, true);
}
bool ShaderManagementConsoleDocumentSystemComponent::CloseDocument(const AZ::Uuid& documentId)
{
bool isOpen = false;
ShaderManagementConsoleDocumentRequestBus::EventResult(isOpen, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::IsOpen);
if (!isOpen)
{
return true;
}
bool isModified = false;
ShaderManagementConsoleDocumentRequestBus::EventResult(isModified, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::IsModified);
if (isModified)
{
if (QMessageBox::question(QApplication::activeWindow(), "document has unsaved changes", "Would you like to close anyway?",
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
{
return false;
}
}
ShaderManagementConsoleDocumentResult closeResult = AZ::Success(AZStd::string("There is no active document"));
ShaderManagementConsoleDocumentRequestBus::EventResult(closeResult, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::Close);
if (!closeResult)
{
QMessageBox::critical(QApplication::activeWindow(), "Failed to close document",
QString::fromUtf8(closeResult.GetError().data(), (int)closeResult.GetError().size()));
return false;
}
ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(&ShaderManagementConsoleDocumentSystemRequestBus::Events::DestroyDocument, documentId);
return true;
}
bool ShaderManagementConsoleDocumentSystemComponent::CloseAllDocuments()
{
bool result = true;
auto documentMap = m_documentMap;
for (const auto& documentPair : documentMap)
{
if (!CloseDocument(documentPair.first))
{
result = false;
}
}
return result;
}
bool ShaderManagementConsoleDocumentSystemComponent::SaveDocument(const AZ::Uuid& documentId)
{
AZStd::string documentPath;
ShaderManagementConsoleDocumentRequestBus::EventResult(documentPath, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetAbsolutePath);
const QFileInfo saveInfo(documentPath.c_str());
if (saveInfo.absoluteFilePath().isEmpty())
{
return false;
}
if (saveInfo.exists() && !saveInfo.isWritable())
{
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Unable to save document. File can not be overwritten."));
return false;
}
ShaderManagementConsoleDocumentResult result = AZ::Failure(AZStd::string("There is no active document"));
ShaderManagementConsoleDocumentRequestBus::EventResult(result, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::Save);
if (!result)
{
QMessageBox::critical(QApplication::activeWindow(), "document not saved",
QString::fromUtf8(result.GetError().data(), (int)result.GetError().size()));
return false;
}
AZ_TracePrintf("ShaderManagementConsole", "%s\n", result.GetValue().c_str());
return true;
}
bool ShaderManagementConsoleDocumentSystemComponent::SaveDocumentAsCopy(const AZ::Uuid& documentId)
{
AZStd::string documentPath;
ShaderManagementConsoleDocumentRequestBus::EventResult(documentPath, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetAbsolutePath);
const QFileInfo& saveInfo = AtomToolsFramework::GetSaveFileInfo(documentPath.c_str());
if (saveInfo.absoluteFilePath().isEmpty())
{
return false;
}
AZStd::string saveDocumentPath = saveInfo.absoluteFilePath().toUtf8().constData();
AzFramework::StringFunc::Path::Normalize(saveDocumentPath);
ShaderManagementConsoleDocumentResult result = AZ::Failure(AZStd::string("There is no active document"));
ShaderManagementConsoleDocumentRequestBus::EventResult(result, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::SaveAsCopy, saveDocumentPath);
if (!result)
{
QMessageBox::critical(QApplication::activeWindow(), "document copy not saved",
QString::fromUtf8(result.GetError().data(), (int)result.GetError().size()));
return false;
}
AZ_TracePrintf("ShaderManagementConsole", "%s\n", result.GetValue().c_str());
return true;
}
bool ShaderManagementConsoleDocumentSystemComponent::SaveAllDocuments()
{
bool result = true;
for (const auto& documentPair : m_documentMap)
{
if (!SaveDocument(documentPair.first))
{
result = false;
}
}
return result;
}
AZ::Uuid ShaderManagementConsoleDocumentSystemComponent::OpenDocumentImpl(AZStd::string_view path, bool checkIfAlreadyOpen)
{
AZStd::string requestedPath = path;
if (requestedPath.empty() || !AzFramework::StringFunc::Path::Normalize(requestedPath))
{
QMessageBox::critical(QApplication::activeWindow(), "document path is invalid",
QString::fromUtf8(requestedPath.data(), (int)requestedPath.size()));
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;
ShaderManagementConsoleDocumentRequestBus::EventResult(openDocumentPath, documentPair.first, &ShaderManagementConsoleDocumentRequestBus::Events::GetAbsolutePath);
if (openDocumentPath == requestedPath)
{
ShaderManagementConsoleDocumentNotificationBus::Broadcast(&ShaderManagementConsoleDocumentNotificationBus::Events::OnDocumentOpened, documentPair.first);
return documentPair.first;
}
}
}
AZ::Uuid documentId = AZ::Uuid::CreateNull();
ShaderManagementConsoleDocumentSystemRequestBus::BroadcastResult(documentId, &ShaderManagementConsoleDocumentSystemRequestBus::Events::CreateDocument);
if (documentId.IsNull())
{
QMessageBox::critical(QApplication::activeWindow(), "Failed to create document",
QString::fromUtf8(requestedPath.data(), (int)requestedPath.size()));
return AZ::Uuid::CreateNull();
}
ShaderManagementConsoleDocumentResult openResult = AZ::Failure(AZStd::string("Failed to open document"));
ShaderManagementConsoleDocumentRequestBus::EventResult(openResult, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::Open, requestedPath);
if (!openResult)
{
QMessageBox::critical(QApplication::activeWindow(), "Failed to open document",
QString::fromUtf8(openResult.GetError().data(), (int)openResult.GetError().size()));
ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(&ShaderManagementConsoleDocumentSystemRequestBus::Events::DestroyDocument, documentId);
return AZ::Uuid::CreateNull();
}
return documentId;
}
}
@@ -9,28 +9,17 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <Atom/Document/ShaderManagementConsoleDocumentSystemRequestBus.h>
#include <Atom/RPI.Public/WindowContext.h>
#include <Document/ShaderManagementConsoleDocument.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QFileInfo>
#include <QString>
AZ_POP_DISABLE_WARNING
namespace ShaderManagementConsole
{
//! ShaderManagementConsoleDocumentSystemComponent is the central component of the Shader Management Console Core gem
//! ShaderManagementConsoleDocumentSystemComponent
class ShaderManagementConsoleDocumentSystemComponent
: public AZ::Component
, private ShaderManagementConsoleDocumentSystemRequestBus::Handler
{
public:
AZ_COMPONENT(ShaderManagementConsoleDocumentSystemComponent, "{58ABE0AE-2710-41E2-ADFD-E2D67407427D}");
AZ_COMPONENT(ShaderManagementConsoleDocumentSystemComponent, "{1610159D-59DC-48B1-B2D1-FCE7AFD3B012}");
ShaderManagementConsoleDocumentSystemComponent();
ShaderManagementConsoleDocumentSystemComponent() = default;
~ShaderManagementConsoleDocumentSystemComponent() = default;
ShaderManagementConsoleDocumentSystemComponent(const ShaderManagementConsoleDocumentSystemComponent&) = delete;
ShaderManagementConsoleDocumentSystemComponent& operator =(const ShaderManagementConsoleDocumentSystemComponent&) = delete;
@@ -48,21 +37,5 @@ namespace ShaderManagementConsole
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// ShaderManagementConsoleDocumentSystemRequestBus::Handler overrides...
AZ::Uuid CreateDocument() override;
bool DestroyDocument(const AZ::Uuid& documentId) override;
AZ::Uuid OpenDocument(AZStd::string_view path) override;
bool CloseDocument(const AZ::Uuid& documentId) override;
bool CloseAllDocuments() override;
bool SaveDocument(const AZ::Uuid& documentId) override;
bool SaveDocumentAsCopy(const AZ::Uuid& documentId) override;
bool SaveAllDocuments() override;
////////////////////////////////////////////////////////////////////////
AZ::Uuid OpenDocumentImpl(AZStd::string_view path, bool checkIfAlreadyOpen);
AZStd::unordered_map<AZ::Uuid, AZStd::shared_ptr<ShaderManagementConsoleDocument>> m_documentMap;
};
}
@@ -7,8 +7,8 @@
*/
#include <Atom/Document/ShaderManagementConsoleDocumentModule.h>
#include <Atom/Document/ShaderManagementConsoleDocumentSystemRequestBus.h>
#include <Atom/Window/ShaderManagementConsoleWindowModule.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <ShaderManagementConsoleApplication.h>
#include <ShaderManagementConsole_Traits_Platform.h>
@@ -66,8 +66,8 @@ namespace ShaderManagementConsole
const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex);
AZ_Printf(GetBuildTargetName().c_str(), "Opening document: %s", openDocumentPath.c_str());
ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(
&ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
}
Base::ProcessCommandLine(commandLine);
@@ -8,8 +8,8 @@
#pragma once
#include <Atom/Document/ShaderManagementConsoleDocumentSystemRequestBus.h>
#include <AtomToolsFramework/Application/AtomToolsApplication.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
namespace ShaderManagementConsole
{

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