From 002a4a4a2120687773e0cb8a6986109818dbf58a Mon Sep 17 00:00:00 2001 From: Dayo Lawal Date: Wed, 21 Jul 2021 14:50:23 -0500 Subject: [PATCH] AtomToolsApplication working with MatEditor Signed-off-by: Dayo Lawal --- .../Application/AtomToolsApplication.h | 92 ++++ .../Application/AtomToolsApplication.cpp | 428 ++++++++++++++++++ .../Code/atomtoolsframework_files.cmake | 2 + .../Code/Source/MaterialEditorApplication.cpp | 203 +-------- .../Code/Source/MaterialEditorApplication.h | 53 +-- .../ShaderManagementConsoleApplication.cpp | 170 +------ .../ShaderManagementConsoleApplication.h | 21 +- 7 files changed, 535 insertions(+), 434 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h new file mode 100644 index 0000000000..dc34ad9a0a --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace AtomToolsFramework +{ + class AtomToolsApplication + : public AzFramework::Application + , public AzQtComponents::AzQtApplication + , protected AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler + , protected AzFramework::AssetSystemStatusBus::Handler + , protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler + , protected AZ::Debug::TraceMessageBus::Handler + , protected AZ::UserSettingsOwnerRequestBus::Handler + { + public: + AZ_TYPE_INFO(AtomTools::AtomToolsApplication, "{30F90CA5-1253-49B5-8143-19CEE37E22BB}"); + + using Base = AzFramework::Application; + + AtomToolsApplication(int* argc, char*** argv); + + ////////////////////////////////////////////////////////////////////////// + // AzFramework::Application + void CreateReflectionManager() override; + void Reflect(AZ::ReflectContext* context) override; + void RegisterCoreComponents() override; + AZ::ComponentTypeList GetRequiredSystemComponents() const override; + void CreateStaticModules(AZStd::vector& outModules) override; + const char* GetCurrentConfigurationName() const override; + void StartCommon(AZ::Entity* systemEntity) override; + void Tick(float deltaOverride = -1.f) override; + void Stop() override; + + protected: + ////////////////////////////////////////////////////////////////////////// + // AssetDatabaseRequestsBus::Handler overrides... + bool GetAssetDatabaseLocation(AZStd::string& result) override; + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // AzFramework::Application overrides... + void Destroy() override; + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // AZ::ComponentApplication overrides... + void QueryApplicationType(AZ::ApplicationTypeQuery& appType) const override; + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // AZ::UserSettingsOwnerRequestBus::Handler overrides... + void SaveSettings() override; + ////////////////////////////////////////////////////////////////////////// + + virtual void LoadSettings(); + virtual void UnloadSettings(); + virtual void CompileCriticalAssets(); + virtual void ProcessCommandLine(const AZ::CommandLine& commandLine); + virtual bool LaunchDiscoveryService(); + virtual void StartInternal(); + + static void PyIdleWaitFrames(uint32_t frames); + + AzToolsFramework::TraceLogger m_traceLogger; + + //! Local user settings are used to store material browser tree expansion state + AZ::UserSettingsProvider m_localUserSettings; + + //! Are local settings loaded + bool m_activatedLocalUserSettings = false; + + QTimer m_timer; + + AtomToolsFramework::LocalSocket m_socket; + AtomToolsFramework::LocalServer m_server; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp new file mode 100644 index 0000000000..35a151e95b --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -0,0 +1,428 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +AZ_POP_DISABLE_WARNING + +namespace AtomToolsFramework +{ + //! This function returns the build system target name of "AtomTools +// AZStd::string_view GetBuildTargetName() +// { +//#if !defined(LY_CMAKE_TARGET) +//#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" +//#endif +// return AZStd::string_view{ LY_CMAKE_TARGET }; +// } + + const char* AtomToolsApplication::GetCurrentConfigurationName() const + { +#if defined(_RELEASE) + return "ReleaseAtomTools"; +#elif defined(_DEBUG) + return "DebugAtomTools"; +#else + return "ProfileAtomTools"; +#endif + } + + + AtomToolsApplication::AtomToolsApplication(int* argc, char*** argv) + : Application(argc, argv) + , AzQtApplication(*argc, *argv) + { + } + + void AtomToolsApplication::CreateReflectionManager() + { + Application::CreateReflectionManager(); + GetSerializeContext()->CreateEditContext(); + } + + void AtomToolsApplication::Reflect(AZ::ReflectContext* context) + { + Application::Reflect(context); + + AzToolsFramework::AssetBrowser::AssetBrowserEntry::Reflect(context); + AzToolsFramework::AssetBrowser::RootAssetBrowserEntry::Reflect(context); + AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry::Reflect(context); + AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::Reflect(context); + AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry::Reflect(context); + + AzToolsFramework::QTreeViewWithStateSaving::Reflect(context); + AzToolsFramework::QWidgetSavedState::Reflect(context); + + if (auto behaviorContext = azrtti_cast(context)) + { + // this will put these methods into the 'azlmbr.AtomTools.general' module + auto addGeneral = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder) + { + methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Category, "Editor") + ->Attribute(AZ::Script::Attributes::Module, "AtomTools.general"); + }; + // The reflection here is based on patterns in CryEditPythonHandler::Reflect + addGeneral(behaviorContext->Method( + "idle_wait_frames", &AtomToolsApplication::PyIdleWaitFrames, nullptr, + "Waits idling for a frames. Primarily used for auto-testing.")); + } + } + + void AtomToolsApplication::RegisterCoreComponents() + { + Application::RegisterCoreComponents(); + RegisterComponentDescriptor(AzToolsFramework::AssetBrowser::AssetBrowserComponent::CreateDescriptor()); + RegisterComponentDescriptor(AzToolsFramework::Thumbnailer::ThumbnailerComponent::CreateDescriptor()); + RegisterComponentDescriptor(AzToolsFramework::Components::PropertyManagerComponent::CreateDescriptor()); + RegisterComponentDescriptor(AzToolsFramework::AssetSystem::AssetSystemComponent::CreateDescriptor()); + RegisterComponentDescriptor(AzToolsFramework::PerforceComponent::CreateDescriptor()); + } + + AZ::ComponentTypeList AtomToolsApplication::GetRequiredSystemComponents() const + { + AZ::ComponentTypeList components = Application::GetRequiredSystemComponents(); + + components.insert( + components.end(), + { + azrtti_typeid(), + azrtti_typeid(), + azrtti_typeid(), + azrtti_typeid(), + }); + + return components; + } + + void AtomToolsApplication::CreateStaticModules(AZStd::vector& outModules) + { + Application::CreateStaticModules(outModules); + outModules.push_back(aznew AzToolsFramework::AzToolsFrameworkModule); + } + + void AtomToolsApplication::StartCommon(AZ::Entity* systemEntity) + { + AzFramework::AssetSystemStatusBus::Handler::BusConnect(); + AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect(); + + AzFramework::Application::StartCommon(systemEntity); + + StartInternal(); + + m_timer.start(); + } + + void AtomToolsApplication::Destroy() + { + AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + + m_logFile = {}; + m_startupLogSink = {}; + + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::StartDisconnectingAssetProcessor); + Application::Destroy(); + } + + void AtomToolsApplication::CompileCriticalAssets() + { + AZ_TracePrintf("AtomTools", "Compiling critical assets.\n"); + + // List of common asset filters for things that need to be compiled to run the material editor + // Some of these things will not be necessary once we have proper support for queued asset loading and reloading + const AZStd::string assetFiltersArray[] = { + "passes/", + "config/", + }; + + QStringList failedAssets; + + // Forced asset processor to synchronously process all critical assets + // Note: with AssetManager's current implementation, a compiled asset won't be added in asset registry until next system tick. + // So the asset id won't be found right after CompileAssetSync call. + for (const AZStd::string& assetFilters : assetFiltersArray) + { + AZ_TracePrintf("AtomTools", "Compiling critical asset matching: %s.\n", assetFilters.c_str()); + + // Wait for the asset be compiled + AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; + AzFramework::AssetSystemRequestBus::BroadcastResult( + status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, assetFilters); + if (status != AzFramework::AssetSystem::AssetStatus_Compiled) + { + failedAssets.append(assetFilters.c_str()); + } + } + + if (!failedAssets.empty()) + { + QMessageBox::critical( + activeWindow(), QString("Failed to compile critical assets"), + QString("Failed to compile the following critical assets:\n%1\n%2") + .arg(failedAssets.join(",\n")) + .arg("Make sure this is an Atom project.")); + ExitMainLoop(); + } + } + + void AtomToolsApplication::SaveSettings() + { + if (m_activatedLocalUserSettings) + { + AZ::SerializeContext* context = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); + AZ_Assert(context, "No serialize context"); + + char resolvedPath[AZ_MAX_PATH_LEN] = ""; + AZ::IO::FileIOBase::GetInstance()->ResolvePath( + "@user@/MaterialEditorUserSettings.xml", resolvedPath, AZ_ARRAY_SIZE(resolvedPath)); + m_localUserSettings.Save(resolvedPath, context); + } + } + + + void AtomToolsApplication::LoadSettings() + { + AZ::SerializeContext* context = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); + AZ_Assert(context, "No serialize context"); + + char resolvedPath[AZ_MAX_PATH_LEN] = ""; + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/EditorUserSettings.xml", resolvedPath, AZ_MAX_PATH_LEN); + + m_localUserSettings.Load(resolvedPath, context); + m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL); + AZ::UserSettingsOwnerRequestBus::Handler::BusConnect(AZ::UserSettings::CT_LOCAL); + m_activatedLocalUserSettings = true; + } + + void AtomToolsApplication::UnloadSettings() + { + if (m_activatedLocalUserSettings) + { + //SaveSettings(); + m_localUserSettings.Deactivate(); + AZ::UserSettingsOwnerRequestBus::Handler::BusDisconnect(); + m_activatedLocalUserSettings = false; + } + } + + void AtomToolsApplication::ProcessCommandLine(const AZ::CommandLine& commandLine) + { + const AZStd::string exitAfterCommandsSwitchName = "exitaftercommands"; + if (commandLine.HasSwitch(exitAfterCommandsSwitchName)) + { + ExitMainLoop(); + } + } + + bool AtomToolsApplication::LaunchDiscoveryService() + { + // Determine if this is the first launch of the tool by attempting to connect to a running server + if (m_socket.Connect(QApplication::applicationName())) + { + // If the server was located, the application is already running. + // Forward commandline options to other application instance. + QByteArray buffer; + buffer.append("ProcessCommandLine:"); + + // Add the command line options from this process to the message, skipping the executable path + for (int argi = 1; argi < m_argC; ++argi) + { + buffer.append(QString(m_argV[argi]).append("\n").toUtf8()); + } + + // Inject command line option to always bring the main window to the foreground + buffer.append("--activatewindow\n"); + + m_socket.Send(buffer); + m_socket.Disconnect(); + return false; + } + + // Setup server to handle basic commands + m_server.SetReadHandler( + [this](const QByteArray& buffer) + { + // Handle commmand line params from connected socket + if (buffer.startsWith("ProcessCommandLine:")) + { + // Remove header and parse commands + AZStd::string params(buffer.data(), buffer.size()); + params = params.substr(strlen("ProcessCommandLine:")); + + AZStd::vector tokens; + AZ::StringFunc::Tokenize(params, tokens, "\n"); + + if (!tokens.empty()) + { + AZ::CommandLine commandLine; + commandLine.Parse(tokens); + ProcessCommandLine(commandLine); + } + } + }); + + // Launch local server + if (!m_server.Connect(QApplication::applicationName())) + { + return false; + } + + return true; + } + + void AtomToolsApplication::StartInternal() + { + if (WasExitMainLoopRequested()) + { + return; + } + + m_traceLogger.WriteStartupLog("AtomTools.log"); + + if (!LaunchDiscoveryService()) + { + ExitMainLoop(); + return; + } + + AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect(); + AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( + &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); + + AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + + AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets(); + + LoadSettings(); + + auto editorPythonEventsInterface = AZ::Interface::Get(); + if (editorPythonEventsInterface) + { + // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here + // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to + // StopPython + editorPythonEventsInterface->StartPython(); + } + + // Delay execution of commands and scripts post initialization + QTimer::singleShot( + 0, + [this]() + { + ProcessCommandLine(m_commandLine); + }); + } + + bool AtomToolsApplication::GetAssetDatabaseLocation(AZStd::string& result) + { + AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::IO::FixedMaxPath assetDatabaseSqlitePath; + if (settingsRegistry && + settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) + { + assetDatabaseSqlitePath /= "assetdb.sqlite"; + result = AZStd::string_view(assetDatabaseSqlitePath.Native()); + return true; + } + + return false; + } + + void AtomToolsApplication::Tick(float deltaOverride) + { + TickSystem(); + Application::Tick(deltaOverride); + + if (WasExitMainLoopRequested()) + { + m_timer.disconnect(); + quit(); + } + } + + void AtomToolsApplication::Stop() + { + UnloadSettings(); + AzFramework::Application::Stop(); + } + + void AtomToolsApplication::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const + { + appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Game; + } + + // Copied from PyIdleWaitFrames in CryEdit.cpp + void AtomToolsApplication::PyIdleWaitFrames(uint32_t frames) + { + struct Ticker : public AZ::TickBus::Handler + { + Ticker(QEventLoop* loop, uint32_t targetFrames) + : m_loop(loop) + , m_targetFrames(targetFrames) + { + AZ::TickBus::Handler::BusConnect(); + } + ~Ticker() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override + { + AZ_UNUSED(deltaTime); + AZ_UNUSED(time); + if (++m_elapsedFrames == m_targetFrames) + { + m_loop->quit(); + } + } + QEventLoop* m_loop = nullptr; + uint32_t m_elapsedFrames = 0; + uint32_t m_targetFrames = 0; + }; + + QEventLoop loop; + Ticker ticker(&loop, frames); + loop.exec(); + } + +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index 817840221a..63bdbcd2ab 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -6,6 +6,7 @@ # set(FILES + Include/AtomToolsFramework/Application/AtomToolsApplication.h Include/AtomToolsFramework/Communication/LocalServer.h Include/AtomToolsFramework/Communication/LocalSocket.h Include/AtomToolsFramework/Debug/TraceRecorder.h @@ -22,6 +23,7 @@ set(FILES Include/AtomToolsFramework/Viewport/RenderViewportWidget.h Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h + Source/Application/AtomToolsApplication.cpp Source/Communication/LocalServer.cpp Source/Communication/LocalSocket.cpp Source/Debug/TraceRecorder.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp index f880ad7680..324db34ee8 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp @@ -71,8 +71,8 @@ namespace MaterialEditor } MaterialEditorApplication::MaterialEditorApplication(int* argc, char*** argv) - : Application(argc, argv) - , AzQtApplication(*argc, *argv) + : AtomToolsApplication(argc, argv) + { QApplication::setApplicationName("O3DE Material Editor"); @@ -93,63 +93,6 @@ namespace MaterialEditor AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect(); } - void MaterialEditorApplication::CreateReflectionManager() - { - Application::CreateReflectionManager(); - GetSerializeContext()->CreateEditContext(); - } - - void MaterialEditorApplication::Reflect(AZ::ReflectContext* context) - { - Application::Reflect(context); - - AzToolsFramework::AssetBrowser::AssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::RootAssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry::Reflect(context); - - AzToolsFramework::QTreeViewWithStateSaving::Reflect(context); - AzToolsFramework::QWidgetSavedState::Reflect(context); - - if (auto behaviorContext = azrtti_cast(context)) - { - // this will put these methods into the 'azlmbr.materialeditor.general' module - auto addGeneral = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder) - { - methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Category, "Editor") - ->Attribute(AZ::Script::Attributes::Module, "materialeditor.general"); - }; - // The reflection here is based on patterns in CryEditPythonHandler::Reflect - addGeneral(behaviorContext->Method("idle_wait_frames", &MaterialEditorApplication::PyIdleWaitFrames, nullptr, "Waits idling for a frames. Primarily used for auto-testing.")); - } - } - - void MaterialEditorApplication::RegisterCoreComponents() - { - Application::RegisterCoreComponents(); - RegisterComponentDescriptor(AzToolsFramework::AssetBrowser::AssetBrowserComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::Thumbnailer::ThumbnailerComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::Components::PropertyManagerComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::AssetSystem::AssetSystemComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::PerforceComponent::CreateDescriptor()); - } - - AZ::ComponentTypeList MaterialEditorApplication::GetRequiredSystemComponents() const - { - AZ::ComponentTypeList components = Application::GetRequiredSystemComponents(); - - components.insert(components.end(), { - azrtti_typeid(), - azrtti_typeid(), - azrtti_typeid(), - azrtti_typeid(), - }); - - return components; - } - void MaterialEditorApplication::CreateStaticModules(AZStd::vector& outModules) { Application::CreateStaticModules(outModules); @@ -269,20 +212,6 @@ namespace MaterialEditor } } - void MaterialEditorApplication::SaveSettings() - { - if (m_activatedLocalUserSettings) - { - AZ::SerializeContext* context = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); - AZ_Assert(context, "No serialize context"); - - char resolvedPath[AZ_MAX_PATH_LEN] = ""; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/MaterialEditorUserSettings.xml", resolvedPath, AZ_ARRAY_SIZE(resolvedPath)); - m_localUserSettings.Save(resolvedPath, context); - } - } - bool MaterialEditorApplication::OnOutput(const char* window, const char* message) { // Suppress spam from the Source Control system @@ -355,86 +284,6 @@ namespace MaterialEditor } } - void MaterialEditorApplication::LoadSettings() - { - AZ::SerializeContext* context = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); - AZ_Assert(context, "No serialize context"); - - char resolvedPath[AZ_MAX_PATH_LEN] = ""; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/EditorUserSettings.xml", resolvedPath, AZ_MAX_PATH_LEN); - - m_localUserSettings.Load(resolvedPath, context); - m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL); - AZ::UserSettingsOwnerRequestBus::Handler::BusConnect(AZ::UserSettings::CT_LOCAL); - m_activatedLocalUserSettings = true; - } - - void MaterialEditorApplication::UnloadSettings() - { - if (m_activatedLocalUserSettings) - { - SaveSettings(); - m_localUserSettings.Deactivate(); - AZ::UserSettingsOwnerRequestBus::Handler::BusDisconnect(); - m_activatedLocalUserSettings = false; - } - } - - bool MaterialEditorApplication::LaunchDiscoveryService() - { - // Determine if this is the first launch of the tool by attempting to connect to a running server - if (m_socket.Connect(QApplication::applicationName())) - { - // If the server was located, the application is already running. - // Forward commandline options to other application instance. - QByteArray buffer; - buffer.append("ProcessCommandLine:"); - - // Add the command line options from this process to the message, skipping the executable path - for (int argi = 1; argi < m_argC; ++argi) - { - buffer.append(QString(m_argV[argi]).append("\n").toUtf8()); - } - - // Inject command line option to always bring the main window to the foreground - buffer.append("--activatewindow\n"); - - m_socket.Send(buffer); - m_socket.Disconnect(); - return false; - } - - // Setup server to handle basic commands - m_server.SetReadHandler([this](const QByteArray& buffer) { - // Handle commmand line params from connected socket - if (buffer.startsWith("ProcessCommandLine:")) - { - // Remove header and parse commands - AZStd::string params(buffer.data(), buffer.size()); - params = params.substr(strlen("ProcessCommandLine:")); - - AZStd::vector tokens; - AZ::StringFunc::Tokenize(params, tokens, "\n"); - - if (!tokens.empty()) - { - AZ::CommandLine commandLine; - commandLine.Parse(tokens); - ProcessCommandLine(commandLine); - } - } - }); - - // Launch local server - if (!m_server.Connect(QApplication::applicationName())) - { - return false; - } - - return true; - } - void MaterialEditorApplication::StartInternal() { if (WasExitMainLoopRequested()) @@ -476,20 +325,6 @@ namespace MaterialEditor QTimer::singleShot(0, [this]() { ProcessCommandLine(m_commandLine); }); } - bool MaterialEditorApplication::GetAssetDatabaseLocation(AZStd::string& result) - { - AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); - AZ::IO::FixedMaxPath assetDatabaseSqlitePath; - if (settingsRegistry && settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) - { - assetDatabaseSqlitePath /= "assetdb.sqlite"; - result = AZStd::string_view(assetDatabaseSqlitePath.Native()); - return true; - } - - return false; - } - void MaterialEditorApplication::Tick(float deltaOverride) { TickSystem(); @@ -545,38 +380,4 @@ namespace MaterialEditor { AZ_Error("MaterialEditor", false, "Python: " AZ_STRING_FORMAT, AZ_STRING_ARG(message)); } - - // Copied from PyIdleWaitFrames in CryEdit.cpp - void MaterialEditorApplication::PyIdleWaitFrames(uint32_t frames) - { - struct Ticker : public AZ::TickBus::Handler - { - Ticker(QEventLoop* loop, uint32_t targetFrames) : m_loop(loop), m_targetFrames(targetFrames) - { - AZ::TickBus::Handler::BusConnect(); - } - ~Ticker() - { - AZ::TickBus::Handler::BusDisconnect(); - } - - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override - { - AZ_UNUSED(deltaTime); - AZ_UNUSED(time); - if (++m_elapsedFrames == m_targetFrames) - { - m_loop->quit(); - } - } - QEventLoop* m_loop = nullptr; - uint32_t m_elapsedFrames = 0; - uint32_t m_targetFrames = 0; - }; - - QEventLoop loop; - Ticker ticker(&loop, frames); - loop.exec(); - } - } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h index 284eddee93..86fce0c73b 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -30,29 +31,19 @@ namespace MaterialEditor class MaterialThumbnailRenderer; class MaterialEditorApplication - : public AzFramework::Application - , public AzQtComponents::AzQtApplication - , private AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler + : public AtomToolsFramework::AtomToolsApplication , private MaterialEditorWindowNotificationBus::Handler - , private AzFramework::AssetSystemStatusBus::Handler - , private AZ::UserSettingsOwnerRequestBus::Handler - , private AZ::Debug::TraceMessageBus::Handler - , private AzToolsFramework::EditorPythonConsoleNotificationBus::Handler { public: AZ_TYPE_INFO(MaterialEditor::MaterialEditorApplication, "{30F90CA5-1253-49B5-8143-19CEE37E22BB}"); - using Base = AzFramework::Application; + using Base = AtomToolsFramework::AtomToolsApplication; MaterialEditorApplication(int* argc, char*** argv); virtual ~MaterialEditorApplication(); ////////////////////////////////////////////////////////////////////////// // AzFramework::Application - void CreateReflectionManager() override; - void Reflect(AZ::ReflectContext* context) override; - void RegisterCoreComponents() override; - AZ::ComponentTypeList GetRequiredSystemComponents() const override; void CreateStaticModules(AZStd::vector& outModules) override; const char* GetCurrentConfigurationName() const override; void StartCommon(AZ::Entity* systemEntity) override; @@ -60,11 +51,6 @@ namespace MaterialEditor void Stop() override; private: - ////////////////////////////////////////////////////////////////////////// - // AssetDatabaseRequestsBus::Handler overrides... - bool GetAssetDatabaseLocation(AZStd::string& result) override; - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// // MaterialEditorWindowNotificationBus::Handler overrides... void OnMaterialEditorWindowClosing() override; @@ -92,28 +78,14 @@ namespace MaterialEditor void AssetSystemAvailable() override; ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - // AZ::UserSettingsOwnerRequestBus::Handler overrides... - void SaveSettings() override; - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// // AZ::Debug::TraceMessageBus::Handler overrides... bool OnOutput(const char* window, const char* message) override; ////////////////////////////////////////////////////////////////////////// - void CompileCriticalAssets(); - - void ProcessCommandLine(const AZ::CommandLine& commandLine); - - void LoadSettings(); - void UnloadSettings(); - - bool LaunchDiscoveryService(); - - void StartInternal(); - - static void PyIdleWaitFrames(uint32_t frames); + void CompileCriticalAssets() override; + void ProcessCommandLine(const AZ::CommandLine& commandLine) override; + void StartInternal() override; struct LogMessage { @@ -123,18 +95,5 @@ namespace MaterialEditor AZStd::vector m_startupLogSink; AZStd::unique_ptr m_logFile; - - AzToolsFramework::TraceLogger m_traceLogger; - - //! Local user settings are used to store material browser tree expansion state - AZ::UserSettingsProvider m_localUserSettings; - - //! Are local settings loaded - bool m_activatedLocalUserSettings = false; - - QTimer m_timer; - - AtomToolsFramework::LocalSocket m_socket; - AtomToolsFramework::LocalServer m_server; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index d10893ff46..271a53d73c 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -67,77 +67,13 @@ namespace ShaderManagementConsole } ShaderManagementConsoleApplication::ShaderManagementConsoleApplication(int* argc, char*** argv) - : Application(argc, argv) - , AzQtApplication(*argc, *argv) + : AtomToolsApplication(argc, argv) { QApplication::setApplicationName("O3DE Shader Management Console"); // The settings registry has been created at this point, so add the CMake target AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( *AZ::SettingsRegistry::Get(), GetBuildTargetName()); - - connect(&m_timer, &QTimer::timeout, this, [&]() - { - this->PumpSystemEventLoopUntilEmpty(); - this->Tick(); - }); - } - - void ShaderManagementConsoleApplication::CreateReflectionManager() - { - Application::CreateReflectionManager(); - GetSerializeContext()->CreateEditContext(); - } - - void ShaderManagementConsoleApplication::Reflect(AZ::ReflectContext* context) - { - Application::Reflect(context); - - AzToolsFramework::AssetBrowser::AssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::RootAssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::Reflect(context); - AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry::Reflect(context); - - AzToolsFramework::QTreeViewWithStateSaving::Reflect(context); - AzToolsFramework::QWidgetSavedState::Reflect(context); - - if (auto behaviorContext = azrtti_cast(context)) - { - // this will put these methods into the 'azlmbr.shadermanagementconsole.general' module - auto addGeneral = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder) - { - methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Category, "Editor") - ->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole.general"); - }; - // The reflection here is based on patterns in CryEditPythonHandler::Reflect - addGeneral(behaviorContext->Method("idle_wait_frames", &ShaderManagementConsoleApplication::PyIdleWaitFrames, nullptr, "Waits idling for a frames. Primarily used for auto-testing.")); - } - } - - void ShaderManagementConsoleApplication::RegisterCoreComponents() - { - Application::RegisterCoreComponents(); - RegisterComponentDescriptor(AzToolsFramework::AssetBrowser::AssetBrowserComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::Thumbnailer::ThumbnailerComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::Components::PropertyManagerComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::AssetSystem::AssetSystemComponent::CreateDescriptor()); - RegisterComponentDescriptor(AzToolsFramework::PerforceComponent::CreateDescriptor()); - } - - AZ::ComponentTypeList ShaderManagementConsoleApplication::GetRequiredSystemComponents() const - { - AZ::ComponentTypeList components = Application::GetRequiredSystemComponents(); - - components.insert(components.end(), { - azrtti_typeid(), - azrtti_typeid(), - azrtti_typeid(), - azrtti_typeid(), - }); - - return components; } void ShaderManagementConsoleApplication::CreateStaticModules(AZStd::vector& outModules) @@ -148,18 +84,6 @@ namespace ShaderManagementConsole outModules.push_back(aznew ShaderManagementConsoleWindowModule); } - void ShaderManagementConsoleApplication::StartCommon(AZ::Entity* systemEntity) - { - AzFramework::AssetSystemStatusBus::Handler::BusConnect(); - AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect(); - - AzFramework::Application::StartCommon(systemEntity); - - StartInternal(); - - m_timer.start(); - } - void ShaderManagementConsoleApplication::OnShaderManagementConsoleWindowClosing() { ExitMainLoop(); @@ -174,6 +98,7 @@ namespace ShaderManagementConsole ShaderManagementConsoleWindowNotificationBus::Handler::BusDisconnect(); AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect(); + m_traceLogger.~TraceLogger(); AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::StartDisconnectingAssetProcessor); @@ -254,20 +179,6 @@ namespace ShaderManagementConsole } } - void ShaderManagementConsoleApplication::SaveSettings() - { - if (m_activatedLocalUserSettings) - { - AZ::SerializeContext* context = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); - AZ_Assert(context, "No serialize context"); - - char resolvedPath[AZ_MAX_PATH_LEN] = ""; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/EditorUserSettings.xml", resolvedPath, AZ_ARRAY_SIZE(resolvedPath)); - m_localUserSettings.Save(resolvedPath, context); - } - } - bool ShaderManagementConsoleApplication::OnPrintf(const char* window, const char* /*message*/) { // Suppress spam from the Source Control system @@ -303,32 +214,6 @@ namespace ShaderManagementConsole } } - void ShaderManagementConsoleApplication::LoadSettings() - { - AZ::SerializeContext* context = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); - AZ_Assert(context, "No serialize context"); - - char resolvedPath[AZ_MAX_PATH_LEN] = ""; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/EditorUserSettings.xml", resolvedPath, AZ_MAX_PATH_LEN); - - m_localUserSettings.Load(resolvedPath, context); - m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL); - AZ::UserSettingsOwnerRequestBus::Handler::BusConnect(AZ::UserSettings::CT_LOCAL); - m_activatedLocalUserSettings = true; - } - - void ShaderManagementConsoleApplication::UnloadSettings() - { - if (m_activatedLocalUserSettings) - { - SaveSettings(); - m_localUserSettings.Deactivate(); - AZ::UserSettingsOwnerRequestBus::Handler::BusDisconnect(); - m_activatedLocalUserSettings = false; - } - } - bool ShaderManagementConsoleApplication::LaunchDiscoveryService() { const QStringList arguments = { "-fail_silently" }; @@ -398,17 +283,6 @@ namespace ShaderManagementConsole } } - void ShaderManagementConsoleApplication::Stop() - { - UnloadSettings(); - AzFramework::Application::Stop(); - } - - void ShaderManagementConsoleApplication::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const - { - appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Game; - } - void ShaderManagementConsoleApplication::OnTraceMessage([[maybe_unused]] AZStd::string_view message) { #if defined(AZ_ENABLE_TRACING) @@ -428,48 +302,8 @@ namespace ShaderManagementConsole #endif } - void ShaderManagementConsoleApplication::OnErrorMessage(AZStd::string_view message) - { - // Use AZ_TracePrintf instead of AZ_Error or AZ_Warning to avoid all the metadata noise - OnTraceMessage(message); - } - void ShaderManagementConsoleApplication::OnExceptionMessage([[maybe_unused]] AZStd::string_view message) { AZ_Error("Shader Management Console", false, "Python: " AZ_STRING_FORMAT, AZ_STRING_ARG(message)); } - - // Copied from PyIdleWaitFrames in CryEdit.cpp - void ShaderManagementConsoleApplication::PyIdleWaitFrames(uint32_t frames) - { - struct Ticker : public AZ::TickBus::Handler - { - Ticker(QEventLoop* loop, uint32_t targetFrames) : m_loop(loop), m_targetFrames(targetFrames) - { - AZ::TickBus::Handler::BusConnect(); - } - ~Ticker() - { - AZ::TickBus::Handler::BusDisconnect(); - } - - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override - { - AZ_UNUSED(deltaTime); - AZ_UNUSED(time); - if (++m_elapsedFrames == m_targetFrames) - { - m_loop->quit(); - } - } - QEventLoop* m_loop = nullptr; - uint32_t m_elapsedFrames = 0; - uint32_t m_targetFrames = 0; - }; - - QEventLoop loop; - Ticker ticker(&loop, frames); - loop.exec(); - } - } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h index e74458b2e7..f6dd2f12ea 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h @@ -23,19 +23,17 @@ #include #include +#include #include namespace ShaderManagementConsole { class ShaderManagementConsoleApplication - : public AzFramework::Application - , public AzQtComponents::AzQtApplication - , private AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler + : public AtomToolsFramework::AtomToolsApplication , private ShaderManagementConsoleWindowNotificationBus::Handler , private AzFramework::AssetSystemStatusBus::Handler - , private AZ::UserSettingsOwnerRequestBus::Handler - , private AZ::Debug::TraceMessageBus::Handler + , private AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler , private AzToolsFramework::EditorPythonConsoleNotificationBus::Handler { public: @@ -113,18 +111,5 @@ namespace ShaderManagementConsole void StartInternal(); static void PyIdleWaitFrames(uint32_t frames); - - AzToolsFramework::TraceLogger m_traceLogger; - - //! Local user settings are used to store asset browser tree expansion state - AZ::UserSettingsProvider m_localUserSettings; - - //! Are local settings loaded - bool m_activatedLocalUserSettings = false; - - QTimer m_timer; - - bool m_started = false; - bool m_closing = false; }; } // namespace ShaderManagementConsole