/* * 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 #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 MaterialEditor { //! This function returns the build system target name of "MaterialEditor 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* MaterialEditorApplication::GetCurrentConfigurationName() const { #if defined(_RELEASE) return "ReleaseMaterialEditor"; #elif defined(_DEBUG) return "DebugMaterialEditor"; #else return "ProfileMaterialEditor"; #endif } MaterialEditorApplication::MaterialEditorApplication(int* argc, char*** argv) : AtomToolsApplication(argc, argv) { QApplication::setApplicationName("O3DE Material Editor"); setTargetName("MaterialEditor"); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( *AZ::SettingsRegistry::Get(), GetBuildTargetName()); connect(&m_timer, &QTimer::timeout, this, [&]() { this->PumpSystemEventLoopUntilEmpty(); this->Tick(); }); } MaterialEditorApplication::~MaterialEditorApplication() { AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect(); MaterialEditorWindowNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect(); } void MaterialEditorApplication::CreateStaticModules(AZStd::vector& outModules) { Base::CreateStaticModules(outModules); outModules.push_back(aznew MaterialDocumentModule); outModules.push_back(aznew MaterialViewportModule); outModules.push_back(aznew MaterialEditorWindowModule); } void MaterialEditorApplication::StartCommon(AZ::Entity* systemEntity) { { //[GFX TODO][ATOM-408] This needs to be updated in some way to support the MaterialViewport render widget } Base::StartCommon(systemEntity); } void MaterialEditorApplication::OnMaterialEditorWindowClosing() { ExitMainLoop(); } void MaterialEditorApplication::Destroy() { // before modules are unloaded, destroy UI to free up any assets it cached MaterialEditor::MaterialEditorWindowFactoryRequestBus::Broadcast( &MaterialEditor::MaterialEditorWindowFactoryRequestBus::Handler::DestroyMaterialEditorWindow); MaterialEditorWindowNotificationBus::Handler::BusDisconnect(); Base::Destroy(); } void MaterialEditorApplication::AssetSystemAvailable() { bool connectedToAssetProcessor = false; // When the AssetProcessor is already launched it should take less than a second to perform a connection // but when the AssetProcessor needs to be launch it could take up to 15 seconds to have the AssetProcessor initialize // and able to negotiate a connection when running a debug build // and to negotiate a connection AzFramework::AssetSystem::ConnectionSettings connectionSettings; AzFramework::AssetSystem::ReadConnectionSettingsFromSettingsRegistry(connectionSettings); connectionSettings.m_connectionDirection = AzFramework::AssetSystem::ConnectionSettings::ConnectionDirection::ConnectToAssetProcessor; connectionSettings.m_connectionIdentifier = targetName.c_str(); connectionSettings.m_loggingCallback = []([[maybe_unused]] AZStd::string_view logData) { AZ_TracePrintf("Material Editor", "%.*s", aznumeric_cast(logData.size()), logData.data()); }; AzFramework::AssetSystemRequestBus::BroadcastResult(connectedToAssetProcessor, &AzFramework::AssetSystemRequestBus::Events::EstablishAssetProcessorConnection, connectionSettings); // 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::vector assetFiltersArray = { "passes/", "config/", "MaterialEditor/" }; if (connectedToAssetProcessor) { CompileCriticalAssets(assetFiltersArray); } AzFramework::AssetSystemStatusBus::Handler::BusDisconnect(); } void MaterialEditorApplication::ProcessCommandLine(const AZ::CommandLine& commandLine) { const AZStd::string activateWindowSwitchName = "activatewindow"; if (commandLine.HasSwitch(activateWindowSwitchName)) { MaterialEditor::MaterialEditorWindowRequestBus::Broadcast( &MaterialEditor::MaterialEditorWindowRequestBus::Handler::ActivateWindow); } const AZStd::string timeoputSwitchName = "timeout"; if (commandLine.HasSwitch(timeoputSwitchName)) { const AZStd::string& timeoutValue = commandLine.GetSwitchValue(timeoputSwitchName, 0); const uint32_t timeoutInMs = atoi(timeoutValue.c_str()); AZ_Printf("MaterialEditor", "Timeout scheduled, shutting down in %u ms", timeoutInMs); QTimer::singleShot(timeoutInMs, [this] { AZ_Printf("MaterialEditor", "Timeout reached, shutting down"); ExitMainLoop(); }); } // Process command line options for running one or more python scripts on startup const AZStd::string runPythonScriptSwitchName = "runpython"; size_t runPythonScriptCount = commandLine.GetNumSwitchValues(runPythonScriptSwitchName); for (size_t runPythonScriptIndex = 0; runPythonScriptIndex < runPythonScriptCount; ++runPythonScriptIndex) { const AZStd::string runPythonScriptPath = commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex); AZStd::vector runPythonArgs; AZ_Printf("MaterialEditor", "Launching script: %s", runPythonScriptPath.c_str()); AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast( &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, runPythonScriptPath, runPythonArgs); } // Process command line options for opening one or more material documents on startup size_t openDocumentCount = commandLine.GetNumMiscValues(); for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex) { const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex); AZ_Printf("MaterialEditor", "Opening document: %s", openDocumentPath.c_str()); MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath); } const AZStd::string exitAfterCommandsSwitchName = "exitaftercommands"; if (commandLine.HasSwitch(exitAfterCommandsSwitchName)) { ExitMainLoop(); } } void MaterialEditorApplication::StartInternal() { Base::StartInternal(); MaterialEditorWindowNotificationBus::Handler::BusConnect(); MaterialEditor::MaterialEditorWindowFactoryRequestBus::Broadcast( &MaterialEditor::MaterialEditorWindowFactoryRequestBus::Handler::CreateMaterialEditorWindow); 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); }); } void MaterialEditorApplication::Stop() { MaterialEditor::MaterialEditorWindowFactoryRequestBus::Broadcast( &MaterialEditor::MaterialEditorWindowFactoryRequestBus::Handler::DestroyMaterialEditorWindow); Base::Stop(); } } // namespace MaterialEditor