diff --git a/CHANGELOG.md b/CHANGELOG.md index bd7daa9a..502d165a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,30 @@ If a copy of the MPL was not distributed with this file, You can obtain one at h --> +## [2.1.0] Render View, Python Console, Performance Table, Misc Improvements and Bugfixes +* **File version number has changed. Files saved with RaCo 2.1.0 cannot be opened by previous versions.** + +### Added +* Added render view widget containing a hierarchical view of the render setup of the scene and the rendered parts of the scene graph. +* Added python script editor and interactive python console. +* Added possibility to run python scripts on save. A project-specific script to execute before saving can be configured via the `ProjectSettings` object while an additional global script can be configured via the preferences dialog. +* Added performance table widget allowing to record runtime statistics of `LogicEngine` scripts and objects. +* Added support for the new attribute naming convention of color attributes in the Blender glTF exporter. The `_COLOR_N` attributes are now imported as color attributes if no attribute using the `COLOR_N` form is present in the glTF file. +* Added support for import of `Vec3` color attributes in the glTF importer. The alpha channel will be set to `1.0` in this case. +* Made `width`, `height`, and `sampleCount` properties of `RenderBuffer` and `RenderBufferMS` objects linkable. Note that outside RamsesComposer modifying these properties via link is only allowed before the Ramses renderer is initialized. + +### Changes + * Increased the size limit of `RenderBuffer` and `RenderBufferMS` objects, and the preview size to `8192x8192` pixels. The viewport properties of cameras and the region properties of `BlitPasses` have also been changed accordingly. + * Allow exporting with Ramses warnings by default in the headless application. This behaviour can be changed with the new `-w` command line option which switches to handling Ramses warnings as errors when exporting. + +### Fixes +* Added fallback texture which prevents empty texture slots causing the rendered object to become invisible. +* Do not clear the framebuffer when zooming into the preview. The preview will continue to show the current framebuffer state when zooming even if all `RenderPasses` rendering into the framebuffer are disabled. +* Prevent long lists of `RenderPasses` or `RenderLayers` shown in the "Rendered By:" and "Added To:" sections below the `tag` property in the property browser forcing a very wide property browser. +* Set all target `MeshNodes` in the `Skin` object when importing skin objects with multiple target nodes from gltf files. +* If the preview setup fails the preview will now enter an error state indicated by an `ERROR` status displayed at the bottom. The project can still be modified, saved, or exported in this state. + + ## [2.0.0] Switch to Ramses 28, Abstract Scene View, Misc UI Iprovements and Bugfixes * **This is a major version upgrade for both RamsesComposer and Ramses/LogicEngine containing changes that can break existing scenes.** * **File version number has changed. Files saved with RaCo 2.0.0 cannot be opened by previous versions.** diff --git a/CMakeLists.txt b/CMakeLists.txt index 791866fb..35e953cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,12 +11,17 @@ cmake_minimum_required(VERSION 3.19) SET(CMAKE_CONFIGURATION_TYPES "Debug;RelWithDebInfo") -project(RaCoOS VERSION 2.0.0) +project(RaCoOS VERSION 2.1.0) SET(RACO_RELEASE_DIRECTORY ${CMAKE_BINARY_DIR}/release) SET(HEADLESS_RELEASE_DIRECTORY ${CMAKE_BINARY_DIR}/release_headless) +# Fix compiler error on msvc. Details: https://github.com/microsoft/cpprestsdk/issues/1768 +if(WIN32) + add_compile_definitions(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING) +endif() + # The build and deployment process for Python works differently for Linux and Windows. # Windows: # * RaCo builds and runs without Python being installed. diff --git a/EditorApp/main.cpp b/EditorApp/main.cpp index 01a3bc11..32fd1e50 100644 --- a/EditorApp/main.cpp +++ b/EditorApp/main.cpp @@ -236,29 +236,34 @@ int main(int argc, char* argv[]) { } if (app) { + std::vector pos_argv_s; + pos_argv_s.emplace_back(pythonScriptPath.toStdString()); + for (auto arg : pythonArguments) { + pos_argv_s.emplace_back(arg); + } + std::vector wPythonSearchPaths; for (auto& path : pythonSearchPaths) { wPythonSearchPaths.emplace_back(path.toStdWString()); } - MainWindow w{app.get(), &rendererBackend, wPythonSearchPaths}; + MainWindow w{app.get(), &rendererBackend}; if (!objectToFocusId.isEmpty()) { w.Q_EMIT focusRequestedForTreeDock(objectToFocusId, ""); } + bool isInterpreterInitialized = python_api::initializeInterpreter(app.get(), QCoreApplication::applicationFilePath().toStdWString(), wPythonSearchPaths, pos_argv_s); if (!pythonScriptPath.isEmpty()) { - auto pythonScriptPathStr = pythonScriptPath.toStdString(); - std::vector pos_argv_cp; - pos_argv_cp.emplace_back(pythonScriptPathStr.c_str()); - for (auto& s : pythonArguments) { - pos_argv_cp.emplace_back(s.c_str()); - } + if (isInterpreterInitialized) { + const auto currentRunStatus = python_api::runPythonScriptFromFile(pythonScriptPath.toStdString()); - auto currentRunStatus = python_api::runPythonScript(app.get(), QCoreApplication::applicationFilePath().toStdWString(), pythonScriptPath.toStdString(), wPythonSearchPaths, pos_argv_cp); - LOG_INFO(log_system::PYTHON, currentRunStatus.stdOutBuffer); + LOG_INFO(raco::log_system::PYTHON, currentRunStatus.stdOutBuffer); - if (!currentRunStatus.stdErrBuffer.empty()) { - LOG_ERROR(log_system::PYTHON, currentRunStatus.stdErrBuffer); + if (!currentRunStatus.stdErrBuffer.empty()) { + LOG_ERROR(log_system::PYTHON, currentRunStatus.stdErrBuffer); + } + } else { + LOG_ERROR(log_system::PYTHON, "Python interpreter initialization failed."); } } diff --git a/EditorApp/mainwindow.cpp b/EditorApp/mainwindow.cpp index 4e5db100..b9251775 100644 --- a/EditorApp/mainwindow.cpp +++ b/EditorApp/mainwindow.cpp @@ -18,7 +18,9 @@ #include "common_widgets/ErrorView.h" #include "common_widgets/ExportDialog.h" #include "common_widgets/LogView.h" +#include "common_widgets/PythonOutputDialog.h" #include "common_widgets/MeshAssetImportDialog.h" +#include "common_widgets/PerformanceTableView.h" #include "common_widgets/PreferencesView.h" #include "common_widgets/RunScriptDialog.h" #include "common_widgets/TracePlayerWidget.h" @@ -26,19 +28,20 @@ #include "components/RaCoPreferences.h" #include "core/BasicTypes.h" #include "core/EditorObject.h" -#include "core/Handles.h" #include "core/PathManager.h" #include "core/Project.h" #include "core/ProjectMigration.h" #include "data_storage/Value.h" +#include "python_api/PythonAPI.h" #include "gui_python_api/GUIPythonAPI.h" #include "log_system/log.h" #include "object_tree_view/ObjectTreeDock.h" #include "object_tree_view/ObjectTreeView.h" #include "object_tree_view_model/ObjectTreeViewPrefabModel.h" +#include "object_tree_view_model/ObjectTreeViewRenderViewModel.h" #include "object_tree_view_model/ObjectTreeViewResourceModel.h" +#include "object_tree_view_model/ObjectTreeViewSceneGraphModel.h" #include "object_tree_view_model/ObjectTreeViewExternalProjectModel.h" -#include "property_browser/PropertyBrowserItem.h" #include "property_browser/PropertyBrowserModel.h" #include "ramses_adaptor/AbstractSceneAdaptor.h" @@ -51,6 +54,7 @@ #include "user_types/AnchorPoint.h" #include "user_types/Animation.h" #include "user_types/AnimationChannel.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/BlitPass.h" #include "user_types/CubeMap.h" #include "user_types/LuaInterface.h" @@ -77,14 +81,12 @@ #include "DockAreaWidget.h" #include "ads_globals.h" -#include "components/RaCoNameConstants.h" -#include "python_api/PythonAPI.h" -#include "utils/ZipUtils.h" #include #include #include #include +#include #include #include #include @@ -145,14 +147,14 @@ ads::CDockAreaWidget* MainWindow::createAndAddPreview(const char* dockObjName) { previewWidget->saveScreenshot(); }); - raco::gui_python_api::setupPreviewWindow(previewWidget); + gui_python_api::setupPreviewWindow(previewWidget); auto* dock = createDockWidget(MainWindow::DockWidgetTypes::RAMSES_PREVIEW, this); dock->setObjectName(dockObjName); dock->setWidget(previewWidget); QObject::connect(dock, &ads::CDockWidget::closed, [this]() { ui->actionNewPreview->setEnabled(true); - raco::gui_python_api::setupPreviewWindow(nullptr); + gui_python_api::setupPreviewWindow(nullptr); }); ui->actionNewPreview->setEnabled(false); return dockManager_->addDockWidget(ads::CenterDockWidgetArea, dock); @@ -165,7 +167,6 @@ ads::CDockAreaWidget* MainWindow::createAndAddAbstractSceneView(const char* dock QObject::connect(widget, &ramses_widgets::AbstractViewMainWindow::selectionRequested, this, &MainWindow::focusToSelection); QObject::connect(&treeDockManager_, &object_tree::view::ObjectTreeDockManager::newObjectTreeItemsSelected, widget, &ramses_widgets::AbstractViewMainWindow::onSelectionChanged); - QObject::connect(&treeDockManager_, &object_tree::view::ObjectTreeDockManager::selectionCleared, widget, &ramses_widgets::AbstractViewMainWindow::onSelectionCleared); auto* dock = createDockWidget(MainWindow::DockWidgetTypes::ABSTRACT_SCENE_VIEW, this); dock->setObjectName(dockObjName); @@ -183,8 +184,7 @@ ads::CDockAreaWidget* MainWindow::createAndAddPropertyBrowser(const char* dockOb QObject::connect(propertyBrowser->model(), &property_browser::PropertyBrowserModel::selectionRequested, this, &MainWindow::focusToSelection); QObject::connect(&treeDockManager_, &object_tree::view::ObjectTreeDockManager::newObjectTreeItemsSelected, propertyBrowser, &property_browser::PropertyBrowserWidget::setObjects); - QObject::connect(&treeDockManager_, &object_tree::view::ObjectTreeDockManager::selectionCleared, propertyBrowser, &property_browser::PropertyBrowserWidget::clear); - + auto* dockWidget = createDockWidget(MainWindow::DockWidgetTypes::PROPERTY_BROWSER, this); dockWidget->setWidget(propertyBrowser); dockWidget->setObjectName(dockObjName); @@ -206,25 +206,6 @@ ads::CDockAreaWidget* MainWindow::createAndAddObjectTree(const char* title, cons QObject::connect(dockModel, &object_tree::model::ObjectTreeViewDefaultModel::meshImportFailed, this, &MainWindow::showMeshImportErrorMessage); dockModel->buildObjectTree(); auto newTreeView = new object_tree::view::ObjectTreeView(title, dockModel, sortFilterModel); - if (sortFilterModel && sortFilterModel->sortingEnabled()) { - newTreeView->sortByColumn( - title == MainWindow::DockWidgetTypes::RESOURCES - ? object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_NAME - : object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_TYPE, - Qt::SortOrder::AscendingOrder); - } - - // Enable Visibility column only for specific tree views. - if (title == MainWindow::DockWidgetTypes::SCENE_GRAPH) { - newTreeView->resizeColumnToContents(object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_PREVIEW_VISIBILITY); - newTreeView->resizeColumnToContents(object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY); - } else if (title == MainWindow::DockWidgetTypes::PREFABS) { - newTreeView->resizeColumnToContents(object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_PREVIEW_VISIBILITY); - newTreeView->setColumnHidden(object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY, true); - } else { - newTreeView->setColumnHidden(object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_PREVIEW_VISIBILITY, true); - newTreeView->setColumnHidden(object_tree::model::ObjectTreeViewDefaultModel::COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY, true); - } dockObjectView->setTreeView(newTreeView); treeDockManager_.addTreeDock(dockObjectView); @@ -240,88 +221,69 @@ ads::CDockAreaWidget* MainWindow::createAndAddProjectBrowser(const char* dockObj } ads::CDockAreaWidget* MainWindow::createAndAddResourceTree(const char* dockObjName, ads::CDockAreaWidget* dockArea) { - using namespace raco::user_types; - - static const std::vector allowedCreateableUserTypes{ - AnchorPoint::typeDescription.typeName, - AnimationChannel::typeDescription.typeName, - BlitPass::typeDescription.typeName, - CubeMap::typeDescription.typeName, - LuaScriptModule::typeDescription.typeName, - Material::typeDescription.typeName, - Mesh::typeDescription.typeName, - Texture::typeDescription.typeName, - TextureExternal::typeDescription.typeName, - Timer::typeDescription.typeName, - RenderBuffer::typeDescription.typeName, - RenderBufferMS::typeDescription.typeName, - RenderTarget::typeDescription.typeName, - RenderTargetMS::typeDescription.typeName, - RenderLayer::typeDescription.typeName, - RenderPass::typeDescription.typeName}; - - auto* model = new object_tree::model::ObjectTreeViewResourceModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects(), allowedCreateableUserTypes); - model->setAcceptableFileExtensions(QStringList{"gltf", "glb", "ctm", "png", "vert", "frag", "geom", "def", "glsl", "lua"}); - model->setAcceptLuaModules(true); + auto* model = new object_tree::model::ObjectTreeViewResourceModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects()); return createAndAddObjectTree( MainWindow::DockWidgetTypes::RESOURCES, dockObjName, model, new object_tree::model::ObjectTreeViewResourceSortFilterProxyModel(this), ads::BottomDockWidgetArea, dockArea); } ads::CDockAreaWidget* MainWindow::createAndAddPrefabTree(const char* dockObjName, ads::CDockAreaWidget* dockArea) { - using namespace raco::user_types; - - static const std::vector allowedCreateableUserTypes{ - Prefab::typeDescription.typeName}; - - auto* model = new object_tree::model::ObjectTreeViewPrefabModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects(), allowedCreateableUserTypes); - + auto* model = new object_tree::model::ObjectTreeViewPrefabModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects()); return createAndAddObjectTree( MainWindow::DockWidgetTypes::PREFABS, dockObjName, model, new object_tree::model::ObjectTreeViewTopLevelSortFilterProxyModel(this), ads::BottomDockWidgetArea, dockArea); } ads::CDockAreaWidget* MainWindow::createAndAddSceneGraphTree(const char* dockObjName) { - using namespace raco::user_types; - - static const std::vector allowedCreateableUserTypes{ - Node::typeDescription.typeName, - MeshNode::typeDescription.typeName, - PrefabInstance::typeDescription.typeName, - OrthographicCamera::typeDescription.typeName, - PerspectiveCamera::typeDescription.typeName, - Animation::typeDescription.typeName, - LuaScript::typeDescription.typeName, - LuaInterface::typeDescription.typeName, - Skin::typeDescription.typeName}; - - auto* model = new object_tree::model::ObjectTreeViewDefaultModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects(), allowedCreateableUserTypes); - model->setAcceptableFileExtensions(QStringList{"lua", "gltf", "glb"}); - model->setAcceptLuaScripts(true); - model->setAcceptLuaInterfaces(true); - model->setDropGltfOpensAssetImportDialog(true); + auto* model = new object_tree::model::ObjectTreeViewSceneGraphModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects()); return createAndAddObjectTree(MainWindow::DockWidgetTypes::SCENE_GRAPH, dockObjName, model, new object_tree::model::ObjectTreeViewDefaultSortFilterProxyModel(this, false), ads::LeftDockWidgetArea, nullptr); } +ads::CDockAreaWidget* MainWindow::createAndAddRenderView(const char* dockObjName, ads::CDockAreaWidget* dockArea) { + auto* model = new object_tree::model::ObjectTreeViewRenderViewModel(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), racoApplication_->externalProjects()); + + return createAndAddObjectTree( + MainWindow::DockWidgetTypes::RENDER_VIEW, dockObjName, model, new object_tree::model::ObjectTreeViewDefaultSortFilterProxyModel(this, true), + ads::BottomDockWidgetArea, dockArea); +} + + ads::CDockAreaWidget* MainWindow::createAndAddUndoView(const char* dockObjName, ads::CDockAreaWidget* dockArea) { auto* dock = createDockWidget(MainWindow::DockWidgetTypes::UNDO_STACK, this); - dock->setWidget(new raco::common_widgets::UndoView(racoApplication_->activeRaCoProject().undoStack(), racoApplication_->dataChangeDispatcher(), this)); + dock->setWidget(new common_widgets::UndoView(racoApplication_->activeRaCoProject().undoStack(), racoApplication_->dataChangeDispatcher(), this)); dock->setObjectName(dockObjName); return dockManager_->addDockWidget(ads::BottomDockWidgetArea, dock, dockArea); } ads::CDockAreaWidget* MainWindow::createAndAddErrorView(const char* dockObjName, ads::CDockAreaWidget* dockArea) { auto* errorView = new raco::common_widgets::ErrorView(racoApplication_->activeRaCoProject().commandInterface(), racoApplication_->dataChangeDispatcher(), false, logViewModel_); - QObject::connect(errorView, &raco::common_widgets::ErrorView::objectSelectionRequested, &treeDockManager_, &object_tree::view::ObjectTreeDockManager::selectObjectAcrossAllTreeDocks); + QObject::connect(errorView, &raco::common_widgets::ErrorView::objectSelectionRequested, &treeDockManager_, [this](auto objectID) { + if (auto object = racoApplication_->activeRaCoProject().project()->getInstanceByID(objectID.toStdString())) { + treeDockManager_.selectObjectAndPropertyAcrossAllTreeDocks(object, {}); + } + }); auto* dock = createDockWidget(MainWindow::DockWidgetTypes::ERROR_VIEW, this); dock->setWidget(errorView); dock->setObjectName(dockObjName); return dockManager_->addDockWidget(ads::BottomDockWidgetArea, dock, dockArea); } +ads::CDockAreaWidget* MainWindow::createAndAddPerformanceTable(const char* dockObjName, ads::CDockAreaWidget* dockArea) { + auto performanceView = new common_widgets::PerformanceTableView(racoApplication_, racoApplication_->dataChangeDispatcher(), this); + QObject::connect(performanceView, &raco::common_widgets::PerformanceTableView::objectSelectionRequested, &treeDockManager_, [this](auto objectID) { + if (auto object = racoApplication_->activeRaCoProject().project()->getInstanceByID(objectID.toStdString())) { + treeDockManager_.selectObjectAndPropertyAcrossAllTreeDocks(object, {}); + } + }); + auto* dock = createDockWidget(MainWindow::DockWidgetTypes::PERFORMANCE_TABLE, this); + dock->setWidget(performanceView); + dock->setObjectName(dockObjName); + return dockManager_->addDockWidget(ads::BottomDockWidgetArea, dock, dockArea); +} + ads::CDockAreaWidget* MainWindow::createAndAddLogView(const char* dockObjName, ads::CDockAreaWidget* dockArea) { - auto* logView = new raco::common_widgets::LogView(logViewModel_); + auto* logView = new common_widgets::LogView(logViewModel_); auto* dock = createDockWidget(MainWindow::DockWidgetTypes::LOG_VIEW, this); dock->setWidget(logView); dock->setObjectName(dockObjName); @@ -329,29 +291,13 @@ ads::CDockAreaWidget* MainWindow::createAndAddLogView(const char* dockObjName, a } ads::CDockAreaWidget* MainWindow::createAndAddPythonRunner(const char* dockObjName, ads::CDockAreaWidget* dockArea) { - auto* pythonRunner = new raco::common_widgets::RunScriptDialog(pythonScriptCache_, pythonScriptArgumentCache_, this); + + + auto* pythonRunner = new common_widgets::RunScriptDialog(pythonScriptCache_, pythonScriptArgumentCache_, this); auto* dock = createDockWidget(MainWindow::DockWidgetTypes::PYTHON_RUNNER, this); dock->setWidget(pythonRunner); dock->setObjectName(dockObjName); - QObject::connect(pythonRunner, &raco::common_widgets::RunScriptDialog::pythonScriptRunRequested, [this, dock, pythonRunner](const QString& scriptPath, const QStringList& arguments) { - pythonRunner->setScriptIsRunning(true); - pythonRunner->repaint(); - std::vector pos_argv_s; - pos_argv_s.emplace_back(scriptPath.toStdString()); - for (auto arg : arguments) { - pos_argv_s.emplace_back(arg.toStdString()); - } - std::vector pos_argv_cp; - for (auto& s : pos_argv_s) { - pos_argv_cp.emplace_back(s.c_str()); - } - - auto currentRunStatus = python_api::runPythonScript(racoApplication_, QCoreApplication::applicationFilePath().toStdWString(), scriptPath.toStdString(), pythonSearchPaths(), pos_argv_cp); - pythonRunner->addPythonOutput(currentRunStatus.stdOutBuffer, currentRunStatus.stdErrBuffer); - pythonRunner->setScriptIsRunning(false); - }); - return dockManager_->addDockWidget(ads::RightDockWidgetArea, dock, dockArea); } @@ -363,7 +309,7 @@ ads::CDockAreaWidget* MainWindow::createAndAddTracePlayer() { auto* newTraceplayerDock{createDockWidget(MainWindow::DockWidgetTypes::TRACE_PLAYER, this)}; newTraceplayerDock->setMinimumSizeHintMode(ads::CDockWidget::eMinimumSizeHintMode::MinimumSizeHintFromContent); - auto* traceplayerWidget{new raco::common_widgets::TracePlayerWidget(newTraceplayerDock->objectName(), &racoApplication_->activeRaCoProject().tracePlayer())}; + auto* traceplayerWidget{new common_widgets::TracePlayerWidget(newTraceplayerDock->objectName(), &racoApplication_->activeRaCoProject().tracePlayer())}; newTraceplayerDock->setWidget(traceplayerWidget, ads::CDockWidget::ForceNoScrollArea); ads::CDockWidget* existingPreviewDock{nullptr}; @@ -409,9 +355,39 @@ void MainWindow::createInitialWidgets() { createAndAddPropertyBrowser("defaultPropertyBrowser"); } -MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, ramses_widgets::RendererBackend* rendererBackend, const std::vector& pythonSearchPaths, QWidget* parent) +void MainWindow::runPythonOnSaveScript(const std::string& scriptPath, const std::string& title) { + utils::u8path utilPath = utils::u8path(scriptPath); + if (utilPath.is_relative()) { + utilPath = utilPath.normalizedAbsolutePath(racoApplication_->activeProjectFolder()); + } + + if (!scriptPath.empty()) { + const auto runStatus = python_api::runPythonScriptFromFile(utilPath.string()); + + if (!runStatus.stdOutBuffer.empty() || !runStatus.stdErrBuffer.empty()) { + const auto msgBox = new common_widgets::PythonOutputDialog( + QString::fromStdString(title), + QString::fromStdString(runStatus.stdOutBuffer), + QString::fromStdString(runStatus.stdErrBuffer)); + msgBox->exec(); + } + } +} + +void MainWindow::runPythonOnSaveScripts() { + // Global + const auto globalPythonOnSaveScript = components::RaCoPreferences::instance().globalPythonOnSaveScript; + runPythonOnSaveScript(globalPythonOnSaveScript.toStdString(), "Global OnSave Script"); + + // Project + if (components::RaCoPreferences::instance().enableProjectPythonScript) { + const auto projectPythonOnSaveScript = racoApplication_->activeRaCoProject().pythonOnSaveScriptPath(); + runPythonOnSaveScript(projectPythonOnSaveScript, "Project OnSave Script"); + } +} + +MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, ramses_widgets::RendererBackend* rendererBackend, QWidget* parent) : QMainWindow(parent), - pythonSearchPaths_(pythonSearchPaths), rendererBackend_(rendererBackend), racoApplication_(racoApplication) { // Setup the UI from the QtCreator file mainwindow.ui @@ -428,7 +404,7 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, rams dockManager_ = createDockManager(); setWindowIcon(QIcon(":applicationLogo")); - logViewModel_ = new raco::common_widgets::LogViewModel(this); + logViewModel_ = new common_widgets::LogViewModel(this); // Shortcuts { @@ -489,7 +465,7 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, rams openProject(); }); QObject::connect(ui->actionExport, &QAction::triggered, this, [this]() { - auto dialog = new raco::common_widgets::ExportDialog(racoApplication_, logViewModel_, this); + auto dialog = new common_widgets::ExportDialog(racoApplication_, logViewModel_, this); dialog->exec(); }); QObject::connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::close); @@ -497,7 +473,7 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, rams new EditMenu(racoApplication_, &treeDockManager_, ui->menuEdit); QObject::connect(ui->actionPreferences, &QAction::triggered, [this]() { - auto dialog = new raco::common_widgets::PreferencesView(this); + auto dialog = new common_widgets::PreferencesView(racoApplication_, this); dialog->resize(500, 500); dialog->exec(); racoApplication_->setNewFileFeatureLevel(components::RaCoPreferences::instance().featureLevel); @@ -512,10 +488,12 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, rams QObject::connect(ui->actionNewSceneGraphTree, &QAction::triggered, [this]() { createAndAddSceneGraphTree(EditorObject::normalizedObjectID("").c_str()); }); QObject::connect(ui->actionNewResourcesTree, &QAction::triggered, [this]() { createAndAddResourceTree(EditorObject::normalizedObjectID("").c_str(), nullptr); }); QObject::connect(ui->actionNewPrefabTree, &QAction::triggered, [this]() { createAndAddPrefabTree(EditorObject::normalizedObjectID("").c_str(), nullptr); }); + QObject::connect(ui->actionNewRenderView, &QAction::triggered, [this]() { createAndAddRenderView(EditorObject::normalizedObjectID("").c_str(), nullptr); }); QObject::connect(ui->actionNewUndoView, &QAction::triggered, [this]() { createAndAddUndoView(EditorObject::normalizedObjectID("").c_str()); }); QObject::connect(ui->actionNewErrorView, &QAction::triggered, [this]() { createAndAddErrorView( EditorObject::normalizedObjectID("").c_str()); }); QObject::connect(ui->actionNewLogView, &QAction::triggered, [this]() { createAndAddLogView(EditorObject::normalizedObjectID("").c_str()); }); QObject::connect(ui->actionNewPythonRunner, &QAction::triggered, [this]() { createAndAddPythonRunner(EditorObject::normalizedObjectID("").c_str()); }); + QObject::connect(ui->actionNewPerformanceTable, &QAction::triggered, [this]() { createAndAddPerformanceTable(EditorObject::normalizedObjectID("").c_str(), nullptr); }); QObject::connect(ui->actionRestoreDefaultLayout, &QAction::triggered, [this]() { resetDockManager(); createInitialWidgets(); @@ -555,7 +533,11 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, rams about.exec(); }); - QObject::connect(this, &MainWindow::focusRequestedForTreeDock, &treeDockManager_, &object_tree::view::ObjectTreeDockManager::selectObjectAndPropertyAcrossAllTreeDocks); + QObject::connect(this, &MainWindow::focusRequestedForTreeDock, &treeDockManager_, [this](auto objectID, auto propertyPath) { + if (auto object = racoApplication_->activeRaCoProject().project()->getInstanceByID(objectID.toStdString())) { + treeDockManager_.selectObjectAndPropertyAcrossAllTreeDocks(object, propertyPath); + } + }); setAcceptDrops(true); @@ -567,8 +549,8 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, rams // Setup updateApplicationTitle(); updateSavedLayoutMenu(); - - raco::gui_python_api::setupObjectTree(&treeDockManager_); + + gui_python_api::setupObjectTree(&treeDockManager_); // Will we support Mac? setUnifiedTitleAndToolBarOnMac(true); @@ -591,10 +573,11 @@ void MainWindow::timerEvent(QTimerEvent* event) { auto startLoop = std::chrono::high_resolution_clock::now(); racoApplication_->doOneLoop(); - const auto& viewport = racoApplication_->activeRaCoProject().project()->settings()->viewport_; + auto& viewport = racoApplication_->activeRaCoProject().project()->settings()->viewport_; const auto& backgroundColor = *racoApplication_->activeRaCoProject().project()->settings()->backgroundColor_; - Q_EMIT viewportChanged({*viewport->i1_, *viewport->i2_}); + int range_max = *viewport->i1_.staticQuery>().max_; + Q_EMIT viewportChanged(QSize(*viewport->i1_, *viewport->i2_).boundedTo({range_max, range_max}).expandedTo({1, 1})); for (auto preview : findChildren()) { preview->commit(racoApplication_->rendererDirty_); @@ -602,7 +585,6 @@ void MainWindow::timerEvent(QTimerEvent* event) { } racoApplication_->rendererDirty_ = false; auto logicEngineExecutionEnd = std::chrono::high_resolution_clock::now(); - timingsModel_.addLogicEngineTotalExecutionDuration(std::chrono::duration_cast(logicEngineExecutionEnd - startLoop).count()); racoApplication_->sceneBackendImpl()->flush(); if (racoApplication_->abstractScene()) { racoApplication_->abstractScene()->scene()->flush(); @@ -735,7 +717,7 @@ void MainWindow::openProject(const QString& file, int featureLevel, bool generat } } - } catch (const raco::application::FutureFileVersion& error) { + } catch (const application::FutureFileVersion& error) { racoApplication_->switchActiveRaCoProject({}, {}); QMessageBox::warning(this, "File Load Error", fmt::format("Project file was created with newer version of {app_name}. Please upgrade.\n\nExpected File Version: {expected_file_version}\nFound File Version: {file_version}", fmt::arg("app_name", "Ramses Composer"), fmt::arg("expected_file_version", serialization::RAMSES_PROJECT_FILE_VERSION), fmt::arg("file_version", error.fileVersion_)).c_str(), QMessageBox::Close); } catch (const ExtrefError& error) { @@ -837,6 +819,8 @@ bool MainWindow::saveActiveProject() { if (isUpgradePrevented()) { return false; } + + runPythonOnSaveScripts(); std::string errorMsg; if (racoApplication_->activeRaCoProject().save(errorMsg)) { @@ -860,7 +844,7 @@ bool MainWindow::isUpgradePrevented() { constexpr auto currentFileVersion = serialization::RAMSES_PROJECT_FILE_VERSION; try { - auto previousFileVersion = serialization::deserializeFileVersion(raco::application::RaCoProject::loadJsonDocument(filename)); + auto previousFileVersion = serialization::deserializeFileVersion(application::RaCoProject::loadJsonDocument(filename)); if (currentFileVersion > previousFileVersion) { const auto answer = QMessageBox::warning(this, "Save File Warning", fmt::format("The project with the file version {} will be overwritten with the file version {}. Are you sure you want to save it with the new file version", previousFileVersion, currentFileVersion).c_str(), QMessageBox::Save, QMessageBox::Cancel); if (answer == QMessageBox::Cancel) { @@ -884,6 +868,9 @@ bool MainWindow::saveAsActiveProject(bool newID) { } if (!newPath.endsWith(".rca")) newPath += ".rca"; std::string errorMsg; + + runPythonOnSaveScripts(); + if (newID) { if (racoApplication_->activeRaCoProject().saveAs(newPath, errorMsg, setProjectName)) { openProject(QString::fromStdString(racoApplication_->activeProjectPath()), -1, true); @@ -948,10 +935,6 @@ void MainWindow::updateUpgradeMenu() { } } -const std::vector& MainWindow::pythonSearchPaths() const { - return pythonSearchPaths_; -} - bool MainWindow::resolveDirtiness() { bool continueWithAction{true}; if (racoApplication_->activeRaCoProject().dirty()) { @@ -1014,6 +997,8 @@ void MainWindow::regenerateLayoutDocks(const RaCoDockManager::LayoutDocks& docks createAndAddProjectSettings(dockNameCString); } else if (savedDockType == DockWidgetTypes::PROPERTY_BROWSER) { createAndAddPropertyBrowser(dockNameCString); + } else if (savedDockType == DockWidgetTypes::PERFORMANCE_TABLE) { + createAndAddPerformanceTable(dockNameCString, nullptr); } else if (savedDockType == DockWidgetTypes::RAMSES_PREVIEW) { if (!hasPreview) { createAndAddPreview(dockNameCString); @@ -1030,6 +1015,8 @@ void MainWindow::regenerateLayoutDocks(const RaCoDockManager::LayoutDocks& docks createAndAddResourceTree(dockNameCString, nullptr); } else if (savedDockType == DockWidgetTypes::SCENE_GRAPH) { createAndAddSceneGraphTree(dockNameCString); + } else if (savedDockType == DockWidgetTypes::RENDER_VIEW) { + createAndAddRenderView(dockNameCString, nullptr); } else if (savedDockType == DockWidgetTypes::UNDO_STACK) { createAndAddUndoView(dockNameCString); } else if (savedDockType == DockWidgetTypes::ERROR_VIEW) { @@ -1061,7 +1048,7 @@ void MainWindow::updateActiveProjectConnection() { if (!racoApplication_->activeProjectPath().empty()) { activeProjectFileConnection_ = QObject::connect( &racoApplication_->activeRaCoProject(), - &raco::application::RaCoProject::activeProjectFileChanged, + &application::RaCoProject::activeProjectFileChanged, this, &MainWindow::activeProjectFileChanged, Qt::QueuedConnection); @@ -1070,7 +1057,7 @@ void MainWindow::updateActiveProjectConnection() { void MainWindow::updateProjectSavedConnection() { QObject::disconnect(projectSavedConnection_); - projectSavedConnection_ = QObject::connect(&racoApplication_->activeRaCoProject(), &raco::application::RaCoProject::projectSuccessfullySaved, [this]() { + projectSavedConnection_ = QObject::connect(&racoApplication_->activeRaCoProject(), &application::RaCoProject::projectSuccessfullySaved, [this]() { recentFileMenu_->addRecentFile(racoApplication_->activeProjectPath().c_str()); updateApplicationTitle(); }); diff --git a/EditorApp/mainwindow.h b/EditorApp/mainwindow.h index af5a28bc..5d35276e 100644 --- a/EditorApp/mainwindow.h +++ b/EditorApp/mainwindow.h @@ -10,7 +10,6 @@ #pragma once #include "RaCoDockManager.h" -#include "common_widgets/TimingsWidget.h" #include "common_widgets/log_model/LogViewModel.h" #include "object_tree_view/ObjectTreeDockManager.h" #include "object_tree_view_model/ObjectTreeViewDefaultModel.h" @@ -49,6 +48,8 @@ class MainWindow : public QMainWindow { static inline const char* ABSTRACT_SCENE_VIEW{"Abstract Scene View"}; static inline const char* RESOURCES{"Resources"}; static inline const char* SCENE_GRAPH{"Scene Graph"}; + static inline const char* RENDER_VIEW{"Render View"}; + static inline const char* PERFORMANCE_TABLE{"Performance Table"}; static inline const char* UNDO_STACK{"Undo Stack"}; static inline const char* ERROR_VIEW{"Error View"}; static inline const char* LOG_VIEW{"Log View"}; @@ -59,7 +60,6 @@ class MainWindow : public QMainWindow { explicit MainWindow( raco::application::RaCoApplication* racoApplication, raco::ramses_widgets::RendererBackend* rendererBackend, - const std::vector& pythonSearchPaths, QWidget* parent = nullptr); ~MainWindow(); @@ -67,8 +67,6 @@ class MainWindow : public QMainWindow { void updateSavedLayoutMenu(); void updateUpgradeMenu(); - const std::vector& pythonSearchPaths() const; - public Q_SLOTS: void showMeshImportErrorMessage(const std::string& filePath, const std::string& meshError); void focusToSelection(const QString& objectID, const QString& property); @@ -115,10 +113,12 @@ protected Q_SLOTS: ads::CDockAreaWidget* createAndAddAbstractSceneView(const char* dockObjName); ads::CDockAreaWidget* createAndAddPropertyBrowser(const char* dockObjName); ads::CDockAreaWidget* createAndAddSceneGraphTree(const char* dockObjName); + ads::CDockAreaWidget* createAndAddPerformanceTable(const char* dockObjName, ads::CDockAreaWidget* dockArea); void createAndAddProjectSettings(const char* dockObjName); ads::CDockAreaWidget* createAndAddPrefabTree(const char* dockObjName, ads::CDockAreaWidget* dockArea); ads::CDockAreaWidget* createAndAddResourceTree(const char* dockObjName, ads::CDockAreaWidget* dockArea); + ads::CDockAreaWidget* createAndAddRenderView(const char* dockObjName, ads::CDockAreaWidget* dockArea); ads::CDockAreaWidget* createAndAddUndoView(const char* dockObjName, ads::CDockAreaWidget* dockArea = nullptr); ads::CDockAreaWidget* createAndAddErrorView(const char* dockObjName, ads::CDockAreaWidget* dockArea = nullptr); ads::CDockAreaWidget* createAndAddLogView(const char* dockObjName, ads::CDockAreaWidget* dockArea = nullptr); @@ -128,17 +128,17 @@ protected Q_SLOTS: ads::CDockAreaWidget* createAndAddObjectTree(const char* title, const char* dockObjName, raco::object_tree::model::ObjectTreeViewDefaultModel* dockModel, raco::object_tree::model::ObjectTreeViewDefaultSortFilterProxyModel* sortFilterModel, ads::DockWidgetArea area, ads::CDockAreaWidget* dockArea); void createInitialWidgets(); + void runPythonOnSaveScript(const std::string& scriptPath, const std::string& title); + void runPythonOnSaveScripts(); Ui::MainWindow* ui; OpenRecentMenu* recentFileMenu_; RaCoDockManager* dockManager_; QListWidget* sceneObjectList_; - const std::vector pythonSearchPaths_; raco::ramses_widgets::RendererBackend* rendererBackend_; raco::application::RaCoApplication* racoApplication_; raco::object_tree::view::ObjectTreeDockManager treeDockManager_; - raco::common_widgets::TimingsModel timingsModel_{this}; QMetaObject::Connection activeProjectFileConnection_; QMetaObject::Connection projectSavedConnection_; raco::common_widgets::LogViewModel* logViewModel_; diff --git a/EditorApp/mainwindow.ui b/EditorApp/mainwindow.ui index 59a80ee2..17c0b073 100644 --- a/EditorApp/mainwindow.ui +++ b/EditorApp/mainwindow.ui @@ -79,11 +79,13 @@ + + @@ -190,6 +192,16 @@ New Pre&fab View + + + + New Render View + + + + + New Performance Table + diff --git a/HeadlessApp/CMakeLists.txt b/HeadlessApp/CMakeLists.txt index e3b4b89e..f95086a3 100644 --- a/HeadlessApp/CMakeLists.txt +++ b/HeadlessApp/CMakeLists.txt @@ -85,7 +85,10 @@ if(WIN32 OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") ) endif() if (NOT WIN32) - deploy_to_extra_dir(RaCoCommand "$.sh" "$") + find_program(LINUXDEPLOYQT linuxdeployqt) + if(EXISTS "${LINUXDEPLOYQT}") + deploy_to_extra_dir(RaCoCommand "$.sh" "$") + endif() endif() if(PACKAGE_TESTS) diff --git a/HeadlessApp/main.cpp b/HeadlessApp/main.cpp index e16910d1..d7933aff 100644 --- a/HeadlessApp/main.cpp +++ b/HeadlessApp/main.cpp @@ -36,8 +36,8 @@ class Worker : public QObject { Q_OBJECT public: - Worker(QObject* parent, QString& projectFile, QString& exportPath, QString& pythonScriptPath, QStringList& pythonSearchPaths, bool compressExport, QStringList positionalArguments, int featureLevel, raco::application::ELuaSavingMode luaSavingMode, ramses::RamsesFrameworkConfig ramsesConfig) - : QObject(parent), projectFile_(projectFile), exportPath_(exportPath), pythonScriptPath_(pythonScriptPath), pythonSearchPaths_(pythonSearchPaths), compressExport_(compressExport), positionalArguments_(positionalArguments), featureLevel_(featureLevel), luaSavingMode_(luaSavingMode), ramsesConfig_(ramsesConfig) { + Worker(QObject* parent, QString& projectFile, QString& exportPath, QString& pythonScriptPath, QStringList& pythonSearchPaths, bool compressExport, QStringList positionalArguments, int featureLevel, raco::application::ELuaSavingMode luaSavingMode, ramses::RamsesFrameworkConfig ramsesConfig, bool warningsAsErrors) + : QObject(parent), projectFile_(projectFile), exportPath_(exportPath), pythonScriptPath_(pythonScriptPath), pythonSearchPaths_(pythonSearchPaths), compressExport_(compressExport), positionalArguments_(positionalArguments), featureLevel_(featureLevel), luaSavingMode_(luaSavingMode), ramsesConfig_(ramsesConfig), warningsAsErrors_(warningsAsErrors) { } public Q_SLOTS: @@ -69,30 +69,34 @@ public Q_SLOTS: for (auto arg : positionalArguments_) { pos_argv_s.emplace_back(arg.toStdString()); } - std::vector pos_argv_cp; - for (auto& s : pos_argv_s) { - pos_argv_cp.emplace_back(s.c_str()); - } std::vector wPythonSearchPaths; for (auto& path : pythonSearchPaths_) { wPythonSearchPaths.emplace_back(path.toStdWString()); } - auto currentRunStatus = python_api::runPythonScript(app.get(), QCoreApplication::applicationFilePath().toStdWString(), pythonScriptPath_.toStdString(), wPythonSearchPaths, pos_argv_cp); - exitCode_ = currentRunStatus.exitCode; - LOG_INFO(log_system::PYTHON, currentRunStatus.stdOutBuffer); + if (python_api::initializeInterpreter(app.get(), QCoreApplication::applicationFilePath().toStdWString(), wPythonSearchPaths, pos_argv_s)) { + const auto currentRunStatus = python_api::runPythonScriptFromFile(pythonScriptPath_.toStdString()); + exitCode_ = currentRunStatus.exitCode; + + LOG_INFO(raco::log_system::PYTHON, currentRunStatus.stdOutBuffer); - if (!currentRunStatus.stdErrBuffer.empty()) { - LOG_ERROR(log_system::PYTHON, currentRunStatus.stdErrBuffer); + if (!currentRunStatus.stdErrBuffer.empty()) { + LOG_ERROR(log_system::PYTHON, currentRunStatus.stdErrBuffer); + } + } else { + LOG_ERROR(log_system::PYTHON, "Python interpreter initialization failed."); + exitCode_ = 1; } } else if (!exportPath_.isEmpty()) { QString ramsesPath = exportPath_ + "." + raco::names::FILE_EXTENSION_RAMSES_EXPORT; std::string error; - if (!app->exportProject(ramsesPath.toStdString(), compressExport_, error, false, luaSavingMode_)) { - LOG_ERROR(log_system::COMMON, "error exporting to {}\n{}", ramsesPath.toStdString(), error.c_str()); + if (!app->exportProject(ramsesPath.toStdString(), compressExport_, error, false, luaSavingMode_, warningsAsErrors_)) { + LOG_ERROR(log_system::COMMON, "Error exporting to {}\n{}", ramsesPath.toStdString(), error.c_str()); exitCode_ = 1; + } else if (!error.empty()) { + LOG_WARNING(log_system::COMMON, "Warning exporting to {}\n{}", ramsesPath.toStdString(), error.c_str()); } } } @@ -114,6 +118,7 @@ public Q_SLOTS: raco::application::ELuaSavingMode luaSavingMode_; int exitCode_ = 0; ramses::RamsesFrameworkConfig ramsesConfig_; + bool warningsAsErrors_ = false; }; #include "main.moc" @@ -137,6 +142,10 @@ int main(int argc, char* argv[]) { << "export", "Export Ramses scene and logic to path. File extensions are added automatically (ignored if '-r' is used).", "export-path"); + QCommandLineOption warningsAsErrorsAction( + QStringList() << "w" + << "warnaserror", + "Export will handle Ramses warnings as errors and fail export."); QCommandLineOption compressExportAction( QStringList() << "c" << "compress", @@ -183,6 +192,7 @@ int main(int argc, char* argv[]) { parser.addOption(loadProjectAction); parser.addOption(exportProjectAction); + parser.addOption(warningsAsErrorsAction); parser.addOption(compressExportAction); parser.addOption(noDumpFileCheckOption); parser.addOption(logLevelOption); @@ -308,7 +318,7 @@ int main(int argc, char* argv[]) { } } - Worker* task = new Worker(&a, projectFile, exportPath, pythonScriptPath, pythonSearchPaths, compressExport, parser.positionalArguments(), featureLevel, luaSavingMode, ramsesConfig); + Worker* task = new Worker(&a, projectFile, exportPath, pythonScriptPath, pythonSearchPaths, compressExport, parser.positionalArguments(), featureLevel, luaSavingMode, ramsesConfig, parser.isSet(warningsAsErrorsAction)); QObject::connect(task, &Worker::finished, &QCoreApplication::exit); QTimer::singleShot(0, task, &Worker::run); diff --git a/HeadlessApp/tests/CMakeLists.txt b/HeadlessApp/tests/CMakeLists.txt index b904f1c5..6ee40231 100644 --- a/HeadlessApp/tests/CMakeLists.txt +++ b/HeadlessApp/tests/CMakeLists.txt @@ -46,3 +46,20 @@ add_racocommand_test(RaCoHeadless_export_lua_saving_mode_source_and_byte_code_su add_racocommand_test(RaCoHeadless_export_lua_saving_mode_long_option "${CMAKE_CURRENT_BINARY_DIR}" "-p" "${CMAKE_SOURCE_DIR}/resources/example_scene.rca" "-e" "lua_saving_mode_long_option_source" "--luasavingmode" "source_code") add_racocommand_test(RaCoHeadless_export_lua_saving_mode_fail "${CMAKE_CURRENT_BINARY_DIR}" "-p" "${CMAKE_SOURCE_DIR}/resources/example_scene.rca" "-e" "lua_saving_mode_fail" "-s" "invalid_setting") set_tests_properties(RaCoHeadless_export_lua_saving_mode_fail PROPERTIES WILL_FAIL True) + +add_racocommand_test(RaCoHeadless_export_raco_warn "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-warning-ramses-ok.rca" -e "export-raco-warning-ramses-ok") +add_racocommand_test(RaCoHeadless_export_raco_error "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-error-ramses-ok.rca" -e "export-raco-error-ramses-ok") +set_tests_properties(RaCoHeadless_export_raco_error PROPERTIES WILL_FAIL True) + +add_racocommand_test(RaCoHeadless_export_ramses_warn "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-ok-ramses-warning.rca" -e "export-raco-ok-ramses-warning") +add_racocommand_test(RaCoHeadless_export_ramses_error "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-ok-ramses-error.rca" -e "export-raco-ok-ramses-error") +set_tests_properties(RaCoHeadless_export_ramses_error PROPERTIES WILL_FAIL True) + +add_racocommand_test(RaCoHeadless_export_strict_raco_warn "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-warning-ramses-ok.rca" -e "export-raco-warning-ramses-ok" -w) +add_racocommand_test(RaCoHeadless_export_strict_raco_error "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-error-ramses-ok.rca" -e "export-raco-error-ramses-ok" -w) +set_tests_properties(RaCoHeadless_export_strict_raco_error PROPERTIES WILL_FAIL True) + +add_racocommand_test(RaCoHeadless_export_strict_ramses_warn "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-ok-ramses-warning.rca" -e "export-raco-ok-ramses-warning" -w) +set_tests_properties(RaCoHeadless_export_strict_ramses_warn PROPERTIES WILL_FAIL True) +add_racocommand_test(RaCoHeadless_export_strict_ramses_error "${CMAKE_CURRENT_BINARY_DIR}" -p "${CMAKE_SOURCE_DIR}/resources/export-raco-ok-ramses-error.rca" -e "export-raco-ok-ramses-error" -w) +set_tests_properties(RaCoHeadless_export_strict_ramses_error PROPERTIES WILL_FAIL True) diff --git a/PyAPITests/CMakeLists.txt b/PyAPITests/CMakeLists.txt index 438dd06d..fad65aa6 100644 --- a/PyAPITests/CMakeLists.txt +++ b/PyAPITests/CMakeLists.txt @@ -14,6 +14,8 @@ endmacro() add_python_test(pyt_general) +add_python_test(pyt_animation) + add_python_test(exit_code) set_tests_properties(PyAPI_exit_code PROPERTIES WILL_FAIL True) diff --git a/PyAPITests/pyt_animation.py b/PyAPITests/pyt_animation.py new file mode 100644 index 00000000..73353d14 --- /dev/null +++ b/PyAPITests/pyt_animation.py @@ -0,0 +1,138 @@ +# +# SPDX-License-Identifier: MPL-2.0 +# +# This file is part of Ramses Composer +# (see https://github.com/bmwcarit/ramses-composer). +# +# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +import unittest +import raco +import os + +class AnimationTests(unittest.TestCase): + def setUp(self): + raco.reset() + + def cwd(self): + return os.getcwd() + + def findObjectByName(self, name): + for object in raco.instances(): + if object.objectName.value() == name: + return object + + def findObjectByType(self, type): + for object in raco.instances(): + if object.typeName() == type: + return object + + def setup_check_animation_channel(self, name, component_type, interpolation, size, time_stamps, keyframes, tangents_in = None, tangents_out = None): + channel = raco.create("AnimationChannelRaco", name) + channel.componentType = component_type + channel.interpolationType = interpolation + channel.componentArraySize = size + if tangents_in == None: + channel.setAnimationData(time_stamps, keyframes) + else: + channel.setAnimationData(time_stamps, keyframes, tangents_in, tangents_out) + + time_stamps = channel.getAnimationTimeStamps() + data = channel.getAnimationOutputData() + + self.assertEqual(time_stamps, channel.getAnimationTimeStamps()) + self.assertEqual(keyframes, data[0]) + if tangents_in != None: + self.assertEqual(tangents_in, data[1]) + self.assertEqual(tangents_out, data[2]) + + def test_anim_float_linear(self): + self.setup_check_animation_channel( + "channel_float_linear", raco.EAnimationComponentType.Float, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [4, 5, 6]) + + def test_anim_float_cubic(self): + self.setup_check_animation_channel( + "channel_float_cubic", raco.EAnimationComponentType.Float, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [4, 5, 6], [0,0,0], [1,1,1]) + + def test_anim_vec2f_linear(self): + self.setup_check_animation_channel( + "channel_vec2f_linear", raco.EAnimationComponentType.Vec2f, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [[4, 5], [5,6], [6,7]]) + + def test_anim_vec2f_cubic(self): + self.setup_check_animation_channel( + "channel_vec2f_cubic", raco.EAnimationComponentType.Vec2f, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [[4.0,5], [5,6], [6,7]], [[0,0], [0,0], [0,0]], [[1,1], [1,1], [1,1]]) + + def test_anim_vec3f_linear(self): + self.setup_check_animation_channel( + "channel_vec3f_linear", raco.EAnimationComponentType.Vec3f, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [[4, 5, 6], [5,6,7], [6,7,8]]) + + def test_anim_vec3f_cubic(self): + self.setup_check_animation_channel( + "channel_vec3f_cubic", raco.EAnimationComponentType.Vec3f, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [[4.0,5,6], [5,6,7], [6,7,8]], [[0,0,0], [0,0,0], [0,0,0]], [[1,1,1], [1,1,1], [1,1,1]]) + + def test_anim_vec4f_linear(self): + self.setup_check_animation_channel( + "channel_vec4f_linear", raco.EAnimationComponentType.Vec4f, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]]) + + def test_anim_vec4f_cubic(self): + self.setup_check_animation_channel( + "channel_vec4f_cubic", raco.EAnimationComponentType.Vec4f, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]], [[0,0,0,0], [0,0,0,0], [0,0,0,0]], [[1,1,1,1], [1,1,1,1], [1,1,1,1]]) + + def test_anim_array_linear(self): + self.setup_check_animation_channel( + "channel_array_linear", raco.EAnimationComponentType.Array, raco.EAnimationInterpolationType.Linear, 5, + [0,0.5,1], [[4.0,5,6,7,8], [5,6,7,8,9], [6,7,8,9,10]]) + + def test_anim_array_cubic(self): + self.setup_check_animation_channel( + "channel_array_cubic", raco.EAnimationComponentType.Array, raco.EAnimationInterpolationType.CubicSpline, 5, + [0,0.5,1], [[4.0,5,6,7,8], [5,6,7,8,9], [6,7,8,9,10]], [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]], [[1,1,1,1,1], [1,1,1,1,1], [1,1,1,1,1]]) + + def test_anim_int_linear(self): + self.setup_check_animation_channel( + "channel_int_linear", raco.EAnimationComponentType.Int, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [4, 5, 6]) + + def test_anim_int_cubic(self): + self.setup_check_animation_channel( + "channel_int_cubic", raco.EAnimationComponentType.Int, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [4, 5, 6], [0,0,0], [1,1,1]) + + def test_anim_vec2i_linear(self): + self.setup_check_animation_channel( + "channel_vec2i_linear", raco.EAnimationComponentType.Vec2i, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [[4, 5], [5,6], [6,7]]) + + def test_anim_vec2i_cubic(self): + self.setup_check_animation_channel( + "channel_vec2i_cubic", raco.EAnimationComponentType.Vec2i, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [[4,5], [5,6], [6,7]], [[0,0], [0,0], [0,0]], [[1,1], [1,1], [1,1]]) + + def test_anim_vec3i_linear(self): + self.setup_check_animation_channel( + "channel_vec3i_linear", raco.EAnimationComponentType.Vec3i, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [[4, 5, 6], [5,6,7], [6,7,8]]) + + def test_anim_vec3i_cubic(self): + self.setup_check_animation_channel( + "channel_vec3i_cubic", raco.EAnimationComponentType.Vec3i, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [[4,5,6], [5,6,7], [6,7,8]], [[0,0,0], [0,0,0], [0,0,0]], [[1,1,1], [1,1,1], [1,1,1]]) + + def test_anim_vec4i_linear(self): + self.setup_check_animation_channel( + "channel_vec4i_linear", raco.EAnimationComponentType.Vec4i, raco.EAnimationInterpolationType.Linear, 0, + [0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]]) + + def test_anim_vec4i_cubic(self): + self.setup_check_animation_channel( + "channel_vec4i_cubic", raco.EAnimationComponentType.Vec4i, raco.EAnimationInterpolationType.CubicSpline, 0, + [0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]], [[0,0,0,0], [0,0,0,0], [0,0,0,0]], [[1,1,1,1], [1,1,1,1], [1,1,1,1]]) diff --git a/README.md b/README.md index 11a9c437..a99c96c2 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ set the environment variable ```RACO_QT_BASE``` to it. \raco> mkdir build \raco> cd build \raco\build> cmake .. -\raco\build> cmake --build . --target RaCoEditor --config # either Release or Debug +\raco\build> cmake --build . --target RaCoEditor --config # either RelWithDebInfo or Debug ``` Ramses Composer is built on Windows 10 with Visual Studio 2019 and on Ubuntu 20.04 with gcc 9.4.0. @@ -94,7 +94,7 @@ sudo apt install python3.8-dev The executable can be found in: ```console -\raco\build\release\bin\\RamsesComposer.exe # either Release or Debug +\raco\build\release\bin\\RamsesComposer.exe # either RelWithDebInfo or Debug ``` Starting RaCoEditor with an extra console showing stdout (Windows only): diff --git a/components/libApplication/CMakeLists.txt b/components/libApplication/CMakeLists.txt index 401a7707..bed19c68 100644 --- a/components/libApplication/CMakeLists.txt +++ b/components/libApplication/CMakeLists.txt @@ -12,6 +12,7 @@ raco_find_qt_components(Core) add_library(libApplication include/application/ExternalProjectsStore.h src/ExternalProjectsStore.cpp + include/application/ReportStatistics.h src/ReportStatistics.cpp include/application/RaCoApplication.h src/RaCoApplication.cpp include/application/RaCoProject.h src/RaCoProject.cpp ) diff --git a/components/libApplication/include/application/RaCoApplication.h b/components/libApplication/include/application/RaCoApplication.h index 9bcfc8eb..625ac9ba 100644 --- a/components/libApplication/include/application/RaCoApplication.h +++ b/components/libApplication/include/application/RaCoApplication.h @@ -10,9 +10,9 @@ #pragma once #include "application/ExternalProjectsStore.h" +#include "application/ReportStatistics.h" #include "application/RaCoProject.h" #include "components/DataChangeDispatcher.h" -#include "core/ChangeRecorder.h" #include "core/Project.h" #include "core/SceneBackendInterface.h" #include @@ -60,7 +60,8 @@ enum class ELuaSavingMode { SourceAndByteCode }; -class RaCoApplication{ +class RaCoApplication : public QObject { + Q_OBJECT public: explicit RaCoApplication(ramses_base::BaseEngineBackend& engine, const RaCoApplicationLaunchSettings& settings = {}); @@ -101,7 +102,8 @@ class RaCoApplication{ bool compress, std::string& outError, bool forceExportWithErrors = false, - ELuaSavingMode luaSavingMode = ELuaSavingMode::SourceCodeOnly); + ELuaSavingMode luaSavingMode = ELuaSavingMode::SourceCodeOnly, + bool warningsAsErrors = false); void doOneLoop(); @@ -141,11 +143,18 @@ class RaCoApplication{ const FeatureLevelLoadError* getFlError() const; + void setRecordingStats(bool enable); + void resetStats(); + const ReportStatistics& getLogicStats() const; + +Q_SIGNALS: + void performanceStatisticsUpdated(); + private: // Needs to access externalProjectsStore_ directly: friend class ::ObjectTreeViewExternalProjectModelTest; - bool exportProjectImpl(const std::string& ramsesExport, bool compress, std::string& outError, bool forceExportWithErrors, ELuaSavingMode luaSavingMode) const; + bool exportProjectImpl(const std::string& ramsesExport, bool compress, std::string& outError, bool forceExportWithErrors, ELuaSavingMode luaSavingMode, bool warningsAsErrors) const; void setupScene(bool optimizedForExport, bool setupAbstractScene); @@ -173,6 +182,9 @@ class RaCoApplication{ std::chrono::high_resolution_clock::time_point startTime_; std::function getTime_; + + bool recordingStats_ = false; + ReportStatistics logicStats_; }; } // namespace raco::application diff --git a/components/libApplication/include/application/RaCoProject.h b/components/libApplication/include/application/RaCoProject.h index 33ffc0fe..84cba85b 100644 --- a/components/libApplication/include/application/RaCoProject.h +++ b/components/libApplication/include/application/RaCoProject.h @@ -86,6 +86,7 @@ class RaCoProject : public QObject { static std::unique_ptr loadFromFile(const QString& filename, RaCoApplication* app, core::LoadContext& loadContext, bool logErrors = true, int featureLevel = -1, bool generateNewObjectIDs = false); QString name() const; + std::string pythonOnSaveScriptPath(); bool dirty() const noexcept; bool save(std::string &outError); @@ -95,6 +96,7 @@ class RaCoProject : public QObject { void updateExternalReferences(core::LoadContext& loadContext); core::Project* project(); + const core::Project* project() const; core::Errors const* errors() const; core::Errors* errors(); core::DataChangeRecorder* recorder(); @@ -126,7 +128,7 @@ class RaCoProject : public QObject { void generateProjectSubfolder(const std::string& subFolderPath); void generateAllProjectSubfolders(); void updateActiveFileListener(); - + core::DataChangeRecorder recorder_; core::Errors errors_; core::Project project_; diff --git a/components/libApplication/include/application/ReportStatistics.h b/components/libApplication/include/application/ReportStatistics.h new file mode 100644 index 00000000..5db4c0e9 --- /dev/null +++ b/components/libApplication/include/application/ReportStatistics.h @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include + +namespace raco::application { + +class ReportStatistics { +public: + using NodeDescriptor = std::string; + using ValueType = std::chrono::microseconds; + + using Snapshot = std::map; + using TimingSeries = std::deque; + using TimingSeriesStore = std::map; + + ReportStatistics(typename TimingSeries::size_type maxLength = 100) : maxLength_(maxLength) { + } + + /** + * @brief Add a snapshot of timings to to statistics. + * + * All timing series in the store will always be of the same length. + * Missing values in the snapshot for existing nodes are filled with 0. + * Keeps at most maxLength_ values discarding the oldest one if size overflows. + * + * @param snapshot Snapshot of timing data from last update. Indexed by object id + */ + void addSnapshot(const Snapshot& snapshot); + + const TimingSeriesStore& getTimingData() const; + +private: + void addValue(TimingSeries& timings, ValueType value); + + typename TimingSeries::size_type maxLength_; + + std::map store_; +}; + +} // namespace raco::application diff --git a/components/libApplication/src/RaCoApplication.cpp b/components/libApplication/src/RaCoApplication.cpp index b758cc66..97123e3f 100644 --- a/components/libApplication/src/RaCoApplication.cpp +++ b/components/libApplication/src/RaCoApplication.cpp @@ -98,6 +98,7 @@ std::string RaCoApplication::activeProjectFolder() const { void RaCoApplication::resetSceneBackend() { previewSceneBackend_->reset(); abstractScene_.reset(); + recordingStats_ = false; } class WithRelinkCallback { @@ -118,6 +119,7 @@ void RaCoApplication::setupScene(bool optimizeForExport, bool setupAbstractScene auto featureLevel = static_cast(activeRaCoProject().project()->featureLevel()); previewSceneBackend_->setScene(activeRaCoProject().project(), activeRaCoProject().errors(), optimizeForExport, ramses_adaptor::SceneBackend::toSceneId(*activeRaCoProject().project()->settings()->sceneId_)); + previewSceneBackend_->logicEngine()->enableUpdateReport(recordingStats_ && !optimizeForExport); if (runningInUI_) { if (setupAbstractScene) { abstractScene_.reset(); @@ -133,8 +135,8 @@ void RaCoApplication::switchActiveRaCoProject(const QString& file, std::function WithRelinkCallback withRelinkCallback(externalProjectsStore_, relinkCallback); activeProject_.reset(); - previewSceneBackend_->reset(); - abstractScene_.reset(); + resetSceneBackend(); + resetStats(); // The module cache should already by empty after removing the local and external projects but explicitly clear it anyway // to avoid potential problems. @@ -204,12 +206,12 @@ core::ErrorLevel RaCoApplication::getExportSceneDescriptionAndStatus(std::vector return errorLevel; } -bool RaCoApplication::exportProject(const std::string& ramsesExport, bool compress, std::string& outError, bool forceExportWithErrors, ELuaSavingMode luaSavingMode) { +bool RaCoApplication::exportProject(const std::string& ramsesExport, bool compress, std::string& outError, bool forceExportWithErrors, ELuaSavingMode luaSavingMode, bool warningsAsErrors) { setupScene(true, false); logicEngineNeedsUpdate_ = true; doOneLoop(); - bool status = exportProjectImpl(ramsesExport, compress, outError, forceExportWithErrors, luaSavingMode); + bool status = exportProjectImpl(ramsesExport, compress, outError, forceExportWithErrors, luaSavingMode, warningsAsErrors); setupScene(false, false); logicEngineNeedsUpdate_ = true; @@ -218,7 +220,7 @@ bool RaCoApplication::exportProject(const std::string& ramsesExport, bool compre return status; } -bool RaCoApplication::exportProjectImpl(const std::string& ramsesExport, bool compress, std::string& outError, bool forceExportWithErrors, ELuaSavingMode luaSavingMode) const { +bool RaCoApplication::exportProjectImpl(const std::string& ramsesExport, bool compress, std::string& outError, bool forceExportWithErrors, ELuaSavingMode luaSavingMode, bool warningsAsErrors) const { // Flushing the scene prevents inconsistent states being saved which could lead to unexpected bevahiour after loading the scene: previewSceneBackend_->flush(); @@ -234,9 +236,17 @@ bool RaCoApplication::exportProjectImpl(const std::string& ramsesExport, bool co } return false; } - if (sceneBackend()->sceneValid() != core::ErrorLevel::NONE) { + core::ErrorLevel errorLevel = sceneBackend()->sceneValid(); + if (errorLevel == core::ErrorLevel::ERROR) { outError = "Export failed: scene contains Ramses errors:\n" + sceneBackend()->getValidationReport(core::ErrorLevel::WARNING); return false; + } else if (errorLevel == core::ErrorLevel::WARNING) { + if (warningsAsErrors) { + outError = "Export failed: scene contains Ramses warnings (treated as errors):\n" + sceneBackend()->getValidationReport(core::ErrorLevel::WARNING); + return false; + } else { + outError = "Export with Ramses warnings:\n" + sceneBackend()->getValidationReport(core::ErrorLevel::WARNING); + } } } @@ -297,6 +307,11 @@ void RaCoApplication::doOneLoop() { // read modified engine data previewSceneBackend_->readDataFromEngine(dataChanges); logicEngineNeedsUpdate_ = false; + + if (recordingStats_) { + logicStats_.addSnapshot(previewSceneBackend_->getPerformanceReport()); + Q_EMIT performanceStatisticsUpdated(); + } } dataChangeDispatcherAbstractScene_->dispatch(dataChanges); @@ -393,6 +408,20 @@ const FeatureLevelLoadError* RaCoApplication::getFlError() const { return externalProjectsStore_.getFlError(); } +void RaCoApplication::setRecordingStats(bool enable) { + recordingStats_ = enable; + previewSceneBackend_->logicEngine()->enableUpdateReport(enable); +} + +void RaCoApplication::resetStats() { + logicStats_ = ReportStatistics{}; + Q_EMIT performanceStatisticsUpdated(); +} + +const ReportStatistics& RaCoApplication::getLogicStats() const { + return logicStats_; +} + core::ExternalProjectsStoreInterface* RaCoApplication::externalProjects() { return &externalProjectsStore_; } diff --git a/components/libApplication/src/RaCoProject.cpp b/components/libApplication/src/RaCoProject.cpp index f3f47257..10db81b2 100644 --- a/components/libApplication/src/RaCoProject.cpp +++ b/components/libApplication/src/RaCoProject.cpp @@ -370,9 +370,6 @@ QJsonDocument RaCoProject::loadJsonDocument(const QString& filename) { int RaCoProject::preloadFeatureLevel(const QString& filename, int featureLevel) { LOG_INFO(log_system::PROJECT, "Loading project from {}", filename.toLatin1()); - QFileInfo path(filename); - QString absPath = path.absoluteFilePath(); - auto document = loadJsonDocument(filename); auto fileFeatureLevel = serialization::deserializeFeatureLevel(document); @@ -469,6 +466,9 @@ QString RaCoProject::name() const { return QString::fromStdString(project_.settings()->objectName()); } +std::string RaCoProject::pythonOnSaveScriptPath() { + return project_.settings()->pythonOnSaveScript_.asString(); +} QJsonDocument RaCoProject::serializeProjectData(const std::unordered_map>& currentVersions) { // Create instances in serialization order: @@ -796,6 +796,10 @@ Project* RaCoProject::project() { return &project_; } +const Project* RaCoProject::project() const { + return &project_; +} + Errors* RaCoProject::errors() { return &errors_; } diff --git a/components/libApplication/src/ReportStatistics.cpp b/components/libApplication/src/ReportStatistics.cpp new file mode 100644 index 00000000..b7270ad4 --- /dev/null +++ b/components/libApplication/src/ReportStatistics.cpp @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include "application/ReportStatistics.h" + +#include +#include + +namespace raco::application { + +void ReportStatistics::addSnapshot(const Snapshot& snapshot) { + auto curLength = store_.empty() ? 0 : store_.begin()->second.size(); + for (const auto& [key, value] : snapshot) { + if (store_.find(key) == store_.end()) { + store_[key] = TimingSeries{curLength}; + } + addValue(store_[key], value); + } + for (const auto& [key, value] : store_) { + if (snapshot.find(key) == snapshot.end()) { + addValue(store_[key], {}); + } + } + auto newLength = store_.empty() ? 0 : std::min(maxLength_, curLength + 1); + assert(std::all_of(store_.begin(), store_.end(), [newLength](const auto& item) { + return item.second.size() == newLength; + })); +} + +const ReportStatistics::TimingSeriesStore& ReportStatistics::getTimingData() const { + return store_; +} + +void ReportStatistics::addValue(TimingSeries& timings, ValueType value) { + timings.push_back(value); + while (timings.size() > maxLength_) { + timings.pop_front(); + } +} + +} // namespace raco::application::stats diff --git a/components/libApplication/tests/CMakeLists.txt b/components/libApplication/tests/CMakeLists.txt index 3303c49c..191b401f 100644 --- a/components/libApplication/tests/CMakeLists.txt +++ b/components/libApplication/tests/CMakeLists.txt @@ -11,6 +11,7 @@ If a copy of the MPL was not distributed with this file, You can obtain one at h # Adding the unit test with gtest using our macro from dsathe top level CMakeLists.txt file set(TEST_SOURCES + ReportStatistics_test.cpp RaCoApplication_test.cpp RaCoProject_test.cpp ) @@ -41,6 +42,7 @@ raco_package_test_resources_process( meshes/InterpolationTest/InterpolationTest.gltf meshes/InterpolationTest/interpolation.bin meshes/InterpolationTest/l.jpg + meshes/SimpleSkin/SimpleSkin-multi-target.gltf meshes/Duck.glb meshes/meshless.gltf meshes/negativeScaleQuad.gltf diff --git a/components/libApplication/tests/RaCoApplication_test.cpp b/components/libApplication/tests/RaCoApplication_test.cpp index e2f9422c..3566e6be 100644 --- a/components/libApplication/tests/RaCoApplication_test.cpp +++ b/components/libApplication/tests/RaCoApplication_test.cpp @@ -183,21 +183,21 @@ TEST_F(RaCoApplicationFixture, export_with_lua_save_modes) { false, error, false, - raco::application::ELuaSavingMode::ByteCodeOnly)); + application::ELuaSavingMode::ByteCodeOnly)); EXPECT_TRUE(application.exportProject( (test_path() / "SourceCodeOnly.ramses").string(), false, error, false, - raco::application::ELuaSavingMode::SourceCodeOnly)); + application::ELuaSavingMode::SourceCodeOnly)); EXPECT_TRUE(application.exportProject( (test_path() / "SourceAndByteCode.ramses").string(), false, error, false, - raco::application::ELuaSavingMode::SourceAndByteCode)); + application::ELuaSavingMode::SourceAndByteCode)); } TEST_F(RaCoApplicationFixture, cant_delete_ProjectSettings) { @@ -205,7 +205,7 @@ TEST_F(RaCoApplicationFixture, cant_delete_ProjectSettings) { commandInterface->deleteObjects(application.activeRaCoProject().project()->instances()); ASSERT_EQ(application.activeRaCoProject().project()->instances().size(), 1); - EXPECT_TRUE(raco::select(application.activeRaCoProject().project()->instances()) != nullptr); + EXPECT_TRUE(select(application.activeRaCoProject().project()->instances()) != nullptr); } TEST_F(RaCoApplicationFixture, importglTFScenegraphCorrectNodeAmount) { @@ -216,7 +216,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphCorrectNodeAmount) { desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); // generated objects: @@ -253,7 +253,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphVectorsGetLinked) { desc.absPath = test_path().append("meshes/InterpolationTest/InterpolationTest.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); ASSERT_EQ(application.activeRaCoProject().project()->links().size(), 9) << "InterpolationTest has 9 animations, all of them should be running"; @@ -267,7 +267,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphMeshWithNegativeScaleWillBeIm desc.absPath = test_path().append("meshes/negativeScaleQuad.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); auto node = core::ValueHandle(core::Queries::findByName(core::Queries::filterForNotResource(commandInterface->project()->instances()), "Quad")); constexpr auto DELTA = 0.0001; @@ -286,7 +286,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphCachedMeshPathGetsChanged) { desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); application.dataChangeDispatcher()->dispatch(*application.activeRaCoProject().recorder()); @@ -301,7 +301,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphCorrectScenegraphStructureTru desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); application.dataChangeDispatcher()->dispatch(*application.activeRaCoProject().recorder()); @@ -347,7 +347,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphCorrectRootNodeInsertion) { desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, myRoot); auto yup2Zup = core::Queries::findByName(commandInterface->project()->instances(), "Yup2Zup"); @@ -364,7 +364,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphCorrectRootNodeRenaming) { desc.absPath = test_path().append("meshes/ToyCar/ToyCar.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); auto root = core::Queries::findByName(commandInterface->project()->instances(), "ToyCar.gltf"); @@ -382,7 +382,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphImportSceneGraphTwice) { desc.bakeAllSubmeshes = false; - auto [sceneGraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [sceneGraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(sceneGraph, desc.absPath, firstRoot); commandInterface->insertAssetScenegraph(sceneGraph, desc.absPath, secondRoot); @@ -401,7 +401,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphImportSceneGraphTwiceButMeshe desc.bakeAllSubmeshes = false; - auto [sceneGraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [sceneGraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(sceneGraph, desc.absPath, firstRoot); auto allMeshes = core::Queries::filterByTypeName(commandInterface->project()->instances(), {user_types::Mesh::typeDescription.typeName}); @@ -432,7 +432,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphImportSceneGraphTwiceButAnima desc.bakeAllSubmeshes = false; - auto [sceneGraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [sceneGraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(sceneGraph, desc.absPath, firstRoot); auto allAnimChannels = core::Queries::filterByTypeName(commandInterface->project()->instances(), {user_types::AnimationChannel::typeDescription.typeName}); @@ -455,7 +455,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphUnbakedMeshesGetTransformed) desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); application.dataChangeDispatcher()->dispatch(*application.activeRaCoProject().recorder()); @@ -496,7 +496,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphCorrectAutomaticMaterialAssig desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); std::map materialMap = { @@ -526,7 +526,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphUnmarkedNodesDoNotGetImported desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); auto nodeToRemoveIndex = std::find_if(scenegraph.nodes.begin(), scenegraph.nodes.end(), [](const auto& node) { return node->name == "Node.001"; }) - scenegraph.nodes.begin(); for (auto& node : scenegraph.nodes) { @@ -566,7 +566,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphImportedAnimationDoesNotGetPa desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); @@ -585,7 +585,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphDeselectedAnimationsDoNotGetI desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); scenegraph.animations.front().reset(); @@ -605,7 +605,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphDeselectedNodesWillNotCreateL desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); for (auto& node : scenegraph.nodes) { node.reset(); @@ -624,7 +624,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphDeselectedAnimationChannelsDo desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); for (auto& samplers : scenegraph.animationSamplers) { for (auto& sampler : samplers) { @@ -678,7 +678,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphWithNoMeshes) { desc.absPath = test_path().append("meshes/meshless.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); ASSERT_EQ(scenegraph.nodes.size(), 3); } @@ -707,7 +707,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphWithNoMeshesAndNoNodes) { desc.absPath = nodeless; desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); ASSERT_TRUE(scenegraph.nodes.empty()); } @@ -720,7 +720,7 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphMeshNodesDontReferenceDeselec desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); auto meshToRemoveIndex = std::find_if(scenegraph.meshes.begin(), scenegraph.meshes.end(), [](const auto& meshName) { return meshName.value() == "Cesium_Milk_Truck.0"; }) - scenegraph.meshes.begin(); scenegraph.meshes[meshToRemoveIndex].reset(); @@ -748,6 +748,26 @@ TEST_F(RaCoApplicationFixture, importglTFScenegraphMeshNodesDontReferenceDeselec } } +TEST_F(RaCoApplicationFixture, importglTFScenegraphMultiTargetSkin) { + core::MeshDescriptor desc; + desc.absPath = (test_path() / "meshes/SimpleSkin/SimpleSkin-multi-target.gltf").string(); + desc.bakeAllSubmeshes = false; + + auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface().meshCache(), desc); + commandInterface().insertAssetScenegraph(scenegraph, desc.absPath, nullptr); + + auto skin = select(project().instances()); + auto node_0 = select(project().instances(), "nodes_0"); + auto node_1 = select(project().instances(), "nodes_1"); + auto node_2 = select(project().instances(), "nodes_2"); + auto node_3 = select(project().instances(), "nodes_3"); + + EXPECT_EQ(skin->targets_->size(), 2); + EXPECT_EQ(skin->targets_->asVector(), std::vector({node_0, node_3})); + EXPECT_EQ(skin->joints_->size(), 2); + EXPECT_EQ(skin->joints_->asVector(), std::vector({node_1, node_2})); +} + TEST_F(RaCoApplicationFixture, LuaScriptRuntimeErrorCausesInformationForAllScripts) { auto* commandInterface = application.activeRaCoProject().commandInterface(); diff --git a/components/libApplication/tests/RaCoProject_test.cpp b/components/libApplication/tests/RaCoProject_test.cpp index ebf9328f..821c3c7b 100644 --- a/components/libApplication/tests/RaCoProject_test.cpp +++ b/components/libApplication/tests/RaCoProject_test.cpp @@ -33,7 +33,7 @@ using namespace raco::core; using namespace raco::user_types; TEST_F(RaCoProjectFixture, saveLoadWithLink) { - raco::createLinkedScene(commandInterface(), test_path()); + createLinkedScene(commandInterface(), test_path()); std::string msg; ASSERT_TRUE(application.activeRaCoProject().saveAs((test_path() / "project.rca").string().c_str(), msg)); @@ -42,7 +42,7 @@ TEST_F(RaCoProjectFixture, saveLoadWithLink) { } TEST_F(RaCoProjectFixture, saveLoadWithBrokenLink) { - auto linkedScene = raco::createLinkedScene(commandInterface(), test_path()); + auto linkedScene = createLinkedScene(commandInterface(), test_path()); utils::file::write((test_path() / "lua_script.lua").string(), R"( function interface(IN,OUT) OUT.newTranslation = Type:Vec3f() @@ -130,7 +130,7 @@ end TEST_F(RaCoProjectFixture, saveWithValidLinkLoadWithBrokenLink) { { - auto linkedScene = raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + auto linkedScene = createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); std::string msg; ASSERT_TRUE(application.activeRaCoProject().saveAs((test_path() / "project.rca").string().c_str(), msg)); } @@ -153,7 +153,7 @@ end TEST_F(RaCoProjectFixture, saveWithBrokenLinkLoadWithValidLink) { { - auto linkedScene = raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + auto linkedScene = createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); utils::file::write((test_path() / "lua_script.lua").string(), R"( function interface(IN,OUT) OUT.newTranslation = Type:Vec3f() @@ -182,7 +182,7 @@ end TEST_F(RaCoProjectFixture, saveLoadWithLinkRemoveOutputPropertyBeforeLoading) { { - raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); std::string msg; ASSERT_TRUE(application.activeRaCoProject().saveAs((test_path() / "project.rca").string().c_str(), msg)); } @@ -271,7 +271,7 @@ TEST_F(RaCoProjectFixture, saveAsThenLoadAnimationKeepsChannelAmount) { desc.absPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface->meshCache(), desc); commandInterface->insertAssetScenegraph(scenegraph, desc.absPath, nullptr); commandInterface->createObject(user_types::Animation::typeDescription.typeName, "userAnim"); @@ -437,14 +437,14 @@ TEST_F(RaCoProjectFixture, save_as_with_new_id_preserves_prefab_id_structure_nes auto& instances = application.activeRaCoProject().project()->instances(); { - auto prefab = raco::select(instances, "prefab"); + auto prefab = select(instances, "prefab"); auto lua = prefab->children_->asVector()[0]; - auto prefab_2 = raco::select(instances, "prefab2"); + auto prefab_2 = select(instances, "prefab2"); auto inst_1 = prefab_2->children_->asVector()[0]; auto lua_1 = inst_1->children_->asVector()[0]; - auto inst_2 = raco::select(instances, "inst2"); + auto inst_2 = select(instances, "inst2"); auto inst_3 = inst_2->children_->asVector()[0]; auto lua_2 = inst_3->children_->asVector()[0]; @@ -591,7 +591,7 @@ TEST_F(RaCoProjectFixture, saveAs_set_path_updates_cached_path) { std::string interfaceSubdirectory = u8"shared"; std::string shaderSubdirectory = u8"shared"; - using namespace raco::user_types; + using namespace user_types; std::string msg; ASSERT_TRUE(application.activeRaCoProject().saveAs((test_path() / "project.rca").string().c_str(), msg, false)); @@ -622,7 +622,7 @@ TEST_F(RaCoProjectFixture, saveAs_with_new_id_set_path_updates_cached_path) { std::string interfaceSubdirectory = u8"shared"; std::string shaderSubdirectory = u8"shared"; - using namespace raco::user_types; + using namespace user_types; std::string msg; ASSERT_TRUE(application.saveAsWithNewIDs((test_path() / "project.rca").string().c_str(), msg, false)); @@ -661,7 +661,7 @@ TEST_F(RaCoProjectFixture, saveAsNewProjectGeneratesResourceSubFolders) { std::string interfaceSubdirectory = u8"shared"; std::string shaderSubdirectory = u8"shared"; - using namespace raco::user_types; + using namespace user_types; const auto& settings = application.activeRaCoProject().project()->settings(); const auto& commandInterface = application.activeRaCoProject().commandInterface(); @@ -760,7 +760,7 @@ TEST_F(RaCoProjectFixture, loadingBrokenJSONFileThrowsException) { TEST_F(RaCoProjectFixture, saveLoadAsZip) { { - auto linkedScene = raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + auto linkedScene = createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); auto lua = std::get(linkedScene); const auto nodeRotEuler{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_eul")}; const auto nodeRotQuat{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_quat")}; @@ -783,7 +783,7 @@ TEST_F(RaCoProjectFixture, saveLoadAsZip) { TEST_F(RaCoProjectFixture, saveLoadRotationLinksGetReinstated) { { - auto linkedScene = raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + auto linkedScene = createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); auto lua = std::get(linkedScene); const auto nodeRotEuler{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_eul")}; const auto nodeRotQuat{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_quat")}; @@ -804,7 +804,7 @@ TEST_F(RaCoProjectFixture, saveLoadRotationLinksGetReinstated) { TEST_F(RaCoProjectFixture, saveLoadRotationInvalidLinksGetReinstated) { { - auto linkedScene = raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + auto linkedScene = createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); auto lua = std::get(linkedScene); const auto nodeRotEuler{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_eul")}; const auto nodeRotQuat{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_quat")}; @@ -833,7 +833,7 @@ TEST_F(RaCoProjectFixture, saveLoadRotationInvalidLinksGetReinstated) { TEST_F(RaCoProjectFixture, saveLoadRotationInvalidLinksGetReinstatedWithDifferentTypes) { { - auto linkedScene = raco::createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); + auto linkedScene = createLinkedScene(*application.activeRaCoProject().commandInterface(), test_path()); auto lua = std::get(linkedScene); const auto nodeRotEuler{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_eul")}; const auto nodeRotQuat{application.activeRaCoProject().commandInterface()->createObject(user_types::Node::typeDescription.typeName, "node_quat")}; @@ -875,7 +875,7 @@ TEST_F(RaCoProjectFixture, copyPasteShallowAnimationReferencingAnimationChannel) application.activeRaCoProject().project()->setCurrentPath((test_path() / "project.rca").string()); auto path = (test_path() / "meshes" / "InterpolationTest" / "InterpolationTest.gltf").string(); - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(application.activeRaCoProject().meshCache(), {path, 0, false}); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(application.activeRaCoProject().meshCache(), {path, 0, false}); application.activeRaCoProject().commandInterface()->insertAssetScenegraph(scenegraph, path, nullptr); application.doOneLoop(); @@ -895,7 +895,7 @@ TEST_F(RaCoProjectFixture, copyPasteDeepAnimationReferencingAnimationChannel) { { application.activeRaCoProject().project()->setCurrentPath((test_path() / "project.rca").string()); auto path = (test_path() / "meshes" / "InterpolationTest" / "InterpolationTest.gltf").string(); - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(application.activeRaCoProject().meshCache(), {path, 0, false}); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(application.activeRaCoProject().meshCache(), {path, 0, false}); application.activeRaCoProject().commandInterface()->insertAssetScenegraph(scenegraph, path, nullptr); application.doOneLoop(); diff --git a/components/libApplication/tests/ReportStatistics_test.cpp b/components/libApplication/tests/ReportStatistics_test.cpp new file mode 100644 index 00000000..db726946 --- /dev/null +++ b/components/libApplication/tests/ReportStatistics_test.cpp @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include "application/ReportStatistics.h" + +#include "testing/TestUtil.h" + +using namespace raco::application; + +using Snapshot = ReportStatistics::Snapshot; +using ValueType = std::chrono::microseconds; + +class ReportStatisticsTest : public RacoBaseTest<> { +}; + +TEST_F(ReportStatisticsTest, addReportTest) { + const Snapshot snapshot1{{"node1", ValueType{1}}}; + const Snapshot snapshot2{{"node2", ValueType{2}}}; + const Snapshot snapshot3{{"node1", ValueType{11}}}; + + ReportStatistics stat{}; + stat.addSnapshot(snapshot1); + const auto& timings = stat.getTimingData(); + ASSERT_EQ(timings.size(), 1); + ASSERT_EQ(timings.at("node1"), std::deque({ValueType(1)})); + + stat.addSnapshot(snapshot2); + ASSERT_EQ(timings.size(), 2); + ASSERT_EQ(timings.at("node1"), std::deque({ValueType(1), ValueType(0)})); + ASSERT_EQ(timings.at("node2"), std::deque({ValueType(0), ValueType(2)})); + + stat.addSnapshot(snapshot3); + ASSERT_EQ(timings.size(), 2); + ASSERT_EQ(timings.at("node1"), std::deque({ValueType(1), ValueType(0), ValueType(11)})); + ASSERT_EQ(timings.at("node2"), std::deque({ValueType(0), ValueType(2), ValueType(0)})); +} + +TEST_F(ReportStatisticsTest, lengthTest) { + const Snapshot snapshot1{{"node1", ValueType{1}}}; + const Snapshot snapshot2{{"node2", ValueType{2}}}; + + ReportStatistics stat{10}; + ASSERT_EQ(stat.getTimingData().size(), 0); + + stat.addSnapshot(snapshot1); + for (int i = 0; i < 20; i++) { + stat.addSnapshot(snapshot2); + } + + ASSERT_EQ(stat.getTimingData().size(), 2); + ASSERT_EQ(stat.getTimingData().at("node1").size(), 10); + ASSERT_EQ(stat.getTimingData().at("node2").size(), 10); +} diff --git a/components/libComponents/include/components/RaCoPreferences.h b/components/libComponents/include/components/RaCoPreferences.h index 144b37a3..6b0c7358 100644 --- a/components/libComponents/include/components/RaCoPreferences.h +++ b/components/libComponents/include/components/RaCoPreferences.h @@ -38,12 +38,14 @@ class RaCoPreferences final : public QObject { QString interfaceSubdirectory; QString shaderSubdirectory; QString screenshotDirectory; + QString globalPythonOnSaveScript; // The feature level in the settings is not capped to the maximum allowed feature level. // Capping is done on application startup and in the PreferencesView instead. int featureLevel; bool isUriValidationCaseSensitive; bool preventAccidentalUpgrade; + bool enableProjectPythonScript; }; } // namespace raco diff --git a/components/libComponents/src/DataChangeDispatcher.cpp b/components/libComponents/src/DataChangeDispatcher.cpp index 3a7e6938..4e0e6cf5 100644 --- a/components/libComponents/src/DataChangeDispatcher.cpp +++ b/components/libComponents/src/DataChangeDispatcher.cpp @@ -199,13 +199,13 @@ void DataChangeDispatcher::dispatch(const DataChangeRecorder& dataChanges) { emitLinksAdded(dataChanges.getAddedLinks()); - // Bulk update notification will be used by the SceneAdaptor to perform the actual engine update. - emitBulkChange(dataChanges.getAllChangedObjects(true)); - for (auto& deletedObject : dataChanges.getDeletedObjects()) { emitDeleted(deletedObject); } + // Bulk update notification will be used by the SceneAdaptor to perform the actual engine update. + emitBulkChange(dataChanges.getAllChangedObjects(true)); + if (undoChanged_) { for (auto& undoListener : undoChangeListeners_) { if (!undoListener.expired()) diff --git a/components/libComponents/src/RaCoPreferences.cpp b/components/libComponents/src/RaCoPreferences.cpp index 07c5a093..26410656 100644 --- a/components/libComponents/src/RaCoPreferences.cpp +++ b/components/libComponents/src/RaCoPreferences.cpp @@ -37,6 +37,8 @@ bool RaCoPreferences::save() { settings.setValue("featureLevel", featureLevel); settings.setValue("isUriValidationCaseSensitive", isUriValidationCaseSensitive); settings.setValue("preventAccidentalUpgrade", preventAccidentalUpgrade); + settings.setValue("globalPythonOnSaveScript", globalPythonOnSaveScript); + settings.setValue("enableProjectPythonScript", enableProjectPythonScript); settings.sync(); @@ -62,6 +64,9 @@ void RaCoPreferences::load() { featureLevel = settings.value("featureLevel", 1).toInt(); isUriValidationCaseSensitive = settings.value("isUriValidationCaseSensitive", false).toBool(); preventAccidentalUpgrade = settings.value("preventAccidentalUpgrade", false).toBool(); + + globalPythonOnSaveScript = settings.value("globalPythonOnSaveScript", "").toString(); + enableProjectPythonScript = settings.value("enableProjectPythonScript", "").toBool(); } RaCoPreferences& RaCoPreferences::instance() noexcept { diff --git a/components/libComponents/tests/FileChangeMonitor_test.cpp b/components/libComponents/tests/FileChangeMonitor_test.cpp index dfb20de2..b26bc005 100644 --- a/components/libComponents/tests/FileChangeMonitor_test.cpp +++ b/components/libComponents/tests/FileChangeMonitor_test.cpp @@ -37,18 +37,13 @@ class BasicFileChangeMonitorTest : public TestEnvironmentCore { // Wait for the timer to queue its event, and then process the timer event, which eventually // leads to the callbacks registered with FileMonitor::registerFileChangedHandler to be called. std::this_thread::sleep_for(std::chrono::milliseconds(components::FileChangeListenerImpl::DELAYED_FILE_LOAD_TIME_MSEC + 100)); - QCoreApplication::processEvents(); - } - while (fileChangeCounter_ < count && std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() <= timeOutInMS); - + QCoreApplication::processEvents(); + } while (fileChangeCounter_ < count && std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() <= timeOutInMS); + + EXPECT_EQ(fileChangeCounter_, count); return fileChangeCounter_ == count; } - int argc = 0; - // Apparently QCoreApplication needs to be initialized before the ProjectFileChangeMonitor is created, since that - // will create signal connections which don't work on Linux otherwise (but they do work on Windows). - QCoreApplication eventLoop_{argc, nullptr}; - int fileChangeCounter_{0}; std::function testCallback_ = [this]() { ++fileChangeCounter_; }; std::unique_ptr testFileChangeMonitor_ = std::make_unique(); diff --git a/components/libComponents/tests/TracePlayer_test.cpp b/components/libComponents/tests/TracePlayer_test.cpp index 47ab19de..9e8378bb 100644 --- a/components/libComponents/tests/TracePlayer_test.cpp +++ b/components/libComponents/tests/TracePlayer_test.cpp @@ -88,7 +88,7 @@ class TracePlayerTest : public RacoBaseTest<> { int argc{0}; QCoreApplication eventLoop_{argc, nullptr}; ramses_base::HeadlessEngineBackend backend{}; - raco::application::RaCoApplication application{backend, {{}, false, false, -1, -1, false}}; + application::RaCoApplication application{backend, {{}, false, false, -1, -1, false}}; }; /* ************************************** helper functions ************************************** */ diff --git a/components/libMeshLoader/include/mesh_loader/glTFBufferData.h b/components/libMeshLoader/include/mesh_loader/glTFBufferData.h index 46e2c508..5a8bf3e8 100644 --- a/components/libMeshLoader/include/mesh_loader/glTFBufferData.h +++ b/components/libMeshLoader/include/mesh_loader/glTFBufferData.h @@ -13,6 +13,8 @@ #include #include +namespace raco::mesh_loader { + struct glTFBufferData { glTFBufferData(const tinygltf::Model &scene, int accessorIndex, const std::set &allowedComponentTypes, const std::set &allowedTypes) : scene_(scene), @@ -39,6 +41,10 @@ struct glTFBufferData { return numComponentsForType.at(accessor_.type); } + int type() const { + return accessor_.type; + } + template T getDataArray(size_t index, bool useComponentSize = true) const { auto componentSize = (useComponentSize) ? accessor_.ByteStride(view_) / sizeof(typename T::value_type) : 1; @@ -61,7 +67,7 @@ struct glTFBufferData { assert(componentSize > 0); auto firstByte = reinterpret_cast(&bufferBytes[(accessor_.byteOffset + view_.byteOffset)]); - + std::vector values(numComponents()); for (int i = 0; i < values.size(); ++i) { @@ -104,7 +110,7 @@ struct glTFBufferData { return {}; } - template + template std::vector getConvertedData(size_t index, bool useComponentSize = true) { switch (accessor_.componentType) { case TINYGLTF_PARAMETER_TYPE_FLOAT: @@ -134,13 +140,12 @@ struct glTFBufferData { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: return getDataAt(index, useComponentSize); break; - } return {}; } - template - std::vector normalize(const std::vector &data){ + template + std::vector normalize(const std::vector &data) { std::vector result(data.size()); for (auto i = 0; i < data.size(); i++) { result[i] = std::max(-1.0F, data[i] / static_cast(std::numeric_limits::max())); @@ -152,4 +157,6 @@ struct glTFBufferData { const tinygltf::Accessor &accessor_; const tinygltf::BufferView &view_; const std::vector &bufferBytes; -}; \ No newline at end of file +}; + +} // namespace raco::mesh_loader \ No newline at end of file diff --git a/components/libMeshLoader/src/glTFFileLoader.cpp b/components/libMeshLoader/src/glTFFileLoader.cpp index bc15b3c7..651f4fc3 100644 --- a/components/libMeshLoader/src/glTFFileLoader.cpp +++ b/components/libMeshLoader/src/glTFFileLoader.cpp @@ -132,6 +132,24 @@ void unpackAnimationData(const std::vector>& data, } } +std::vector convert_vec3(const std::vector>& data) { + std::vector result; + for (size_t index = 0; index < data.size(); index++) { + const auto& v = data[index]; + result.emplace_back(glm::vec3(v[0], v[1], v[2])); + } + return result; +} + +std::vector convert_vec4(const std::vector>& data) { + std::vector result; + for (size_t index = 0; index < data.size(); index++) { + const auto& v = data[index]; + result.emplace_back(glm::vec4(v[0], v[1], v[2], v[3])); + } + return result; +} + } // namespace namespace raco::mesh_loader { @@ -301,13 +319,15 @@ void glTFFileLoader::importSkins() { const auto& skin = scene_->skins[index]; std::string name = skin.name.empty() ? fmt::format("skin_{}", index) : skin.name; - // Find node by searching through all nodes in scene - auto it = std::find_if(scene_->nodes.begin(), scene_->nodes.end(), [index](const tinygltf::Node& node) { - return index == node.skin; - }); - if (it != scene_->nodes.end()) { - int nodeIndex = it - scene_->nodes.begin(); - sceneGraph_->skins.emplace_back(core::SkinDescription{name, nodeIndex, skin.joints}); + // Find target nodes by searching through all nodes in scene + std::vector targets; + for (int nodeIndex = 0; nodeIndex < scene_->nodes.size(); nodeIndex++) { + if (scene_->nodes[nodeIndex].skin == index) { + targets.emplace_back(nodeIndex); + } + } + if (!targets.empty()) { + sceneGraph_->skins.emplace_back(core::SkinDescription{name, targets, skin.joints}); } } } @@ -398,7 +418,24 @@ core::SharedAnimationSamplerData glTFFileLoader::getAnimationSamplerData(const s unpackAnimationData(output, input.size(), interpolation, componentType, keyFrames, tangentsIn, tangentsOut); - return std::make_shared(core::AnimationSamplerData{interpolation, componentType, input, keyFrames, tangentsIn, tangentsOut}); + core::AnimationSamplerData::OutputDataVariant ramsesOutputData; + + switch (componentType) { + case core::EnginePrimitive::Array: + ramsesOutputData = core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData>{ + keyFrames, tangentsIn, tangentsOut}); + break; + case core::EnginePrimitive::Vec3f: + ramsesOutputData = core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convert_vec3(keyFrames), convert_vec3(tangentsIn), convert_vec3(tangentsOut)}); + break; + case core::EnginePrimitive::Vec4f: + ramsesOutputData = core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convert_vec4(keyFrames), convert_vec4(tangentsIn), convert_vec4(tangentsOut)}); + break; + default: + assert(false); + } + + return std::make_shared(core::AnimationSamplerData{interpolation, componentType, keyFrames.front().size(), input, ramsesOutputData}); } core::SharedMeshData glTFFileLoader::loadMesh(const core::MeshDescriptor& descriptor) { diff --git a/components/libMeshLoader/src/glTFMesh.cpp b/components/libMeshLoader/src/glTFMesh.cpp index bf83293b..a4d2719b 100644 --- a/components/libMeshLoader/src/glTFMesh.cpp +++ b/components/libMeshLoader/src/glTFMesh.cpp @@ -282,7 +282,7 @@ void convertPositionData(const glTFBufferData &data, std::vector &buffer, } } -void convertAttributeSet(const tinygltf::Primitive &primitive, const tinygltf::Model &scene, std::vector> &buffers, const std::string &attributeBaseName, const std::set &allowedComponentTypes, const std::set &allowedTypes, bool normalize, int numVertices) { +void convertAttributeSet(const tinygltf::Primitive &primitive, const tinygltf::Model &scene, std::vector> &buffers, const std::string &attributeBaseName, const std::set &allowedComponentTypes, const std::set &allowedTypes, bool normalize, int numVertices, bool padVec3Types = false) { for (auto channel = 0; channel < std::numeric_limits::max(); ++channel) { auto attribName = fmt::format("{}_{}", attributeBaseName, channel); if (primitive.attributes.find(attribName) != primitive.attributes.end()) { @@ -294,6 +294,10 @@ void convertAttributeSet(const tinygltf::Primitive &primitive, const tinygltf::M for (size_t vertexIndex = 0; vertexIndex < bufferData.accessor_.count; vertexIndex++) { auto elementData = normalize ? bufferData.getNormalizedData(vertexIndex) : bufferData.getConvertedData(vertexIndex); buffer.insert(buffer.end(), elementData.begin(), elementData.end()); + // Optionally add padding to convert RGB color to RGBA color using 1.0 for alpha as required by gltf spec: + if (padVec3Types && bufferData.type() == TINYGLTF_TYPE_VEC3) { + buffer.emplace_back(1.0f); + } } } else { LOG_WARNING(log_system::MESH_LOADER, "Attribute '{}' has different size than vertex buffer, ignoring it.", attribName); @@ -423,7 +427,13 @@ void glTFMesh::loadPrimitiveData(const tinygltf::Primitive &primitive, const tin convertAttributeSet(primitive, scene, colorBuffers, "COLOR", std::set{TINYGLTF_COMPONENT_TYPE_FLOAT, TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE, TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT}, - std::set{TINYGLTF_TYPE_VEC3, TINYGLTF_TYPE_VEC4}, true, numVertices); + std::set{TINYGLTF_TYPE_VEC3, TINYGLTF_TYPE_VEC4}, true, numVertices, true); + + if (colorBuffers.empty()) { + convertAttributeSet(primitive, scene, colorBuffers, "_COLOR", + std::set{TINYGLTF_COMPONENT_TYPE_FLOAT, TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE, TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT}, + std::set{TINYGLTF_TYPE_VEC3, TINYGLTF_TYPE_VEC4}, true, numVertices, true); + } convertAttributeSet(primitive, scene, jointBuffers, "JOINTS", std::set{TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE, TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT}, diff --git a/components/libPythonAPI/include/python_api/PythonAPI.h b/components/libPythonAPI/include/python_api/PythonAPI.h index 10c18c2f..be952d5a 100644 --- a/components/libPythonAPI/include/python_api/PythonAPI.h +++ b/components/libPythonAPI/include/python_api/PythonAPI.h @@ -21,7 +21,19 @@ struct PythonRunStatus { std::string stdErrBuffer; }; +std::string getPythonVersion(); bool preparePythonEnvironment(std::wstring argv0, const std::vector& pythonSearchPaths, bool searchPythonFolderForTest = false); -void setup(application::RaCoApplication* app); -PythonRunStatus runPythonScript(application::RaCoApplication* app, const std::wstring& applicationPath, const std::string& pythonScriptPath, const std::vector& pythonSearchPaths, const std::vector& pos_argv_cp); +void setApp(application::RaCoApplication* racoApp); +bool importRaCoModule(); +bool importCompleter(); + +bool initializeInterpreter(application::RaCoApplication* racoApp, const std::wstring& racoAppPath, const std::vector& pythonSearchPaths, const std::vector& cmdLineArgs); +void finalizeInterpreter(); + +PythonRunStatus runPythonScript(const std::string& pythonScript); +PythonRunStatus runPythonScriptFromFile(const std::string& pythonScriptPath); + +std::vector getCompletions(const std::string& prefix); +bool isCompleteCommand(const std::string& command); + } diff --git a/components/libPythonAPI/src/PythonAPI.cpp b/components/libPythonAPI/src/PythonAPI.cpp index f6d6e9f4..54da3a21 100644 --- a/components/libPythonAPI/src/PythonAPI.cpp +++ b/components/libPythonAPI/src/PythonAPI.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "python_api/PythonAPI.h" @@ -30,6 +31,7 @@ #include "core/ExternalReferenceAnnotation.h" #include "core/PrefabOperations.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/Enumerations.h" #include "user_types/Mesh.h" #include "user_types/Prefab.h" @@ -38,19 +40,20 @@ #include -#include - namespace py = pybind11; namespace { using namespace raco; -raco::application::RaCoApplication* app; -raco::python_api::PythonRunStatus currentRunStatus; +application::RaCoApplication* app{nullptr}; +std::wstring appPath{}; +std::vector pythonSearchPaths{}; +python_api::PythonRunStatus currentRunStatus{}; + py::object python_get_scalar_value(core::ValueHandle handle) { - using namespace raco::user_types; + using namespace user_types; switch (handle.type()) { case data_storage::PrimitiveType::Bool: @@ -99,6 +102,12 @@ py::object python_get_scalar_value(core::ValueHandle handle) { case core::EUserTypeEnumerations::StencilOperation: return py::cast(static_cast(handle.asInt())); + case core::EUserTypeEnumerations::AnimationComponentType: + return py::cast(static_cast(handle.asInt())); + + case core::EUserTypeEnumerations::AnimationInterpolationType: + return py::cast(static_cast(handle.asInt())); + default: assert(false); return py::none(); @@ -240,6 +249,50 @@ void python_set_value(const core::PropertyDescriptor& desc, py::object value) { } } +template +std::vector> glmToVector(const std::vector>& data) { + std::vector> result; + for (size_t index = 0; index < data.size(); index++) { + std::vector v; + for (size_t component = 0; component < N; component++) { + v.push_back(data[index][component]); + } + result.push_back(v); + } + return result; +} + +bool isIntegerComponentType(core::EnginePrimitive primitiveType) { + std::set intPrimTypes{ + core::EnginePrimitive::Int32, + core::EnginePrimitive::Vec2i, + core::EnginePrimitive::Vec3i, + core::EnginePrimitive::Vec4i}; + + return intPrimTypes.find(primitiveType) != intPrimTypes.end(); +} + +std::vector toFloat(std::vector in) { + std::vector out; + for (auto v : in) { + out.emplace_back(v); + } + return out; +} + +std::vector> toFloat(std::vector> in) { + std::vector> out; + for (size_t index = 0; index < in.size(); index++) { + std::vector v; + for (auto value : in[index]) { + v.emplace_back(value); + } + out.emplace_back(v); + } + return out; +} + + void python_load_project(std::string& path, int featureLevel) { if (app->isRunningInUI()) { throw std::runtime_error(fmt::format("Can not load project: project-switching Python functions currently not allowed in UI.")); @@ -421,9 +474,8 @@ PYBIND11_EMBEDDED_MODULE(raco_py_io, m) { }); } - PYBIND11_EMBEDDED_MODULE(raco, m) { - using namespace raco::user_types; + using namespace user_types; py::enum_(m, "ECullMode") .value("Disabled", ECullMode::Disabled) @@ -557,11 +609,28 @@ PYBIND11_EMBEDDED_MODULE(raco, m) { .value("WARNING", ErrorLevel::WARNING) .value("ERROR", ErrorLevel::ERROR); - py::enum_(m, "ELuaSavingMode") - .value("SourceCodeOnly", raco::application::ELuaSavingMode::SourceCodeOnly) - .value("ByteCodeOnly", raco::application::ELuaSavingMode::ByteCodeOnly) - .value("SourceAndByteCode", raco::application::ELuaSavingMode::SourceAndByteCode); - + py::enum_(m, "ELuaSavingMode") + .value("SourceCodeOnly", application::ELuaSavingMode::SourceCodeOnly) + .value("ByteCodeOnly", application::ELuaSavingMode::ByteCodeOnly) + .value("SourceAndByteCode", application::ELuaSavingMode::SourceAndByteCode); + + py::enum_(m, "EAnimationInterpolationType") + .value("Step", MeshAnimationInterpolation::Step) + .value("Linear", MeshAnimationInterpolation::Linear) + .value("CubicSpline", MeshAnimationInterpolation::CubicSpline) + .value("Linear_Quaternion", MeshAnimationInterpolation::Linear_Quaternion) + .value("CubicSpline_Quaternion", MeshAnimationInterpolation::CubicSpline_Quaternion); + + py::enum_(m, "EAnimationComponentType") + .value("Float", EnginePrimitive::Double) + .value("Vec2f", EnginePrimitive::Vec2f) + .value("Vec3f", EnginePrimitive::Vec3f) + .value("Vec4f", EnginePrimitive::Vec4f) + .value("Int", EnginePrimitive::Int32) + .value("Vec2i", EnginePrimitive::Vec2i) + .value("Vec3i", EnginePrimitive::Vec3i) + .value("Vec4i", EnginePrimitive::Vec4i) + .value("Array", EnginePrimitive::Array); m.def("load", [](std::string path) { if (app->activeRaCoProject().undoStack()->depth() > 0) { @@ -666,7 +735,7 @@ PYBIND11_EMBEDDED_MODULE(raco, m) { } }); - m.def("export", [](std::string ramsesExport, bool compress, raco::application::ELuaSavingMode luaSavingMode) { + m.def("export", [](std::string ramsesExport, bool compress, application::ELuaSavingMode luaSavingMode) { std::string outError; if (!app->exportProject(ramsesExport, compress, outError, false, luaSavingMode)) { throw std::runtime_error(fmt::format(("Export failed: {}", outError))); @@ -871,6 +940,114 @@ PYBIND11_EMBEDDED_MODULE(raco, m) { app->activeRaCoProject().commandInterface()->setRenderableTags(handle, renderables); app->doOneLoop(); } + }) + .def("getAnimationTimeStamps", [](core::SEditorObject obj) -> py::object { + checkTypedObject(obj); + auto channel = obj->as(); + if (channel->currentSamplerData_) { + return py::cast(channel->currentSamplerData_->timeStamps); + } + return py::none(); + }) + .def("getAnimationOutputData", [](core::SEditorObject obj) -> py::object { + checkTypedObject(obj); + auto channel = obj->as(); + if (channel->currentSamplerData_) { + return std::visit( + overloaded{[](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(data.keyFrames, data.tangentsIn, data.tangentsOut)); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(glmToVector(data.keyFrames), glmToVector(data.tangentsIn), glmToVector(data.tangentsOut))); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(glmToVector(data.keyFrames), glmToVector(data.tangentsIn), glmToVector(data.tangentsOut))); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(glmToVector(data.keyFrames), glmToVector(data.tangentsIn), glmToVector(data.tangentsOut))); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(data.keyFrames, data.tangentsIn, data.tangentsOut)); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(glmToVector(data.keyFrames), glmToVector(data.tangentsIn), glmToVector(data.tangentsOut))); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(glmToVector(data.keyFrames), glmToVector(data.tangentsIn), glmToVector(data.tangentsOut))); + }, + [](const AnimationOutputData& data) -> py::object { + return py::cast(std::make_tuple(glmToVector(data.keyFrames), glmToVector(data.tangentsIn), glmToVector(data.tangentsOut))); + }, + [](const AnimationOutputData>& data) -> py::object { + return py::cast(std::make_tuple(data.keyFrames, data.tangentsIn, data.tangentsOut)); + }}, + channel->currentSamplerData_->output); + } + return py::none(); + }) + // Note: the int overloads before need to appear before the float overloads because pybind seems to pick + // the first matching one and for an all-int python list the float overload will match too. + // However to allow passing all-int python lists when settings float-type animation data we convert + // int -> float when the animation channel component type is a float type. + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector keyFrames) { + checkTypedObject(obj); + auto channel = obj->as(); + if (isIntegerComponentType(static_cast(*channel->componentType_))) { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames); + } else { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, toFloat(keyFrames)); + } + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector keyFrames, std::vector tangentsIn, std::vector tangentsOut) { + checkTypedObject(obj); + auto channel = obj->as(); + if (isIntegerComponentType(static_cast(*channel->componentType_))) { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames, tangentsIn, tangentsOut); + } else { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, toFloat(keyFrames), toFloat(tangentsIn), toFloat(tangentsOut)); + } + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector keyFrames) { + checkTypedObject(obj); + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames); + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector keyFrames, std::vector tangentsIn, std::vector tangentsOut) { + checkTypedObject(obj); + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames, tangentsIn, tangentsOut); + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector> keyFrames) { + checkTypedObject(obj); + auto channel = obj->as(); + if (isIntegerComponentType(static_cast(*channel->componentType_))) { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames); + } else { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, toFloat(keyFrames)); + } + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector> keyFrames, std::vector> tangentsIn, std::vector> tangentsOut) { + checkTypedObject(obj); + auto channel = obj->as(); + if (isIntegerComponentType(static_cast(*channel->componentType_))) { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames, tangentsIn, tangentsOut); + } else { + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, toFloat(keyFrames), toFloat(tangentsIn), toFloat(tangentsOut)); + } + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector> keyFrames) { + checkTypedObject(obj); + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames); + app->doOneLoop(); + }) + .def("setAnimationData", [](core::SEditorObject obj, std::vector timeStamps, std::vector> keyFrames, std::vector> tangentsIn, std::vector> tangentsOut) { + checkTypedObject(obj); + app->activeRaCoProject().commandInterface()->setAnimationData(obj, timeStamps, keyFrames, tangentsIn, tangentsOut); + app->doOneLoop(); }); py::class_(m, "LinkDescriptor") @@ -1010,6 +1187,10 @@ PYBIND11_EMBEDDED_MODULE(raco, m) { namespace raco::python_api { +std::string getPythonVersion() { + return Py_GetVersion(); +} + bool preparePythonEnvironment(std::wstring argv0, const std::vector& pythonSearchPaths, bool searchPythonFolderForTest) { PyPreConfig preconfig; PyPreConfig_InitIsolatedConfig(&preconfig); @@ -1020,7 +1201,6 @@ bool preparePythonEnvironment(std::wstring argv0, const std::vector& pythonSearchPaths, const std::vector& cmdLineArgs) { + // Setup environment + if (::appPath.empty() || ::pythonSearchPaths.empty()) { + ::appPath = racoAppPath; + ::pythonSearchPaths = pythonSearchPaths; + preparePythonEnvironment(racoAppPath, pythonSearchPaths); + } + + // Setup app + if (::app == nullptr) { + ::app = racoApp; + } + + // Interpreter + try { + // Initialize + std::vector pos_argv_cp; + for (auto& s : cmdLineArgs) { + pos_argv_cp.emplace_back(s.c_str()); + } + py::initialize_interpreter(true, static_cast(pos_argv_cp.size()), pos_argv_cp.data()); + + importRaCoModule(); + importCompleter(); + + setupDllLoadPath(); + } catch (...) { + return false; + } + return true; } -PythonRunStatus runPythonScript(application::RaCoApplication* app, const std::wstring& applicationPath, const std::string& pythonScriptPath, const std::vector& pythonSearchPaths, const std::vector& pos_argv_cp) { +void finalizeInterpreter() { + if (Py_IsInitialized()) { + py::finalize_interpreter(); + } +} + +PythonRunStatus runPythonScript(const std::string& pythonScript) { currentRunStatus.stdOutBuffer.clear(); currentRunStatus.stdErrBuffer.clear(); - if (python_api::preparePythonEnvironment(applicationPath, pythonSearchPaths)) { - py::scoped_interpreter pyGuard{true, static_cast(pos_argv_cp.size()), pos_argv_cp.data()}; - - python_api::setup(app); - currentRunStatus.stdOutBuffer.append(fmt::format("running python script {}\n\n", pythonScriptPath)); + try { + auto result = py::eval(pythonScript); + if (!result.is_none()) { + py::print(result); + } + } catch (py::error_already_set& e) { try { - py::eval_file(pythonScriptPath); + py::exec(pythonScript); } catch (py::error_already_set& e) { + auto what = std::string(e.what()); + if (e.matches(PyExc_SystemExit)) { auto exitCode = py::cast(e.value().attr("code")); currentRunStatus.stdErrBuffer.append(fmt::format("Exit called from Python: exit code '{}'\n", exitCode)); @@ -1130,9 +1387,36 @@ PythonRunStatus runPythonScript(application::RaCoApplication* app, const std::ws // need a test return currentRunStatus; } - } else { - currentRunStatus.stdErrBuffer.append("Failed to prepare the Python environment.\n"); + + return currentRunStatus; + } + + return currentRunStatus; +} + +PythonRunStatus runPythonScriptFromFile(const std::string& pythonScriptPath) { + currentRunStatus.stdOutBuffer.clear(); + currentRunStatus.stdErrBuffer.clear(); + + try { + py::eval_file(pythonScriptPath); + } catch (py::error_already_set& e) { + if (e.matches(PyExc_SystemExit)) { + auto exitCode = py::cast(e.value().attr("code")); + currentRunStatus.stdErrBuffer.append(fmt::format("Exit called from Python: exit code '{}'\n", exitCode)); + currentRunStatus.exitCode = py::cast(e.value().attr("code")); + return currentRunStatus; + } else { + currentRunStatus.stdErrBuffer.append(fmt::format("Python exception:\n{}", e.what())); + currentRunStatus.exitCode = 1; + return currentRunStatus; + } + } catch (std::exception& e) { + currentRunStatus.stdErrBuffer.append(fmt::format("Error thrown in Python script:\n{}", e.what())); currentRunStatus.exitCode = 1; + // TODO exit code + // how do we get here? + // need a test return currentRunStatus; } currentRunStatus.exitCode = 0; @@ -1140,4 +1424,34 @@ PythonRunStatus runPythonScript(application::RaCoApplication* app, const std::ws return currentRunStatus; } +std::vector getCompletions(const std::string& prefix) { + const auto code = R"( +matches = [completer.complete('__prefix__', i) for i in range(100)] +matches = [m for m in matches if m is not None] +)"; + + const auto formattedCode = std::regex_replace(code, std::regex("__prefix__"), prefix); + const auto globalNamespace = py::globals(); + + try { + py::exec(formattedCode, globalNamespace); + const auto matches = globalNamespace["matches"].cast>(); + return matches; + } catch (const py::error_already_set &e) { + } + + return std::vector(); +} + +bool isCompleteCommand(const std::string& command) { + try { + const py::module code = py::module::import("code"); + const py::object result = code.attr("compile_command")(command); + return !result.is_none(); + } + catch(...) { + return false; + } +} + } // namespace raco::python_api diff --git a/components/libPythonAPI/tests/PythonAPI_Simple_test.cpp b/components/libPythonAPI/tests/PythonAPI_Simple_test.cpp index b978ed18..05fcef4d 100644 --- a/components/libPythonAPI/tests/PythonAPI_Simple_test.cpp +++ b/components/libPythonAPI/tests/PythonAPI_Simple_test.cpp @@ -8,12 +8,6 @@ * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#if defined(WIN32) && defined(_DEBUG) && defined(PYTHON_DEBUG_LIBRARY_AVAILABLE) -// Needed to avoid pybind11/embed.h to cause linking to the non-debug DLL if the debug DLL is available. -// See https://github.com/pybind/pybind11/issues/3403#issuecomment-962878324 -#define Py_DEBUG -#endif - #include #include @@ -37,7 +31,8 @@ class PythonTest : public RaCoApplicationTest { PythonTest() : RaCoApplicationTest() { python_api::preparePythonEnvironment(QCoreApplication::applicationFilePath().toStdWString(), {}, true); pyGuard = std::make_unique(); - python_api::setup(&application); + raco::python_api::setApp(&application); + raco::python_api::importRaCoModule(); } std::unique_ptr pyGuard; @@ -262,4 +257,4 @@ with raco.compositeCommand("test"): EXPECT_THROW(py::exec(script), std::runtime_error); auto end_index = application.activeRaCoProject().undoStack()->getIndex(); EXPECT_EQ(start_index, end_index); -} \ No newline at end of file +} diff --git a/components/libRamsesBase/include/ramses_adaptor/AbstractSceneAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/AbstractSceneAdaptor.h index 7defd8f2..6a067dc3 100644 --- a/components/libRamsesBase/include/ramses_adaptor/AbstractSceneAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/AbstractSceneAdaptor.h @@ -169,8 +169,6 @@ class AbstractSceneAdaptor : public QObject { bool adaptorStatusDirty_ = false; - std::vector dependencyGraph_; - ramses_base::RamsesPerspectiveCamera camera_; ramses_base::RamsesRenderGroup renderGroup_; ramses_base::RamsesRenderPass renderPass_; diff --git a/components/libRamsesBase/include/ramses_adaptor/AnimationChannelAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/AnimationChannelAdaptor.h index 036e2155..031aeed9 100644 --- a/components/libRamsesBase/include/ramses_adaptor/AnimationChannelAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/AnimationChannelAdaptor.h @@ -17,9 +17,9 @@ namespace raco::ramses_adaptor { -class AnimationChannelAdaptor final : public UserTypeObjectAdaptor { +class AnimationChannelAdaptor final : public UserTypeObjectAdaptor { public: - explicit AnimationChannelAdaptor(SceneAdaptor* sceneAdaptor, user_types::SAnimationChannel channel); + explicit AnimationChannelAdaptor(SceneAdaptor* sceneAdaptor, user_types::SAnimationChannelBase channel); bool sync(core::Errors* errors) override; @@ -29,7 +29,7 @@ class AnimationChannelAdaptor final : public UserTypeObjectAdaptor subscriptions_; + std::array subscriptions_; components::Subscription previewDirtySubscription_; }; diff --git a/components/libRamsesBase/include/ramses_adaptor/CubeMapAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/CubeMapAdaptor.h index fb31ff4d..df1da038 100644 --- a/components/libRamsesBase/include/ramses_adaptor/CubeMapAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/CubeMapAdaptor.h @@ -9,9 +9,9 @@ */ #pragma once +#include "components/DataChangeDispatcher.h" #include "core/Handles.h" #include "ramses_adaptor/ObjectAdaptor.h" -#include "components/DataChangeDispatcher.h" #include "user_types/CubeMap.h" #include #include @@ -28,7 +28,6 @@ class CubeMapAdaptor : public TypedObjectAdaptor subscriptions_; @@ -37,4 +36,4 @@ class CubeMapAdaptor : public TypedObjectAdaptor> generateMipmapData(core::Errors* errors, int level, ramses_base::PngDecodingInfo& decodingInfo); }; -}; // namespace raco::ramses_adaptor \ No newline at end of file +}; // namespace raco::ramses_adaptor \ No newline at end of file diff --git a/components/libRamsesBase/include/ramses_adaptor/DefaultRamsesObjects.h b/components/libRamsesBase/include/ramses_adaptor/DefaultRamsesObjects.h index 97f2818c..f71002fd 100644 --- a/components/libRamsesBase/include/ramses_adaptor/DefaultRamsesObjects.h +++ b/components/libRamsesBase/include/ramses_adaptor/DefaultRamsesObjects.h @@ -27,6 +27,10 @@ static constexpr const char* defaultNormalDataBufferName = "ramses_adaptor::Defa static constexpr const char* defaultRenderGroupName = "ramses_adaptor::DefaultRenderGroup"; static constexpr const char* defaultRenderPassName = "ramses_adaptor::DefaultRenderPass"; static constexpr const char* defaultGizmoArrowName = "ramses_adaptor::DefaultGizmoArrow"; +static constexpr const char* defaultTexture2DName = "ramses_adaptor::DefaultTexture2D"; +static constexpr const char* defaultTextureCubeName = "ramses_adaptor::DefaultTextureCube"; +static constexpr const char* defaultTextureSamplerName = "ramses_adaptor::DefaultTextureSampler"; +static constexpr const char* defaultTextureCubeSamplerName = "ramses_adaptor::DefaultTextureCubeSampler"; ramses_base::RamsesAppearance createDefaultAppearance(ramses::Scene* scene, bool withNormals, bool highlight, bool transparent); @@ -41,6 +45,12 @@ ramses_base::RamsesArrayResource createCatNormalDataBuffer(ramses::Scene* scene) ramses_base::RamsesArrayResource createQuadVertexDataBuffer(ramses::Scene* scene); ramses_base::RamsesArrayResource createQuadIndexDataBuffer(ramses::Scene* scene); +ramses_base::RamsesTextureSampler createDefaultTextureSampler(ramses::Scene* scene); +ramses_base::RamsesTextureSampler createDefaultTextureCubeSampler(ramses::Scene* scene); + +ramses_base::RamsesTexture2D createDefaultTexture2D(bool flipped, ramses::Scene* scene); +ramses_base::RamsesTextureCube createDefaultTextureCube(ramses::Scene* scene, bool generateMipChain); + struct RamsesGizmoMeshBuffers { ramses_base::RamsesArrayResource indices; ramses_base::RamsesArrayResource vertices; diff --git a/components/libRamsesBase/include/ramses_adaptor/LinkAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/LinkAdaptor.h index b5f826ec..22d9b233 100644 --- a/components/libRamsesBase/include/ramses_adaptor/LinkAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/LinkAdaptor.h @@ -37,11 +37,17 @@ class LinkAdaptor { void lift(); void connect(); - void readDataFromEngine(core::DataChangeRecorder &recorder); + /** + * @brief Read back data from the Ramses property for the link endpoint and update the Raco data model. + * @param recorder Change recorder to use for collecting actually changed properties. + * @return Returns true if some value was changed in Raco data model. + */ + bool readDataFromEngine(core::DataChangeRecorder& recorder); protected: void connectHelper(const core::ValueHandle& start, const core::ValueHandle& end, bool isWeak); - void readFromEngineRecursive(core::DataChangeRecorder& recorder, const core::ValueHandle& property); + + bool readFromEngineRecursive(core::DataChangeRecorder& recorder, const core::ValueHandle& property); SceneAdaptor* sceneAdaptor_; core::LinkDescriptor editorLink_; diff --git a/components/libRamsesBase/include/ramses_adaptor/RenderBufferAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/RenderBufferAdaptor.h index 0ed3745b..8342aaae 100644 --- a/components/libRamsesBase/include/ramses_adaptor/RenderBufferAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/RenderBufferAdaptor.h @@ -16,19 +16,25 @@ namespace raco::ramses_adaptor { - class RenderBufferAdaptor : public TypedObjectAdaptor { - public: - explicit RenderBufferAdaptor(SceneAdaptor* sceneAdaptor, std::shared_ptr editorObject); +class RenderBufferAdaptor : public TypedObjectAdaptor, public ILogicPropertyProvider { +public: + explicit RenderBufferAdaptor(SceneAdaptor* sceneAdaptor, std::shared_ptr editorObject); - bool sync(core::Errors* errors) override; - std::vector getExportInformation() const override; + bool sync(core::Errors* errors) override; + std::vector getExportInformation() const override; - ramses_base::RamsesRenderBuffer buffer() const; + ramses_base::RamsesRenderBuffer buffer() const; - private: - ramses_base::RamsesRenderBuffer buffer_; + void getLogicNodes(std::vector& logicNodes) const override; + ramses::Property* getProperty(const std::vector& propertyNamesVector) override; + void onRuntimeError(core::Errors& errors, std::string const& message, core::ErrorLevel level) override; - std::array subscriptions_; - }; +private: + ramses_base::RamsesRenderBuffer buffer_; -}; \ No newline at end of file + ramses_base::RamsesRenderBufferBinding binding_; + + std::array subscriptions_; +}; + +}; // namespace raco::ramses_adaptor \ No newline at end of file diff --git a/components/libRamsesBase/include/ramses_adaptor/RenderBufferMSAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/RenderBufferMSAdaptor.h index 06ee324d..5cecca35 100644 --- a/components/libRamsesBase/include/ramses_adaptor/RenderBufferMSAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/RenderBufferMSAdaptor.h @@ -16,19 +16,25 @@ namespace raco::ramses_adaptor { - class RenderBufferMSAdaptor : public TypedObjectAdaptor { - public: - explicit RenderBufferMSAdaptor(SceneAdaptor* sceneAdaptor, std::shared_ptr editorObject); +class RenderBufferMSAdaptor : public TypedObjectAdaptor, public ILogicPropertyProvider { +public: + explicit RenderBufferMSAdaptor(SceneAdaptor* sceneAdaptor, std::shared_ptr editorObject); - bool sync(core::Errors* errors) override; - std::vector getExportInformation() const override; + bool sync(core::Errors* errors) override; + std::vector getExportInformation() const override; - ramses_base::RamsesRenderBuffer buffer() const; + ramses_base::RamsesRenderBuffer buffer() const; - private: - ramses_base::RamsesRenderBuffer buffer_; + void getLogicNodes(std::vector& logicNodes) const override; + ramses::Property* getProperty(const std::vector& propertyNamesVector) override; + void onRuntimeError(core::Errors& errors, std::string const& message, core::ErrorLevel level) override; - std::array subscriptions_; - }; +private: + ramses_base::RamsesRenderBuffer buffer_; -}; \ No newline at end of file + ramses_base::RamsesRenderBufferBinding binding_; + + std::array subscriptions_; +}; + +}; // namespace raco::ramses_adaptor \ No newline at end of file diff --git a/components/libRamsesBase/include/ramses_adaptor/SceneAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/SceneAdaptor.h index 5c89657d..7f664601 100644 --- a/components/libRamsesBase/include/ramses_adaptor/SceneAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/SceneAdaptor.h @@ -11,7 +11,6 @@ #include "core/Context.h" #include "ramses_adaptor/LinkAdaptor.h" -//#include "ramses_base/LogicEngine.h" #include "ramses_base/RamsesHandles.h" #include "ramses_base/BaseEngineBackend.h" #include "ramses_adaptor/utilities.h" @@ -46,7 +45,7 @@ class SceneAdaptor { const SRamsesAdaptorDispatcher dispatcher() const; const ramses_base::RamsesAppearance defaultAppearance(bool withMeshNormals); const ramses_base::RamsesArrayResource defaultVertices(int index); - const ramses_base::RamsesArrayResource defaultNormals(int index); + const ramses_base::RamsesArrayResource defaultNormals(int index); const ramses_base::RamsesArrayResource defaultIndices(int index); ObjectAdaptor* lookupAdaptor(const core::SEditorObject& editorObject) const; Project& project() const; @@ -57,7 +56,7 @@ class SceneAdaptor { } /* END: Adaptor API */ - void readDataFromEngine(core::DataChangeRecorder &recorder); + void readDataFromEngine(core::DataChangeRecorder& recorder); void iterateAdaptors(std::function func); @@ -67,6 +66,10 @@ class SceneAdaptor { void updateRuntimeError(const ramses::Issue& issue); void clearRuntimeError(); + const ramses_base::RamsesTextureSampler defaultTextureSampler(); + const ramses_base::RamsesTextureSampler defaultTextureCubeSampler(); + + const std::vector& dependencyGraph(); private: bool needAdaptor(SEditorObject object); @@ -80,7 +83,6 @@ class SceneAdaptor { void rebuildSortedDependencyGraph(SEditorObjectSet const& objects); - void deleteUnusedDefaultResources(); ramses::RamsesClient* client_; @@ -95,13 +97,15 @@ class SceneAdaptor { // Fallback resources: used when MeshNode doesn't have valid shader program or mesh data ramses_base::RamsesAppearance defaultAppearance_; ramses_base::RamsesAppearance defaultAppearanceWithNormals_; + ramses_base::RamsesTextureSampler defaultTextureSampler_; + ramses_base::RamsesTextureSampler defaultTextureCubeSampler_; std::array defaultIndices_; std::array defaultVertices_; std::array defaultNormals_; std::map> adaptors_{}; - + struct LinkAdaptorContainer { std::map> linksByStart_{}; std::map> linksByEnd_{}; diff --git a/components/libRamsesBase/include/ramses_adaptor/SceneBackend.h b/components/libRamsesBase/include/ramses_adaptor/SceneBackend.h index af444633..4badb429 100644 --- a/components/libRamsesBase/include/ramses_adaptor/SceneBackend.h +++ b/components/libRamsesBase/include/ramses_adaptor/SceneBackend.h @@ -57,6 +57,8 @@ class SceneBackend : public core::SceneBackendInterface { ramses::LogicEngine* logicEngine() const; + std::map getPerformanceReport(); + static bool discardRamsesMessage(std::string_view message); private: diff --git a/components/libRamsesBase/include/ramses_adaptor/TextureSamplerAdaptor.h b/components/libRamsesBase/include/ramses_adaptor/TextureSamplerAdaptor.h index c1aaac95..d19b02c6 100644 --- a/components/libRamsesBase/include/ramses_adaptor/TextureSamplerAdaptor.h +++ b/components/libRamsesBase/include/ramses_adaptor/TextureSamplerAdaptor.h @@ -21,26 +21,19 @@ namespace raco::ramses_adaptor { class TextureSamplerAdaptor : public TypedObjectAdaptor { public: - static inline auto FALLBACK_TEXTURE_SIZE_PX = 256; - explicit TextureSamplerAdaptor(SceneAdaptor* sceneAdaptor, std::shared_ptr editorObject); bool sync(core::Errors* errors) override; std::vector getExportInformation() const override; - - static std::vector& getFallbackTextureData(bool flipped); + static void flipDecodedPicture(std::vector& rawPictureData, unsigned int availableChannels, unsigned int width, unsigned int height, unsigned int bitdepth); private: - ramses_base::RamsesTexture2D createTexture(core::Errors* errors, ramses_base::PngDecodingInfo &decodingInfo); - ramses_base::RamsesTexture2D getFallbackTexture(); - std::array subscriptions_; ramses_base::RamsesTexture2D textureData_; - static inline std::array, 2> fallbackTextureData_; + ramses_base::RamsesTexture2D createTexture(core::Errors* errors, ramses_base::PngDecodingInfo &decodingInfo); std::string createDefaultTextureDataName(); - static void flipDecodedPicture(std::vector& rawPictureData, unsigned int availableChannels, unsigned int width, unsigned int height, unsigned int bitdepth); }; }; // namespace raco::ramses_adaptor \ No newline at end of file diff --git a/components/libRamsesBase/include/ramses_adaptor/utilities.h b/components/libRamsesBase/include/ramses_adaptor/utilities.h index c3560f9b..065f019d 100644 --- a/components/libRamsesBase/include/ramses_adaptor/utilities.h +++ b/components/libRamsesBase/include/ramses_adaptor/utilities.h @@ -166,80 +166,82 @@ inline bool setLuaInputInEngine(ramses::Property* property, const core::ValueHan return success; } -void getOutputFromEngine(const ramses::Property& property, const core::ValueHandle& valueHandle, core::DataChangeRecorder& recorder); +bool getOutputFromEngine(const ramses::Property& property, const core::ValueHandle& valueHandle, core::DataChangeRecorder& recorder); -inline void getComplexLuaOutputFromEngine(const ramses::Property& property, const core::ValueHandle& valueHandle, core::DataChangeRecorder& recorder) { +inline bool getComplexLuaOutputFromEngine(const ramses::Property& property, const core::ValueHandle& valueHandle, core::DataChangeRecorder& recorder) { + bool changed = false; for (size_t i{0}; i < valueHandle.size(); i++) { if (property.getType() == ramses::EPropertyType::Array) { - getOutputFromEngine(*property.getChild(i), valueHandle[i], recorder); + changed = getOutputFromEngine(*property.getChild(i), valueHandle[i], recorder) || changed; } else { - getOutputFromEngine(*property.getChild(valueHandle[i].getPropName()), valueHandle[i], recorder); + changed = getOutputFromEngine(*property.getChild(valueHandle[i].getPropName()), valueHandle[i], recorder) || changed; } } + return changed; } -inline void getOutputFromEngine(const ramses::Property& property, const core::ValueHandle& valueHandle, core::DataChangeRecorder& recorder) { +inline bool getOutputFromEngine(const ramses::Property& property, const core::ValueHandle& valueHandle, core::DataChangeRecorder& recorder) { using core::PrimitiveType; // read quaternion rotation data if (valueHandle.isVec3f() && property.getType() == ramses::EPropertyType::Vec4f) { auto v = property.get().value(); auto [eulerX, eulerY, eulerZ] = utils::math::quaternionToXYZDegrees(v.x, v.y, v.z, v.w); - core::CodeControlledPropertyModifier::setVec3f(valueHandle, eulerX, eulerY, eulerZ, recorder); - return; + return core::CodeControlledPropertyModifier::setVec3f(valueHandle, eulerX, eulerY, eulerZ, recorder); } switch (valueHandle.type()) { case PrimitiveType::Double: { - core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); + return core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); break; } case PrimitiveType::Int: { - core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); + return core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); break; } case PrimitiveType::Int64: { - core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); + return core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); break; } case PrimitiveType::Bool: { - core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); + return core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); break; } case PrimitiveType::String: { - core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); + return core::CodeControlledPropertyModifier::setPrimitive(valueHandle, property.get().value(), recorder); break; } case PrimitiveType::Struct: { auto typeDesc = &valueHandle.constValueRef()->asStruct().getTypeDescription(); if (typeDesc == &core::Vec2f::typeDescription) { auto v = property.get().value(); - core::CodeControlledPropertyModifier::setVec2f(valueHandle, v.x, v.y, recorder); + return core::CodeControlledPropertyModifier::setVec2f(valueHandle, v.x, v.y, recorder); } else if (typeDesc == &core::Vec3f::typeDescription) { auto v = property.get().value(); - core::CodeControlledPropertyModifier::setVec3f(valueHandle, v.x, v.y, v.z, recorder); + return core::CodeControlledPropertyModifier::setVec3f(valueHandle, v.x, v.y, v.z, recorder); } else if (typeDesc == &core::Vec4f::typeDescription) { auto v = property.get().value(); - core::CodeControlledPropertyModifier::setVec4f(valueHandle, v.x, v.y, v.z, v.w, recorder); + return core::CodeControlledPropertyModifier::setVec4f(valueHandle, v.x, v.y, v.z, v.w, recorder); } else if (typeDesc == &core::Vec2i::typeDescription) { auto v = property.get().value(); - core::CodeControlledPropertyModifier::setVec2i(valueHandle, v.x, v.y, recorder); + return core::CodeControlledPropertyModifier::setVec2i(valueHandle, v.x, v.y, recorder); } else if (typeDesc == &core::Vec3i::typeDescription) { auto v = property.get().value(); - core::CodeControlledPropertyModifier::setVec3i(valueHandle, v.x, v.y, v.z, recorder); + return core::CodeControlledPropertyModifier::setVec3i(valueHandle, v.x, v.y, v.z, recorder); } else if (typeDesc == &core::Vec4i::typeDescription) { auto v = property.get().value(); - core::CodeControlledPropertyModifier::setVec4i(valueHandle, v.x, v.y, v.z, v.w, recorder); + return core::CodeControlledPropertyModifier::setVec4i(valueHandle, v.x, v.y, v.z, v.w, recorder); } else { - getComplexLuaOutputFromEngine(property, valueHandle, recorder); + return getComplexLuaOutputFromEngine(property, valueHandle, recorder); } break; } case PrimitiveType::Table: { - getComplexLuaOutputFromEngine(property, valueHandle, recorder); + return getComplexLuaOutputFromEngine(property, valueHandle, recorder); break; } } + return false; } inline ramses::EDepthWrite getDepthWriteMode(const ramses::Appearance* appearance) { diff --git a/components/libRamsesBase/include/ramses_base/EnumerationTranslations.h b/components/libRamsesBase/include/ramses_base/EnumerationTranslations.h index 94cfd6ff..d566abda 100644 --- a/components/libRamsesBase/include/ramses_base/EnumerationTranslations.h +++ b/components/libRamsesBase/include/ramses_base/EnumerationTranslations.h @@ -11,8 +11,11 @@ #include "user_types/Enumerations.h" +#include "core/MeshCacheInterface.h" + #include #include +#include #include #include @@ -33,5 +36,7 @@ extern std::map enumerationT extern std::map enumerationTranslationTextureAddressMode; extern std::map enumerationTranslationTextureSamplingMethod; +extern std::map enumerationTranslationAnimationInterpolationType; + } // namespace raco::ramses_base diff --git a/components/libRamsesBase/include/ramses_base/RamsesHandles.h b/components/libRamsesBase/include/ramses_base/RamsesHandles.h index 1c27c1ff..3204c768 100644 --- a/components/libRamsesBase/include/ramses_base/RamsesHandles.h +++ b/components/libRamsesBase/include/ramses_base/RamsesHandles.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -490,6 +491,8 @@ inline RamsesRenderBuffer ramsesRenderBuffer(ramses::Scene* scene, auto buffer{scene->createRenderBuffer(width, height, format, accessMode, sampleCount, name)}; if (buffer) { buffer->setUserId(objectID.first, objectID.second); + } else { + LOG_ERROR(log_system::RAMSES_ADAPTOR, "Ramses RenderBuffer creation for width = {}, height = {}, format = {}, accessMode = {}, sampleCount = {}, name = '{}' failed.", width, height, accessMode, sampleCount, name); } return {buffer, createRamsesObjectDeleter(scene)}; @@ -620,7 +623,10 @@ inline RamsesTextureSampler ramsesTextureSampler(ramses::Scene* scene, ramses::E auto sampler = scene->createTextureSampler(wrapUMode, wrapVMode, minSamplingMethod, magSamplingMethod, *texture, anisotropyLevel, name); if (sampler) { sampler->setUserId(objectID.first, objectID.second); + } else { + LOG_ERROR(log_system::RAMSES_ADAPTOR, "Ramses TextureSampler creation for name = '{}' failed.", name); } + return {sampler, [scene, forceCopy = texture](ramses::RamsesObject* obj) { if (!scene->destroy(*static_cast(obj))) { @@ -634,7 +640,10 @@ inline RamsesTextureSamplerMS ramsesTextureSamplerMS(ramses::Scene* scene, Ramse auto sampler = scene->createTextureSamplerMS(*buffer, name); if (sampler) { sampler->setUserId(objectID.first, objectID.second); + } else { + LOG_ERROR(log_system::RAMSES_ADAPTOR, "Ramses TextureSamplerMS creation for name = '{}' failed.", name); } + return { sampler, [scene, forceCopy = buffer](ramses::RamsesObject* buffer) { @@ -677,6 +686,8 @@ inline RamsesTexture2D ramsesTexture2D(ramses::Scene* scene, auto texture{scene->createTexture2D(format, width, height, mipLevelData, generateMipChain, swizzle, name)}; if (texture) { texture->setUserId(objectID.first, objectID.second); + } else { + LOG_ERROR(log_system::RAMSES_ADAPTOR, "Ramses TextureSampler2D creation for width = {}, height = {}, format = {}, name = '{}' failed.", width, height, format, name); } return {texture, createRamsesObjectDeleter(scene)}; @@ -732,7 +743,7 @@ using RamsesNodeBinding = std::shared_ptr; using RamsesCameraBinding = std::shared_ptr; using UniqueRamsesRenderPassBinding = std::unique_ptr>; using RamsesRenderGroupBinding = std::shared_ptr; - +using RamsesRenderBufferBinding = std::shared_ptr; inline RamsesAppearanceBinding ramsesAppearanceBinding(ramses::Appearance& appearance, ramses::LogicEngine* logicEngine, const std::string& name, const std::pair &objectID) { RamsesAppearanceBinding binding{logicEngine->createAppearanceBinding(appearance, name), @@ -989,5 +1000,18 @@ inline RamsesRenderGroupBinding ramsesRenderGroupBinding(ramses::LogicEngine* lo return binding; } +inline RamsesRenderBufferBinding ramsesRenderBufferBinding(RamsesRenderBuffer buffer, ramses::LogicEngine* logicEngine, const std::string& name, const std::pair& objectID) { + RamsesRenderBufferBinding binding{logicEngine->createRenderBufferBinding(*buffer, name), + [logicEngine, forceNodeCopy = buffer](ramses::RenderBufferBinding* binding) { + destroyLogicObject(logicEngine, binding); + }}; + + if (binding) { + binding->setUserId(objectID.first, objectID.second); + } + + return binding; +} + }; // namespace raco::ramses_base diff --git a/components/libRamsesBase/src/ramses_adaptor/AbstractSceneAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/AbstractSceneAdaptor.cpp index 21cf6610..6de610c3 100644 --- a/components/libRamsesBase/src/ramses_adaptor/AbstractSceneAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/AbstractSceneAdaptor.cpp @@ -169,7 +169,6 @@ void AbstractSceneAdaptor::createAdaptor(SEditorObject obj) { void AbstractSceneAdaptor::removeAdaptor(SEditorObject obj) { adaptors_.erase(obj); deleteUnusedDefaultResources(); - dependencyGraph_.clear(); if (gizmo_ && gizmo_->object() == obj) { gizmo_.reset(); } @@ -287,14 +286,9 @@ core::Project& AbstractSceneAdaptor::project() const { return *project_; } -void AbstractSceneAdaptor::rebuildSortedDependencyGraph(SEditorObjectSet const& objects) { - dependencyGraph_ = buildSortedDependencyGraph(objects); -} - void AbstractSceneAdaptor::performBulkEngineUpdate(const core::SEditorObjectSet& changedObjects) { if (adaptorStatusDirty_) { - for (const auto& item : dependencyGraph_) { - auto object = item.object; + for (const auto& object : project().instances()) { auto adaptor = lookupAdaptor(object); bool haveAdaptor = adaptor != nullptr; @@ -309,14 +303,10 @@ void AbstractSceneAdaptor::performBulkEngineUpdate(const core::SEditorObjectSet& adaptorStatusDirty_ = false; } - if (dependencyGraph_.empty() || !changedObjects.empty()) { - rebuildSortedDependencyGraph(SEditorObjectSet(project_->instances().begin(), project_->instances().end())); - } - renderGroup_->removeAllRenderables(); SEditorObjectSet updated; - for (const auto& item : dependencyGraph_) { + for (const auto& item : previewAdaptor_->dependencyGraph()) { auto object = item.object; if (auto adaptor = lookupAdaptor(object)) { bool needsUpdate = adaptor->isDirty(); @@ -336,7 +326,7 @@ void AbstractSceneAdaptor::performBulkEngineUpdate(const core::SEditorObjectSet& } } - for (const auto& item : dependencyGraph_) { + for (const auto& item : previewAdaptor_->dependencyGraph()) { auto object = item.object; if (auto adaptor = lookup(object)) { bool transparent = highlightUsingTransparency_ && !adaptor->highlighted(); diff --git a/components/libRamsesBase/src/ramses_adaptor/AnimationChannelAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/AnimationChannelAdaptor.cpp index ea1969fa..f04fdbc5 100644 --- a/components/libRamsesBase/src/ramses_adaptor/AnimationChannelAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/AnimationChannelAdaptor.cpp @@ -34,34 +34,13 @@ namespace raco::ramses_adaptor { using namespace raco::ramses_base; -AnimationChannelAdaptor::AnimationChannelAdaptor(SceneAdaptor* sceneAdaptor, user_types::SAnimationChannel channel) +AnimationChannelAdaptor::AnimationChannelAdaptor(SceneAdaptor* sceneAdaptor, user_types::SAnimationChannelBase channel) : UserTypeObjectAdaptor{sceneAdaptor, channel}, subscriptions_{ - sceneAdaptor->dispatcher()->registerOn(core::ValueHandle{editorObject_, &user_types::AnimationChannel::objectName_}, [this]() { tagDirty(); }), - sceneAdaptor->dispatcher()->registerOn(core::ValueHandle{editorObject_, &user_types::AnimationChannel::animationIndex_}, [this]() { tagDirty(); }), - sceneAdaptor->dispatcher()->registerOn(core::ValueHandle{editorObject_, &user_types::AnimationChannel::uri_}, [this]() { tagDirty(); }), - sceneAdaptor->dispatcher()->registerOn(core::ValueHandle{editorObject_, &user_types::AnimationChannel::samplerIndex_}, [this]() { tagDirty(); })}, + sceneAdaptor->dispatcher()->registerOn(core::ValueHandle{editorObject_, &user_types::AnimationChannel::objectName_}, [this]() { tagDirty(); })}, previewDirtySubscription_{sceneAdaptor->dispatcher()->registerOnPreviewDirty(editorObject_, [this]() { tagDirty(); })} { } -std::vector convert_vec3(const std::vector>& data) { - std::vector result; - for (size_t index = 0; index < data.size(); index++) { - const auto& v = data[index]; - result.emplace_back(glm::vec3(v[0], v[1], v[2])); - } - return result; -} - -std::vector convert_vec4(const std::vector>& data) { - std::vector result; - for (size_t index = 0; index < data.size(); index++) { - const auto& v = data[index]; - result.emplace_back(glm::vec4(v[0], v[1], v[2], v[3])); - } - return result; -} - bool AnimationChannelAdaptor::sync(core::Errors* errors) { ObjectAdaptor::sync(errors); handle_.reset(); @@ -73,33 +52,13 @@ bool AnimationChannelAdaptor::sync(core::Errors* errors) { handle_->name = editorObject_->objectName(); handle_->keyframeTimes = ramsesDataArray(animSampler->timeStamps, &sceneAdaptor_->logicEngine(), handle_->name + ".timestamps", objectID); - std::map interpolationTypeMap = { - {core::MeshAnimationInterpolation::Linear, ramses::EInterpolationType::Linear}, - {core::MeshAnimationInterpolation::CubicSpline, ramses::EInterpolationType::Cubic}, - {core::MeshAnimationInterpolation::Step, ramses::EInterpolationType::Step}, - {core::MeshAnimationInterpolation::Linear_Quaternion, ramses::EInterpolationType::Linear_Quaternions}, - {core::MeshAnimationInterpolation::CubicSpline_Quaternion, ramses::EInterpolationType::Cubic_Quaternions} - }; - - handle_->interpolationType = interpolationTypeMap.at(animSampler->interpolation); - - switch (animSampler->componentType) { - case core::EnginePrimitive::Array: { - // Morph target weights - createRamsesDataArrays(handle_, &sceneAdaptor_->logicEngine(), animSampler->tangentsIn, animSampler->keyFrames, animSampler->tangentsOut, objectID); - break; - } - case core::EnginePrimitive::Vec3f: { - createRamsesDataArrays(handle_, &sceneAdaptor_->logicEngine(), convert_vec3(animSampler->tangentsIn), convert_vec3(animSampler->keyFrames), convert_vec3(animSampler->tangentsOut), objectID); - break; - } - case core::EnginePrimitive::Vec4f: { - createRamsesDataArrays(handle_, &sceneAdaptor_->logicEngine(), convert_vec4(animSampler->tangentsIn), convert_vec4(animSampler->keyFrames), convert_vec4(animSampler->tangentsOut), objectID); - break; - } - default: - assert(false); - } + handle_->interpolationType = ramses_base::enumerationTranslationAnimationInterpolationType.at(animSampler->interpolation); + + std::visit( + [this, objectID](const auto& data) { + createRamsesDataArrays(handle_, &sceneAdaptor_->logicEngine(), data.tangentsIn, data.keyFrames, data.tangentsOut, objectID); + }, + animSampler->output); } tagDirty(false); diff --git a/components/libRamsesBase/src/ramses_adaptor/CubeMapAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/CubeMapAdaptor.cpp index 70dbce46..2ca2627f 100644 --- a/components/libRamsesBase/src/ramses_adaptor/CubeMapAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/CubeMapAdaptor.cpp @@ -10,6 +10,7 @@ #include "ramses_adaptor/CubeMapAdaptor.h" #include "core/CoreFormatter.h" #include "lodepng.h" +#include "ramses_adaptor/DefaultRamsesObjects.h" #include "ramses_adaptor/SceneAdaptor.h" #include "ramses_adaptor/TextureSamplerAdaptor.h" #include "ramses_base/RamsesHandles.h" @@ -57,7 +58,7 @@ CubeMapAdaptor::CubeMapAdaptor(SceneAdaptor* sceneAdaptor, std::shared_ptrmipmapLevel_ < 1 || *editorObject()->mipmapLevel_ > 4) { - return fallbackCube(); + return createDefaultTextureCube(sceneAdaptor_->scene(), *editorObject()->generateMipmaps_); } std::vector>> rawMipDatas; @@ -73,7 +74,7 @@ ramses_base::RamsesTextureCube CubeMapAdaptor::createTexture(core::Errors* error } if (!mipMapsOk) { - return fallbackCube(); + return createDefaultTextureCube(sceneAdaptor_->scene(), *editorObject()->generateMipmaps_); } for (auto& mipData : rawMipDatas) { @@ -104,28 +105,6 @@ ramses_base::RamsesTextureCube CubeMapAdaptor::createTexture(core::Errors* error return ramses_base::ramsesTextureCube(sceneAdaptor_->scene(), ramsesFormat, decodingInfo.width, mipDatas, *editorObject()->generateMipmaps_, {}, {}, editorObject()->objectIDAsRamsesLogicID()); } -ramses_base::RamsesTextureCube CubeMapAdaptor::fallbackCube() { - std::map> data; - - data["uriRight"] = TextureSamplerAdaptor::getFallbackTextureData(false); - data["uriLeft"] = TextureSamplerAdaptor::getFallbackTextureData(false); - data["uriTop"] = TextureSamplerAdaptor::getFallbackTextureData(false); - data["uriBottom"] = TextureSamplerAdaptor::getFallbackTextureData(false); - data["uriFront"] = TextureSamplerAdaptor::getFallbackTextureData(false); - data["uriBack"] = TextureSamplerAdaptor::getFallbackTextureData(false); - - std::vector mipDatas; - mipDatas.emplace_back(ramses::CubeMipLevelData{ - {reinterpret_cast(data["uriRight"].data()), reinterpret_cast(data["uriRight"].data()) + data["uriRight"].size()}, - {reinterpret_cast(data["uriLeft"].data()), reinterpret_cast(data["uriLeft"].data()) + data["uriLeft"].size()}, - {reinterpret_cast(data["uriTop"].data()), reinterpret_cast(data["uriTop"].data()) + data["uriTop"].size()}, - {reinterpret_cast(data["uriBottom"].data()), reinterpret_cast(data["uriBottom"].data()) + data["uriBottom"].size()}, - {reinterpret_cast(data["uriFront"].data()), reinterpret_cast(data["uriFront"].data()) + data["uriFront"].size()}, - {reinterpret_cast(data["uriBack"].data()), reinterpret_cast(data["uriBack"].data()) + data["uriBack"].size()}}); - - return ramses_base::ramsesTextureCube(sceneAdaptor_->scene(), ramses::ETextureFormat::RGBA8, TextureSamplerAdaptor::FALLBACK_TEXTURE_SIZE_PX, mipDatas, *editorObject()->generateMipmaps_, {}, {}, editorObject()->objectIDAsRamsesLogicID()); -} - std::string CubeMapAdaptor::createDefaultTextureDataName() { return this->editorObject()->objectName() + "_TextureCube"; } @@ -134,9 +113,16 @@ std::map> CubeMapAdaptor::generateMipmap std::map> data; auto mipmapOk = true; - for (const std::string &propName : {"uriRight", "uriLeft", "uriTop", "uriBottom", "uriFront", "uriBack", }) { + for (const std::string& propName : { + "uriRight", + "uriLeft", + "uriTop", + "uriBottom", + "uriFront", + "uriBack", + }) { auto uriPropName = (level > 1) ? fmt::format("level{}{}", level, propName) : propName; - data[propName] = ramses_base::decodeMipMapData(errors, sceneAdaptor_->project(), editorObject(), uriPropName, level, decodingInfo); + data[propName] = decodeMipMapData(errors, sceneAdaptor_->project(), editorObject(), uriPropName, level, decodingInfo); if (data[propName].empty()) { mipmapOk = false; @@ -204,4 +190,4 @@ std::vector CubeMapAdaptor::getExportInformation() const { return result; } -} // namespace raco::ramses_adaptor +} // namespace raco::ramses_adaptor \ No newline at end of file diff --git a/components/libRamsesBase/src/ramses_adaptor/DefaultRamsesObjects.cpp b/components/libRamsesBase/src/ramses_adaptor/DefaultRamsesObjects.cpp index 1568cec5..a66a8d3f 100644 --- a/components/libRamsesBase/src/ramses_adaptor/DefaultRamsesObjects.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/DefaultRamsesObjects.cpp @@ -10,10 +10,14 @@ #include "ramses_adaptor/DefaultRamsesObjects.h" +#include "lodepng.h" #include "ramses_adaptor/utilities.h" +#include "ramses_base/RamsesHandles.h" #include "core/MeshCacheInterface.h" #include "mesh_loader/glTFFileLoader.h" +#include "ramses_adaptor/CubeMapAdaptor.h" +#include "ramses_adaptor/TextureSamplerAdaptor.h" namespace raco::ramses_adaptor { @@ -871,4 +875,76 @@ ramses_base::RamsesArrayResource createCatIndexDataBuffer(ramses::Scene* scene) return ramses_base::ramsesArrayResource(scene, cat_indices_data, defaultIndexDataBufferName); } +std::vector getFallbackTextureData(bool flipped, unsigned int &outWidth, unsigned int &outHeight) { + std::vector textureData; + QFile file(":fallbackTextureOpenGL"); + if (file.exists()) { + auto size = file.size(); + file.open(QIODevice::ReadOnly); + QDataStream in(&file); + std::vector sBuffer(size); + + for (auto i = 0; i < size; ++i) { + in >> sBuffer[i]; + } + + file.close(); + + lodepng::decode(textureData, outWidth, outHeight, sBuffer); + + if (flipped) { + TextureSamplerAdaptor::flipDecodedPicture(textureData, 4, outWidth, outHeight, 8); + } + } + + return textureData; +} + +ramses_base::RamsesTextureSampler createDefaultTextureSampler(ramses::Scene* scene) { + const auto texture = createDefaultTexture2D(false, scene); + const auto sampler = ramses_base::ramsesTextureSampler(scene, ramses::ETextureAddressMode::Repeat, ramses::ETextureAddressMode::Repeat, ramses::ETextureSamplingMethod::Linear, ramses::ETextureSamplingMethod::Linear, texture, 1, defaultTextureSamplerName, {0, 0}); + return sampler; +} +ramses_base::RamsesTextureSampler createDefaultTextureCubeSampler(ramses::Scene* scene) { + const auto textureCube = createDefaultTextureCube(scene, true); + const auto textureSampler = ramses_base::ramsesTextureSampler(scene, ramses::ETextureAddressMode::Repeat, ramses::ETextureAddressMode::Repeat, ramses::ETextureSamplingMethod::Linear, ramses::ETextureSamplingMethod::Linear, textureCube, 1, defaultTextureCubeSamplerName, {0, 0}); + return textureSampler; +} + +ramses_base::RamsesTexture2D createDefaultTexture2D(bool flipped, ramses::Scene* scene) { + unsigned int width; + unsigned int height; + auto data = getFallbackTextureData(flipped, width, height); + std::vector mipDatas; + mipDatas.emplace_back(reinterpret_cast(data.data()), reinterpret_cast(data.data()) + data.size()); + ramses_base::RamsesTexture2D texture = ramses_base::ramsesTexture2D(scene, ramses::ETextureFormat::RGBA8, width, height, mipDatas, false, {}, defaultTexture2DName, {}); + return texture; +} + +ramses_base::RamsesTextureCube createDefaultTextureCube(ramses::Scene* scene, bool generateMipChain) { + std::map> data; + + unsigned int width; + unsigned int height; + const auto fallbackImage = getFallbackTextureData(false, width, height); + + data["uriRight"] = fallbackImage; + data["uriLeft"] = fallbackImage; + data["uriTop"] = fallbackImage; + data["uriBottom"] = fallbackImage; + data["uriFront"] = fallbackImage; + data["uriBack"] = fallbackImage; + + std::vector mipDatas; + mipDatas.emplace_back(ramses::CubeMipLevelData{ + {reinterpret_cast(data["uriRight"].data()), reinterpret_cast(data["uriRight"].data()) + data["uriRight"].size()}, + {reinterpret_cast(data["uriLeft"].data()), reinterpret_cast(data["uriLeft"].data()) + data["uriLeft"].size()}, + {reinterpret_cast(data["uriTop"].data()), reinterpret_cast(data["uriTop"].data()) + data["uriTop"].size()}, + {reinterpret_cast(data["uriBottom"].data()), reinterpret_cast(data["uriBottom"].data()) + data["uriBottom"].size()}, + {reinterpret_cast(data["uriFront"].data()), reinterpret_cast(data["uriFront"].data()) + data["uriFront"].size()}, + {reinterpret_cast(data["uriBack"].data()), reinterpret_cast(data["uriBack"].data()) + data["uriBack"].size()}}); + + return ramses_base::ramsesTextureCube(scene, ramses::ETextureFormat::RGBA8,width, mipDatas, generateMipChain, {}, defaultTextureCubeName, {}); +} + } // namespace raco::ramses_adaptor \ No newline at end of file diff --git a/components/libRamsesBase/src/ramses_adaptor/Factories.cpp b/components/libRamsesBase/src/ramses_adaptor/Factories.cpp index c3d5135e..3be0a60c 100644 --- a/components/libRamsesBase/src/ramses_adaptor/Factories.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/Factories.cpp @@ -38,9 +38,11 @@ #include "ramses_adaptor/AbstractMeshNodeAdaptor.h" #include "ramses_adaptor/AbstractNodeAdaptor.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/CubeMap.h" #include "user_types/Texture.h" #include "user_types/PrefabInstance.h" + #include #include #include @@ -64,7 +66,10 @@ UniqueObjectAdaptor Factories::createAdaptor(SceneAdaptor* sceneAdaptor, core::S // RESOURCES {user_types::Animation::typeDescription.typeName, [](SceneAdaptor* sceneAdaptor, core::SEditorObject obj) { return std::make_unique(sceneAdaptor, std::dynamic_pointer_cast(obj)); }}, + {user_types::AnimationChannel::typeDescription.typeName, [](SceneAdaptor* sceneAdaptor, core::SEditorObject obj) { return std::make_unique(sceneAdaptor, std::dynamic_pointer_cast(obj)); }}, + {user_types::AnimationChannelRaco::typeDescription.typeName, [](SceneAdaptor* sceneAdaptor, core::SEditorObject obj) { return std::make_unique(sceneAdaptor, std::dynamic_pointer_cast(obj)); }}, + {user_types::Material::typeDescription.typeName, [](SceneAdaptor* sceneAdaptor, core::SEditorObject obj) { return std::make_unique(sceneAdaptor, std::dynamic_pointer_cast(obj)); }}, {user_types::Mesh::typeDescription.typeName, [](SceneAdaptor* sceneAdaptor, core::SEditorObject obj) { return std::make_unique(sceneAdaptor, std::dynamic_pointer_cast(obj)); }}, {user_types::Texture::typeDescription.typeName, [](SceneAdaptor* sceneAdaptor, core::SEditorObject obj) { return std::make_unique(sceneAdaptor, std::dynamic_pointer_cast(obj)); }}, diff --git a/components/libRamsesBase/src/ramses_adaptor/LinkAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/LinkAdaptor.cpp index b0b6595d..010ed481 100644 --- a/components/libRamsesBase/src/ramses_adaptor/LinkAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/LinkAdaptor.cpp @@ -121,26 +121,29 @@ void LinkAdaptor::connect() { } } -void LinkAdaptor::readFromEngineRecursive(core::DataChangeRecorder& recorder, const core::ValueHandle& property) { +bool LinkAdaptor::readFromEngineRecursive(core::DataChangeRecorder& recorder, const core::ValueHandle& property) { + bool changed = false; if (property) { if (!core::Queries::isEnginePrimitive(property)) { for (size_t index = 0; index < property.size(); index++) { - readFromEngineRecursive(recorder, property[index]); + changed = readFromEngineRecursive(recorder, property[index]) || changed; } } else { if (auto adaptor = sceneAdaptor_->lookupAdaptor(property.rootObject())) { if (auto engineProp = dynamic_cast(adaptor)->getProperty(property.getPropertyNamesVector())) { - getOutputFromEngine(*engineProp, property, recorder); + changed = getOutputFromEngine(*engineProp, property, recorder) || changed; } } } } + return changed; } -void LinkAdaptor::readDataFromEngine(core::DataChangeRecorder& recorder) { +bool LinkAdaptor::readDataFromEngine(core::DataChangeRecorder& recorder) { if (editorLink_.isValid) { - readFromEngineRecursive(recorder, core::ValueHandle(editorLink_.end)); + return readFromEngineRecursive(recorder, core::ValueHandle(editorLink_.end)); } + return false; } } // namespace raco::ramses_adaptor diff --git a/components/libRamsesBase/src/ramses_adaptor/MaterialAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/MaterialAdaptor.cpp index ae1b43b9..00884967 100644 --- a/components/libRamsesBase/src/ramses_adaptor/MaterialAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/MaterialAdaptor.cpp @@ -152,9 +152,9 @@ std::vector getArrayData(const core::ValueHandle& handle) { inline void setUniform(core::Errors* errors, SceneAdaptor* sceneAdaptor, ramses::Appearance* appearance, const core::ValueHandle& valueHandle, const std::string& uniformEngineName, - std::vector newSamplers, - std::vector newSamplersMS, - std::vector newSamplersExternal) { + std::vector& newSamplers, + std::vector& newSamplersMS, + std::vector& newSamplersExternal) { ramses::UniformInput input = appearance->getEffect().findUniformInput(uniformEngineName.c_str()).value(); @@ -246,6 +246,7 @@ inline void setUniform(core::Errors* errors, SceneAdaptor* sceneAdaptor, ramses: } } else { errors->addError(core::ErrorCategory::GENERAL, core::ErrorLevel::ERROR, valueHandle, "Texture or RenderBuffer needed for this uniform."); + sampler = sceneAdaptor->defaultTextureSampler(); } if (sampler) { appearance->setInputTexture(input, *sampler); @@ -253,16 +254,20 @@ inline void setUniform(core::Errors* errors, SceneAdaptor* sceneAdaptor, ramses: } } break; - case core::EnginePrimitive::TextureSamplerCube: { + case core::EnginePrimitive::TextureSamplerCube: { + ramses_base::RamsesTextureSampler sampler = nullptr; if (auto texture = valueHandle.asTypedRef()) { if (auto adaptor = sceneAdaptor->lookup(texture)) { - if (auto sampler = adaptor->getRamsesObjectPointer()) { - appearance->setInputTexture(input, *sampler); - newSamplers.emplace_back(sampler); - } + sampler = adaptor->getRamsesObjectPointer(); } } else { errors->addError(core::ErrorCategory::GENERAL, core::ErrorLevel::ERROR, valueHandle, "CubeMap needed for this uniform."); + sampler = sceneAdaptor->defaultTextureCubeSampler(); + } + + if (sampler) { + appearance->setInputTexture(input, *sampler); + newSamplers.emplace_back(sampler); } } break; @@ -272,9 +277,9 @@ inline void setUniform(core::Errors* errors, SceneAdaptor* sceneAdaptor, ramses: } inline void setUniformRecursive(core::Errors* errors, SceneAdaptor* sceneAdaptor, ramses::Appearance* appearance, const core::ValueHandle& uniformContainerHandle, const core::ValueHandle& handle, - std::vector newSamplers, - std::vector newSamplersMS, - std::vector newSamplersExternal) { + std::vector& newSamplers, + std::vector& newSamplersMS, + std::vector& newSamplersExternal) { auto engineTypeAnno = handle.query(); switch (engineTypeAnno->type()) { case core::EnginePrimitive::Struct: diff --git a/components/libRamsesBase/src/ramses_adaptor/RenderBufferAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/RenderBufferAdaptor.cpp index 648bebb1..54bed267 100644 --- a/components/libRamsesBase/src/ramses_adaptor/RenderBufferAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/RenderBufferAdaptor.cpp @@ -44,6 +44,7 @@ RenderBufferAdaptor::RenderBufferAdaptor(SceneAdaptor* sceneAdaptor, std::shared } bool RenderBufferAdaptor::sync(core::Errors* errors) { + binding_.reset(); buffer_.reset(); auto format = static_cast(*editorObject()->format_); @@ -104,6 +105,8 @@ bool RenderBufferAdaptor::sync(core::Errors* errors) { } reset(std::move(textureSampler)); + + binding_ = ramses_base::ramsesRenderBufferBinding(buffer_, &sceneAdaptor_->logicEngine(), editorObject()->objectName() + "_Binding", editorObject()->objectIDAsRamsesLogicID()); } else { reset(nullptr); } @@ -117,14 +120,38 @@ ramses_base::RamsesRenderBuffer RenderBufferAdaptor::buffer() const { } std::vector RenderBufferAdaptor::getExportInformation() const { - if (buffer_ == nullptr) { - return {}; + std::vector result; + if (getRamsesObjectPointer() != nullptr) { + result.emplace_back(ramsesObject().getType(), ramsesObject().getName()); + } + if (buffer_) { + result.emplace_back(buffer_->getType(), buffer_->getName()); + } + if (binding_) { + result.emplace_back("RenderBufferBinding", binding_->getName()); + } + return result; +} + +void RenderBufferAdaptor::getLogicNodes(std::vector& logicNodes) const { + if (binding_) { + logicNodes.push_back(binding_.get()); + } +} + +ramses::Property* RenderBufferAdaptor::getProperty(const std::vector& propertyNamesVector) { + if (binding_ && propertyNamesVector.size() >= 1) { + return binding_->getInputs()->getChild(propertyNamesVector[0]); } + return nullptr; +} - return { - ExportInformation{ramsesObject().getType(), ramsesObject().getName()}, - ExportInformation{buffer_->getType(), buffer_->getName()}, - }; +void RenderBufferAdaptor::onRuntimeError(core::Errors& errors, std::string const& message, core::ErrorLevel level) { + core::ValueHandle const valueHandle{editorObject_}; + if (errors.hasError(valueHandle)) { + return; + } + errors.addError(core::ErrorCategory::RAMSES_LOGIC_RUNTIME, level, valueHandle, message); } } // namespace raco::ramses_adaptor diff --git a/components/libRamsesBase/src/ramses_adaptor/RenderBufferMSAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/RenderBufferMSAdaptor.cpp index ba445ace..17fb6be1 100644 --- a/components/libRamsesBase/src/ramses_adaptor/RenderBufferMSAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/RenderBufferMSAdaptor.cpp @@ -33,6 +33,7 @@ RenderBufferMSAdaptor::RenderBufferMSAdaptor(SceneAdaptor* sceneAdaptor, std::sh } bool RenderBufferMSAdaptor::sync(core::Errors* errors) { + binding_.reset(); buffer_.reset(); auto sampleCount = *editorObject()->sampleCount_; @@ -62,6 +63,8 @@ bool RenderBufferMSAdaptor::sync(core::Errors* errors) { if (buffer_) { auto textureSampler = ramses_base::ramsesTextureSamplerMS(sceneAdaptor_->scene(), buffer_, (editorObject()->objectName() + "_TextureSamplerMS").c_str(), editorObject()->objectIDAsRamsesLogicID()); reset(std::move(textureSampler)); + + binding_ = ramses_base::ramsesRenderBufferBinding(buffer_, &sceneAdaptor_->logicEngine(), editorObject()->objectName() + "_Binding", editorObject()->objectIDAsRamsesLogicID()); } else { reset(nullptr); } @@ -75,14 +78,38 @@ ramses_base::RamsesRenderBuffer RenderBufferMSAdaptor::buffer() const { } std::vector RenderBufferMSAdaptor::getExportInformation() const { - if (buffer_ == nullptr) { - return {}; + std::vector result; + if (getRamsesObjectPointer() != nullptr) { + result.emplace_back(ramsesObject().getType(), ramsesObject().getName()); + } + if (buffer_) { + result.emplace_back(buffer_->getType(), buffer_->getName()); + } + if (binding_) { + result.emplace_back("RenderBufferBinding", binding_->getName()); + } + return result; +} + +void RenderBufferMSAdaptor::getLogicNodes(std::vector& logicNodes) const { + if (binding_) { + logicNodes.push_back(binding_.get()); + } +} + +ramses::Property* RenderBufferMSAdaptor::getProperty(const std::vector& propertyNamesVector) { + if (binding_ && propertyNamesVector.size() >= 1) { + return binding_->getInputs()->getChild(propertyNamesVector[0]); } + return nullptr; +} - return { - ExportInformation{ramsesObject().getType(), ramsesObject().getName()}, - ExportInformation{buffer_->getType(), buffer_->getName()}, - }; +void RenderBufferMSAdaptor::onRuntimeError(core::Errors& errors, std::string const& message, core::ErrorLevel level) { + core::ValueHandle const valueHandle{editorObject_}; + if (errors.hasError(valueHandle)) { + return; + } + errors.addError(core::ErrorCategory::RAMSES_LOGIC_RUNTIME, level, valueHandle, message); } } // namespace raco::ramses_adaptor diff --git a/components/libRamsesBase/src/ramses_adaptor/RenderTargetAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/RenderTargetAdaptor.cpp index dc399b57..5530752b 100644 --- a/components/libRamsesBase/src/ramses_adaptor/RenderTargetAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/RenderTargetAdaptor.cpp @@ -28,8 +28,8 @@ bool RenderTargetAdaptorTsceneAdaptor_->template lookup(buffer)) { if (auto ramsesBuffer = adaptor->buffer()) { - if (!rtDesc.addRenderBuffer(*ramsesBuffer)) { - auto errorMsg = this->sceneAdaptor_->scene()->getRamsesClient().getRamsesFramework().getLastError().value().message; + std::string errorMsg; + if (!rtDesc.addRenderBuffer(*ramsesBuffer, &errorMsg)) { LOG_ERROR(log_system::RAMSES_ADAPTOR, errorMsg); errors->addError(core::ErrorCategory::PARSING, core::ErrorLevel::ERROR, {this->editorObject()->shared_from_this()}, errorMsg); } else { diff --git a/components/libRamsesBase/src/ramses_adaptor/SceneAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/SceneAdaptor.cpp index 57c95938..297817c3 100644 --- a/components/libRamsesBase/src/ramses_adaptor/SceneAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/SceneAdaptor.cpp @@ -208,12 +208,26 @@ void SceneAdaptor::deleteUnusedDefaultResources() { if (defaultNormals_[1].use_count() == 1) { defaultNormals_[1].reset(); } + if (defaultTextureSampler_.use_count() == 1) { + defaultTextureSampler_.reset(); + } + if (defaultTextureCubeSampler_.use_count() == 1) { + defaultTextureCubeSampler_.reset(); + } } void SceneAdaptor::readDataFromEngine(core::DataChangeRecorder& recorder) { for (const auto& [endObjecttID, linkMap] : links_.linksByEnd_) { for (const auto& [link, adaptor] : linkMap) { - adaptor->readDataFromEngine(recorder); + bool changed = adaptor->readDataFromEngine(recorder); + if (changed && (link.end.object()->isType() || link.end.object()->isType())) { + if (auto endObjAdaptor = lookupAdaptor(link.end.object())) { + // This is needed because Ramses can't change the size of a RenderBuffer after it is created. + // To work around this we detect a buffer size change via a link and set the adaptor to dirty to + // force a recreation of the buffer in ramses in the next frame: + endObjAdaptor->tagDirty(true); + } + } } } for (const auto& [editorObject, adaptor] : adaptors_) { @@ -297,6 +311,24 @@ const RamsesArrayResource SceneAdaptor::defaultIndices(int index) { return defaultIndices_[index]; } +const ramses_base::RamsesTextureSampler SceneAdaptor::defaultTextureSampler() { + if (!defaultTextureSampler_) { + defaultTextureSampler_ = createDefaultTextureSampler(scene_.get()); + } + return defaultTextureSampler_; +} + +const ramses_base::RamsesTextureSampler SceneAdaptor::defaultTextureCubeSampler() { + if (!defaultTextureCubeSampler_) { + defaultTextureCubeSampler_ = createDefaultTextureCubeSampler(scene_.get()); + } + return defaultTextureCubeSampler_; +} + +const std::vector& SceneAdaptor::dependencyGraph() { + return dependencyGraph_; +} + ObjectAdaptor* SceneAdaptor::lookupAdaptor(const core::SEditorObject& editorObject) const { if (!editorObject) { return nullptr; @@ -318,8 +350,7 @@ void SceneAdaptor::rebuildSortedDependencyGraph(SEditorObjectSet const& objects) void SceneAdaptor::performBulkEngineUpdate(const core::SEditorObjectSet& changedObjects) { if (adaptorStatusDirty_) { - for (const auto& item : dependencyGraph_) { - auto object = item.object; + for (const auto& object : project().instances()) { auto adaptor = lookupAdaptor(object); bool haveAdaptor = adaptor != nullptr; diff --git a/components/libRamsesBase/src/ramses_adaptor/SceneBackend.cpp b/components/libRamsesBase/src/ramses_adaptor/SceneBackend.cpp index abd9c46d..02fcf1fc 100644 --- a/components/libRamsesBase/src/ramses_adaptor/SceneBackend.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/SceneBackend.cpp @@ -73,7 +73,9 @@ std::optional SceneBackend::getLastError() { void SceneBackend::flush() { if (scene_) { - scene_->scene()->flush(); + if (!scene_->scene()->flush()) { + LOG_ERROR(log_system::RAMSES_BACKEND, "Scene flush failed with '{}'", getLastError().value().message); + } } } @@ -84,6 +86,14 @@ void SceneBackend::readDataFromEngine(core::DataChangeRecorder& recorder) { } bool SceneBackend::discardRamsesMessage(std::string_view message) { + // The ramses Renderer will produce this error message if a RenderBuffer changes its size after it has been allocated. + // If the size changes via a normal property change of the RenderBuffer the engine backend would recreate the objects and all is fine. + // If the change happens due to a link update only this error is generated. But in this case SceneAdaptor::readDataFromEngine + // will tag the adaptor as dirty and the buffer will be recreated in Ramses in the next frame so we are OK too. + // So we can safely ignore this error. + if (message.find("RendererResourceManager::updateRenderTargetBufferProperties changing properties of RenderBuffer which is already uploaded is not supported!") != std::string_view::npos) { + return true; + } if (message.find("has unlinked output") != std::string::npos) { return true; } @@ -295,4 +305,15 @@ std::string SceneBackend::getExportedObjectNames(SEditorObject editorObject) con return result; } +std::map SceneBackend::getPerformanceReport() { + auto report{logicEngine()->getLastUpdateReport()}; + + std::map timings; + for (auto& [logicNode, time_us] : report.getNodesExecuted()) { + auto objectID{core::EditorObject::ramsesLogicIDAsObjectID(logicNode->getUserId())}; + timings[objectID] += time_us; + } + return timings; +} + } // namespace raco::ramses_adaptor diff --git a/components/libRamsesBase/src/ramses_adaptor/TextureSamplerAdaptor.cpp b/components/libRamsesBase/src/ramses_adaptor/TextureSamplerAdaptor.cpp index 45bef45e..f0dafa79 100644 --- a/components/libRamsesBase/src/ramses_adaptor/TextureSamplerAdaptor.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/TextureSamplerAdaptor.cpp @@ -10,6 +10,7 @@ #include "ramses_adaptor/TextureSamplerAdaptor.h" #include "core/ErrorItem.h" #include "lodepng.h" +#include "ramses_adaptor/DefaultRamsesObjects.h" #include "ramses_adaptor/SceneAdaptor.h" #include "ramses_base/RamsesHandles.h" #include "user_types/Enumerations.h" @@ -73,7 +74,7 @@ bool TextureSamplerAdaptor::sync(core::Errors* errors) { } if (!textureData_) { - textureData_ = getFallbackTexture(); + textureData_ = createDefaultTexture2D(*editorObject()->flipTexture_, sceneAdaptor_->scene()); } else { auto selectedTextureFormat = static_cast((*editorObject()->textureFormat_)); @@ -123,7 +124,7 @@ bool TextureSamplerAdaptor::sync(core::Errors* errors) { RamsesTexture2D TextureSamplerAdaptor::createTexture(core::Errors* errors, PngDecodingInfo& decodingInfo) { if (*editorObject()->mipmapLevel_ < 1 || *editorObject()->mipmapLevel_ > 4) { - return getFallbackTexture(); + return createDefaultTexture2D(*editorObject()->flipTexture_, sceneAdaptor_->scene()); } std::vector> rawMipDatas; @@ -143,7 +144,7 @@ RamsesTexture2D TextureSamplerAdaptor::createTexture(core::Errors* errors, PngDe } if (!mipMapsOk) { - return getFallbackTexture(); + return createDefaultTexture2D(*editorObject()->flipTexture_, sceneAdaptor_->scene()); } // Swizzle is defined by original file format and user-selected texture format. @@ -165,15 +166,6 @@ RamsesTexture2D TextureSamplerAdaptor::createTexture(core::Errors* errors, PngDe return ramsesTexture2D(sceneAdaptor_->scene(), swizzleTextureFormat, decodingInfo.width, decodingInfo.height, mipDatas, *editorObject()->generateMipmaps_, swizzle, {}, editorObject()->objectIDAsRamsesLogicID()); } -RamsesTexture2D TextureSamplerAdaptor::getFallbackTexture() { - auto& data = getFallbackTextureData(*editorObject()->flipTexture_); - std::vector mipDatas; - mipDatas.emplace_back(reinterpret_cast(data.data()), reinterpret_cast(data.data()) + data.size()); - ramses::Texture2D* textureData = sceneAdaptor_->scene()->createTexture2D(ramses::ETextureFormat::RGBA8, FALLBACK_TEXTURE_SIZE_PX, FALLBACK_TEXTURE_SIZE_PX, mipDatas, false, {}, {}); - - return {textureData, createRamsesObjectDeleter(sceneAdaptor_->scene())}; -} - std::string TextureSamplerAdaptor::createDefaultTextureDataName() { return this->editorObject()->objectName() + "_Texture2D"; } @@ -191,30 +183,6 @@ void TextureSamplerAdaptor::flipDecodedPicture(std::vector& rawPi } } -std::vector& TextureSamplerAdaptor::getFallbackTextureData(bool flipped) { - QFile file(":fallbackTextureOpenGL"); - if (file.exists() && fallbackTextureData_.front().empty()) { - auto size = file.size(); - file.open(QIODevice::ReadOnly); - QDataStream in(&file); - std::vector sBuffer(size); - - for (auto i = 0; i < size; ++i) { - in >> sBuffer[i]; - } - - file.close(); - - unsigned int width; - unsigned int height; - lodepng::decode(fallbackTextureData_[0], width, height, sBuffer); - fallbackTextureData_[1] = fallbackTextureData_[0]; - flipDecodedPicture(fallbackTextureData_[1], 4, width, height, 8); - } - - return fallbackTextureData_[flipped]; -} - std::vector TextureSamplerAdaptor::getExportInformation() const { if (textureData_ == nullptr) { return {}; diff --git a/components/libRamsesBase/src/ramses_adaptor/utilities.cpp b/components/libRamsesBase/src/ramses_adaptor/utilities.cpp index 16c0a3b5..9d4e480f 100644 --- a/components/libRamsesBase/src/ramses_adaptor/utilities.cpp +++ b/components/libRamsesBase/src/ramses_adaptor/utilities.cpp @@ -19,7 +19,7 @@ namespace raco::ramses_adaptor { -raco::ramses_base::RamsesNodeBinding lookupNodeBinding(const SceneAdaptor* sceneAdaptor, core::SEditorObject node) { +ramses_base::RamsesNodeBinding lookupNodeBinding(const SceneAdaptor* sceneAdaptor, core::SEditorObject node) { if (auto nodeAdaptor = sceneAdaptor->lookup(node)) { return nodeAdaptor->nodeBinding(); } else if (auto nodeAdaptor = sceneAdaptor->lookup(node)) { diff --git a/components/libRamsesBase/src/ramses_base/EnumerationTranslations.cpp b/components/libRamsesBase/src/ramses_base/EnumerationTranslations.cpp index 00ea0818..9b85a124 100644 --- a/components/libRamsesBase/src/ramses_base/EnumerationTranslations.cpp +++ b/components/libRamsesBase/src/ramses_base/EnumerationTranslations.cpp @@ -96,4 +96,12 @@ std::map enumerati {user_types::ERenderBufferFormat::Depth16, ramses::ERenderBufferFormat::Depth16}, {user_types::ERenderBufferFormat::Depth32, ramses::ERenderBufferFormat::Depth32}}; +std::map enumerationTranslationAnimationInterpolationType = { + {core::MeshAnimationInterpolation::Linear, ramses::EInterpolationType::Linear}, + {core::MeshAnimationInterpolation::CubicSpline, ramses::EInterpolationType::Cubic}, + {core::MeshAnimationInterpolation::Step, ramses::EInterpolationType::Step}, + {core::MeshAnimationInterpolation::Linear_Quaternion, ramses::EInterpolationType::Linear_Quaternions}, + {core::MeshAnimationInterpolation::CubicSpline_Quaternion, ramses::EInterpolationType::Cubic_Quaternions}}; + + } // namespace raco::ramses_base diff --git a/components/libRamsesBase/tests/AnimationAdaptor_test.cpp b/components/libRamsesBase/tests/AnimationAdaptor_test.cpp index 36d354a8..044ce447 100644 --- a/components/libRamsesBase/tests/AnimationAdaptor_test.cpp +++ b/components/libRamsesBase/tests/AnimationAdaptor_test.cpp @@ -13,12 +13,44 @@ #include "ramses_adaptor/AnimationAdaptor.h" #include "ramses_adaptor/utilities.h" #include "user_types/AnimationChannel.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/Prefab.h" #include "user_types/PrefabInstance.h" using namespace raco::user_types; -class AnimationAdaptorTest : public RamsesBaseFixture<> {}; +class AnimationAdaptorTest : public RamsesBaseFixture<> { +public: + template + void check_interpolation(EnginePrimitive componentType, ramses::EPropertyType ramsesComponentType, MeshAnimationInterpolation interpolation, + std::vector timeStamps, + std::vector keyFrames, std::vector tangentsIn, std::vector tangentsOut, + float refTime, U refValue) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(componentType)); + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(interpolation)); + + commandInterface.setAnimationData(channel, timeStamps, keyFrames, tangentsIn, tangentsOut); + + auto animation = create("animation"); + commandInterface.set(ValueHandle{animation, &Animation::animationChannels_}[0], channel); + + dispatch(); + + auto ramsesAnimation = selectCheckLogic(animation); + + ASSERT_TRUE(ramsesAnimation->getOutputs()->hasChild("Ch0.channel")); + auto ramsesProp = ramsesAnimation->getOutputs()->getChild("Ch0.channel"); + ASSERT_EQ(ramsesProp->getType(), ramsesComponentType); + ASSERT_EQ(ramsesProp->get().value(), U()); + + commandInterface.set({animation, &Animation::progress_}, refTime); + dispatch(); + + ASSERT_EQ(ramsesProp->get().value(), refValue); + } +}; TEST_F(AnimationAdaptorTest, animNode_Creation) { auto anim = context.createObject(Animation::typeDescription.typeName, "Animation Name"); @@ -226,3 +258,131 @@ TEST_F(AnimationAdaptorTest, component_type_array_valid) { ASSERT_NE(select(sceneContext.logicEngine(), "Animation Name"), nullptr); } +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_float_linear) { + check_interpolation(EnginePrimitive::Double, ramses::EPropertyType::Float, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {0.0, 4.0}, {}, {}, 0.5, 2.0); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_float_step) { + check_interpolation(EnginePrimitive::Double, ramses::EPropertyType::Float, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {0.0, 4.0}, {}, {}, 0.5, 0.0); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_float_cubic) { + check_interpolation(EnginePrimitive::Double, ramses::EPropertyType::Float, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {0.0, 4.0}, {0.0, 0.0}, {0.0, 0.0}, 0.5, 2.0); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_float_cubic_2) { + check_interpolation(EnginePrimitive::Double, ramses::EPropertyType::Float, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {0.0, 4.0}, {1.0, 1.0}, {1.0, 1.0}, 0.5, 2.0); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec2f_linear) { + check_interpolation, glm::vec2>(EnginePrimitive::Vec2f, ramses::EPropertyType::Vec2f, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {{0.0, 0.0}, {4.0, 6.0}}, {}, {}, 0.5, {2.0, 3.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec2f_step) { + check_interpolation, glm::vec2>(EnginePrimitive::Vec2f, ramses::EPropertyType::Vec2f, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {{0.0, 0.0}, {4.0, 6.0}}, {}, {}, 0.5, {0.0, 0.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec2f_cubic) { + check_interpolation, glm::vec2>(EnginePrimitive::Vec2f, ramses::EPropertyType::Vec2f, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {{0.0, 0.0}, {4.0, 6.0}}, {{0.0, 0.0}, {0.0, 0.0}}, {{0.0, 0.0}, {0.0, 0.0}}, 0.5, {2.0, 3.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec3f_linear) { + check_interpolation, glm::vec3>(EnginePrimitive::Vec3f, ramses::EPropertyType::Vec3f, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {{0.0, 0.0, 0.0}, {4.0, 6.0, 8.0}}, {}, {}, 0.5, {2.0, 3.0, 4.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec3f_step) { + check_interpolation, glm::vec3>(EnginePrimitive::Vec3f, ramses::EPropertyType::Vec3f, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {{0.0, 0.0, 0.0}, {4.0, 6.0, 8.0}}, {}, {}, 0.5, {0.0, 0.0, 0.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec3f_cubic) { + check_interpolation, glm::vec3>(EnginePrimitive::Vec3f, ramses::EPropertyType::Vec3f, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {{0.0, 0.0, 0.0}, {4.0, 6.0, 8.0}}, {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, 0.5, {2.0, 3.0, 4.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec4f_linear) { + check_interpolation, glm::vec4>(EnginePrimitive::Vec4f, ramses::EPropertyType::Vec4f, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {{0.0, 0.0, 0.0, 0.0}, {4.0, 6.0, 8.0, 10.0}}, {}, {}, 0.5, {2.0, 3.0, 4.0, 5.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec4f_step) { + check_interpolation, glm::vec4>(EnginePrimitive::Vec4f, ramses::EPropertyType::Vec4f, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {{0.0, 0.0, 0.0, 0.0}, {4.0, 6.0, 8.0, 10.0}}, {}, {}, 0.5, {0.0, 0.0, 0.0, 0.0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec4f_cubic) { + check_interpolation, glm::vec4>(EnginePrimitive::Vec4f, ramses::EPropertyType::Vec4f, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {{0.0, 0.0, 0.0, 0.0}, {4.0, 6.0, 8.0, 10.0}}, {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}, {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}, 0.5, {2.0, 3.0, 4.0, 5.0}); +} + + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_int_linear) { + check_interpolation(EnginePrimitive::Int32, ramses::EPropertyType::Int32, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {0, 5}, {}, {}, 0.5, 3); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_int_step) { + check_interpolation(EnginePrimitive::Int32, ramses::EPropertyType::Int32, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {0, 5}, {}, {}, 0.5, 0); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_int_cubic) { + check_interpolation(EnginePrimitive::Int32, ramses::EPropertyType::Int32, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {0, 5}, {0, 0}, {0, 0}, 0.5, 3); +} + + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec2i_linear) { + check_interpolation, glm::ivec2>(EnginePrimitive::Vec2i, ramses::EPropertyType::Vec2i, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {{0, 0}, {5, 7}}, {}, {}, 0.5, {3, 4}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec2i_step) { + check_interpolation, glm::ivec2>(EnginePrimitive::Vec2i, ramses::EPropertyType::Vec2i, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {{0, 0}, {5, 7}}, {}, {}, 0.5, {0, 0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec2i_cubic) { + check_interpolation, glm::ivec2>(EnginePrimitive::Vec2i, ramses::EPropertyType::Vec2i, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {{0, 0}, {5, 7}}, {std::vector(2, 0), std::vector(2, 0)}, {std::vector(2, 0), std::vector(2, 0)}, 0.5, {3, 4}); +} + + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec3i_linear) { + check_interpolation, glm::ivec3>(EnginePrimitive::Vec3i, ramses::EPropertyType::Vec3i, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {{0, 0, 0}, {5, 7, 9}}, {}, {}, 0.5, {3, 4, 5}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec3i_step) { + check_interpolation, glm::ivec3>(EnginePrimitive::Vec3i, ramses::EPropertyType::Vec3i, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {{0, 0, 0}, {5, 7, 9}}, {}, {}, 0.5, {0, 0, 0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec3i_cubic) { + check_interpolation, glm::ivec3>(EnginePrimitive::Vec3i, ramses::EPropertyType::Vec3i, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {{0, 0, 0}, {5, 7, 9}}, {std::vector(3, 0), std::vector(3, 0)}, {std::vector(3, 0), std::vector(3, 0)}, 0.5, {3, 4, 5}); +} + + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec4i_linear) { + check_interpolation, glm::ivec4>(EnginePrimitive::Vec4i, ramses::EPropertyType::Vec4i, MeshAnimationInterpolation::Linear, + {0.0, 1.0}, {{0, 0, 0, 0}, {5, 7, 9, 11}}, {}, {}, 0.5, {3, 4, 5, 6}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec4i_step) { + check_interpolation, glm::ivec4>(EnginePrimitive::Vec4i, ramses::EPropertyType::Vec4i, MeshAnimationInterpolation::Step, + {0.0, 1.0}, {{0, 0, 0, 0}, {5, 7, 9, 11}}, {}, {}, 0.5, {0, 0, 0, 0}); +} + +TEST_F(AnimationAdaptorTest, raco_channel_interpolation_vec4i_cubic) { + check_interpolation, glm::ivec4>(EnginePrimitive::Vec4i, ramses::EPropertyType::Vec4i, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0}, {{0, 0, 0, 0}, {5, 7, 9, 11}}, {std::vector(4, 0), std::vector(4, 0)}, {std::vector(4, 0), std::vector(4, 0)}, 0.5, {3, 4, 5, 6}); +} diff --git a/components/libRamsesBase/tests/CMakeLists.txt b/components/libRamsesBase/tests/CMakeLists.txt index 1f4e6b83..4c0c1e39 100644 --- a/components/libRamsesBase/tests/CMakeLists.txt +++ b/components/libRamsesBase/tests/CMakeLists.txt @@ -9,6 +9,7 @@ If a copy of the MPL was not distributed with this file, You can obtain one at h ]] # Adding the unit test with gtest using our macro from dsathe top level CMakeLists.txt file + set(CMAKE_AUTORCC ON) set(TEST_SOURCES AdaptorTestUtils.h @@ -33,6 +34,8 @@ set(TEST_SOURCES PerspectiveCameraAdaptor_test.cpp Ramses_test.cpp RamsesLogic_test.cpp + RenderBufferAdaptor_test.cpp + RenderBufferMSAdaptor_test.cpp RenderLayerAdaptor_test.cpp Resources_test.cpp SceneContext_test.cpp @@ -41,6 +44,7 @@ set(TEST_SOURCES TextureAdaptor_test.cpp TextureExternalAdaptor_test.cpp utilities_test.cpp + ../../../styles/images.qrc ) set(TEST_LIBRARIES raco::RamsesBase @@ -106,4 +110,6 @@ raco_package_add_test_resources( meshes/SimpleSkin/SimpleSkin.gltf meshes/AnimatedMorphCube/AnimatedMorphCube.bin meshes/AnimatedMorphCube/AnimatedMorphCube.gltf + meshes/cube_color_attr_no_underscore_vec3.gltf + meshes/cube_color_attr_with_underscore_vec4.gltf ) diff --git a/components/libRamsesBase/tests/LinkAdaptor_test.cpp b/components/libRamsesBase/tests/LinkAdaptor_test.cpp index 4c17e559..d628fd9e 100644 --- a/components/libRamsesBase/tests/LinkAdaptor_test.cpp +++ b/components/libRamsesBase/tests/LinkAdaptor_test.cpp @@ -68,9 +68,6 @@ end EXPECT_EQ(logicEngine().getPropertyLinks().size(), 1); } -#if (!defined (__linux__)) -// awaitPreviewDirty does not work in Linux as expected. See RAOS-692 - TEST_F(LinkAdaptorFixture, linkWorksIfScriptContentChanges) { const auto luaScript{context.createObject(user_types::LuaScript::typeDescription.typeName, "lua_script", "lua_script_id")}; const auto node{context.createObject(user_types::Node::typeDescription.typeName, "node", "node_id")}; @@ -106,13 +103,12 @@ function run(IN,OUT) end )"); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, luaScript)); + EXPECT_TRUE(awaitPreviewDirty(recorder, luaScript)); ASSERT_TRUE(dispatch()); checkRamsesNodeTranslation("node", {5.0, 5.0, 0.0}); EXPECT_EQ(logicEngine().getPropertyLinks().size(), 1); } -#endif TEST_F(LinkAdaptorFixture, linkUnlinkLink) { const auto luaScript{context.createObject(user_types::LuaScript::typeDescription.typeName, "lua_script", "lua_script_id")}; diff --git a/components/libRamsesBase/tests/LuaScriptAdaptor_test.cpp b/components/libRamsesBase/tests/LuaScriptAdaptor_test.cpp index 8c2258ee..f5130a5f 100644 --- a/components/libRamsesBase/tests/LuaScriptAdaptor_test.cpp +++ b/components/libRamsesBase/tests/LuaScriptAdaptor_test.cpp @@ -491,6 +491,153 @@ end ASSERT_EQ(4.0f, engineObj->getOutputs()->getChild("value")->get()); } +TEST_F(LuaScriptAdaptorFixture, prefab_move_out) { + TextFile scriptFile = makeFile("script.lua", R"( +function interface(IN, OUT) +end +function run(IN,OUT) + error() +end +)"); + auto prefab = create("prefab"); + auto script = create_lua("script", scriptFile, prefab); + dispatch(); + + dontFindLogic("script"); + + commandInterface.moveScenegraphChildren({script}, {}); + dispatch(); + + selectCheckLogic(script); +} + +TEST_F(LuaScriptAdaptorFixture, prefab_delete_then_move_out) { + TextFile scriptFile = makeFile("script.lua", R"( +function interface(IN, OUT) +end +function run(IN,OUT) + error() +end +)"); + auto prefab = create("prefab"); + auto script = create_lua("script", scriptFile, prefab); + auto node = create("node"); + dispatch(); + + selectCheck(node); + dontFindLogic("script"); + + commandInterface.deleteObjects({node}); + dispatch(); + + dontFind("node"); + dontFindLogic("script"); + + commandInterface.moveScenegraphChildren({script}, {}); + dispatch(); + + dontFind("node"); + selectCheckLogic(script); +} + +TEST_F(LuaScriptAdaptorFixture, prefab_delete_and_move_out) { + TextFile scriptFile = makeFile("script.lua", R"( +function interface(IN, OUT) +end +function run(IN,OUT) + error() +end +)"); + auto prefab = create("prefab"); + auto script = create_lua("script", scriptFile, prefab); + auto node = create("node"); + dispatch(); + + selectCheck(node); + dontFindLogic("script"); + + commandInterface.deleteObjects({node}); + commandInterface.moveScenegraphChildren({script}, {}); + dispatch(); + + dontFind("node"); + selectCheckLogic(script); +} + +TEST_F(LuaScriptAdaptorFixture, prefab_move_in) { + TextFile scriptFile = makeFile("script.lua", R"( +function interface(IN, OUT) +end +function run(IN,OUT) + error() +end +)"); + auto prefab = create("prefab"); + auto script = create_lua("script", scriptFile); + dispatch(); + + selectCheckLogic(script); + + commandInterface.moveScenegraphChildren({script}, prefab); + dispatch(); + + dontFindLogic("script"); +} + +TEST_F(LuaScriptAdaptorFixture, prefab_delete_then_move_in) { + TextFile scriptFile = makeFile("script.lua", R"( +function interface(IN, OUT) +end +function run(IN,OUT) + error() +end +)"); + auto prefab = create("prefab"); + auto script = create_lua("script", scriptFile); + auto node = create("node"); + dispatch(); + + selectCheck(node); + selectCheckLogic(script); + + commandInterface.deleteObjects({node}); + dispatch(); + + dontFind("node"); + selectCheckLogic(script); + + commandInterface.moveScenegraphChildren({script}, prefab); + dispatch(); + + dontFind("node"); + dontFindLogic("script"); +} + +TEST_F(LuaScriptAdaptorFixture, prefab_delete_and_move_in) { + TextFile scriptFile = makeFile("script.lua", R"( +function interface(IN, OUT) +end +function run(IN,OUT) + error() +end +)"); + auto prefab = create("prefab"); + auto script = create_lua("script", scriptFile); + auto node = create("node"); + dispatch(); + + selectCheck(node); + selectCheckLogic(script); + + commandInterface.deleteObjects({node}); + commandInterface.moveScenegraphChildren({script}, prefab); + dispatch(); + + dontFind("node"); + dontFindLogic("script"); +} + + TEST_F(LuaScriptAdaptorFixture, prefab_instance_top_level_script_engine_name_gets_changed_after_moving) { auto luaScriptTopLevel = create("LuaScript Name"); auto luaScriptChild = create("Child LuaScript Name"); diff --git a/components/libRamsesBase/tests/MeshAdaptor_test.cpp b/components/libRamsesBase/tests/MeshAdaptor_test.cpp index b79a65b7..51ba770a 100644 --- a/components/libRamsesBase/tests/MeshAdaptor_test.cpp +++ b/components/libRamsesBase/tests/MeshAdaptor_test.cpp @@ -76,4 +76,54 @@ TEST_F(MeshAdaptorTest, gltf_with_meshes_but_no_mesh_refs_unbaked) { ASSERT_TRUE(isRamsesNameInArray("Mesh Name_MeshVertexData_a_Normal", meshStuff)); ASSERT_TRUE(isRamsesNameInArray("Mesh Name_MeshVertexData_a_TextureCoordinate", meshStuff)); ASSERT_EQ(context.errors().getError(mesh).level(), core::ErrorLevel::INFORMATION); -} \ No newline at end of file +} + +TEST_F(MeshAdaptorTest, gltf_color_attribute_vec3_no_underscore) { + auto mesh = create("mesh"); + context.set({mesh, &user_types::Mesh::bakeMeshes_}, false); + context.set({mesh, &user_types::Mesh::uri_}, test_path().append("meshes/cube_color_attr_no_underscore_vec3.gltf").string()); + + dispatch(); + + auto data = mesh->meshData(); + + auto color_idx = data->attribIndex("a_Color"); + ASSERT_TRUE(color_idx >= 0); + EXPECT_EQ(data->attribDataType(color_idx), core::MeshData::VertexAttribDataType::VAT_Float4); + + auto meshStuff{select(*sceneContext.scene(), ramses::ERamsesObjectType::ArrayResource)}; + EXPECT_EQ(meshStuff.size(), 7); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshIndexData", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Position", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Normal", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_TextureCoordinate", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Tangent", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Bitangent", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Color", meshStuff)); + ASSERT_EQ(context.errors().getError({mesh}).level(), core::ErrorLevel::INFORMATION); +} + +TEST_F(MeshAdaptorTest, gltf_color_attribute_vec4_with_underscore) { + auto mesh = create("mesh"); + context.set({mesh, &user_types::Mesh::bakeMeshes_}, false); + context.set({mesh, &user_types::Mesh::uri_}, test_path().append("meshes/cube_color_attr_with_underscore_vec4.gltf").string()); + + dispatch(); + + auto data = mesh->meshData(); + + auto color_idx = data->attribIndex("a_Color"); + ASSERT_TRUE(color_idx >= 0); + EXPECT_EQ(data->attribDataType(color_idx), core::MeshData::VertexAttribDataType::VAT_Float4); + + auto meshStuff{select(*sceneContext.scene(), ramses::ERamsesObjectType::ArrayResource)}; + EXPECT_EQ(meshStuff.size(), 7); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshIndexData", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Position", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Normal", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_TextureCoordinate", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Tangent", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Bitangent", meshStuff)); + ASSERT_TRUE(isRamsesNameInArray("mesh_MeshVertexData_a_Color", meshStuff)); + ASSERT_EQ(context.errors().getError({mesh}).level(), core::ErrorLevel::INFORMATION); +} diff --git a/components/libRamsesBase/tests/RamsesBaseFixture.h b/components/libRamsesBase/tests/RamsesBaseFixture.h index 556d7880..8bf2cc67 100644 --- a/components/libRamsesBase/tests/RamsesBaseFixture.h +++ b/components/libRamsesBase/tests/RamsesBaseFixture.h @@ -71,6 +71,32 @@ class RamsesBaseFixture : public TestEnvironmentCoreT { return status; } + template + inline const T* selectCheck(core::SEditorObject obj) { + auto ramsesObj = select(*sceneContext.scene(), obj->objectName().c_str()); + EXPECT_TRUE(ramsesObj != nullptr); + EXPECT_EQ(ramsesObj->getUserId(), obj->objectIDAsRamsesLogicID()); + return ramsesObj; + } + + template + inline const T* selectCheckLogic(core::SEditorObject obj) { + auto ramsesObj = select(sceneContext.logicEngine(), obj->objectName().c_str()); + EXPECT_TRUE(ramsesObj != nullptr); + EXPECT_EQ(ramsesObj->getUserId(), obj->objectIDAsRamsesLogicID()); + return ramsesObj; + } + + template + inline void dontFind(const char* name) { + EXPECT_TRUE(sceneContext.scene()->findObject(name) == nullptr); + } + + template + inline void dontFindLogic(const char* name) { + EXPECT_TRUE(sceneContext.logicEngine().findObject(name) == nullptr); + } + protected: template bool isRamsesNameInArray(std::string_view name, const std::vector& arrayOfArrays) { diff --git a/components/libRamsesBase/tests/RenderBufferAdaptor_test.cpp b/components/libRamsesBase/tests/RenderBufferAdaptor_test.cpp new file mode 100644 index 00000000..8359e136 --- /dev/null +++ b/components/libRamsesBase/tests/RenderBufferAdaptor_test.cpp @@ -0,0 +1,107 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include + +#include "RamsesBaseFixture.h" +#include "user_types/RenderBuffer.h" +#include "user_types/RenderTarget.h" + +using namespace user_types; + +class RenderBufferAdaptorTest : public RamsesBaseFixture<> { +public: + TextFile defaultFile() { + return makeFile("interface.lua", + R"___( +function interface(INOUT) + INOUT.integer = Type:Int32() +end +)___"); + } +}; + +TEST_F(RenderBufferAdaptorTest, target_buffer_size_mismatch) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget("render_target", {buffer_color, buffer_depth}); + dispatch(); + + ASSERT_FALSE(errors.hasError({target})); + + commandInterface.set({buffer_depth, &RenderBuffer::width_}, 100); + dispatch(); + + ASSERT_TRUE(errors.hasError({target})); + + commandInterface.set({buffer_color, &RenderBuffer::width_}, 100); + dispatch(); + + ASSERT_FALSE(errors.hasError({target})); +} + +TEST_F(RenderBufferAdaptorTest, link_width) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget("render_target", {buffer_color, buffer_depth}); + + dispatch(); + ASSERT_FALSE(errors.hasError({target})); + + commandInterface.set({lua, {"inputs", "integer"}}, 256); + commandInterface.addLink({lua, {"inputs", "integer"}}, {buffer_depth, &RenderBuffer::width_}); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({target})); + EXPECT_EQ(*buffer_depth->width_, 256); + + commandInterface.set({lua, {"inputs", "integer"}}, 100); + dispatch(); + dispatch(); + ASSERT_TRUE(errors.hasError({target})); + EXPECT_EQ(*buffer_depth->width_, 100); + + commandInterface.set({buffer_color, &RenderBuffer::width_}, 100); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({target})); +} + +TEST_F(RenderBufferAdaptorTest, link_height) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget("render_target", {buffer_color, buffer_depth}); + + dispatch(); + ASSERT_FALSE(errors.hasError({target})); + + commandInterface.set({lua, {"inputs", "integer"}}, 256); + commandInterface.addLink({lua, {"inputs", "integer"}}, {buffer_depth, &RenderBuffer::height_}); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({target})); + EXPECT_EQ(*buffer_depth->height_, 256); + + commandInterface.set({lua, {"inputs", "integer"}}, 100); + dispatch(); + dispatch(); + ASSERT_TRUE(errors.hasError({target})); + EXPECT_EQ(*buffer_depth->height_, 100); + + commandInterface.set({buffer_color, &RenderBuffer::height_}, 100); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({target})); +} diff --git a/components/libRamsesBase/tests/RenderBufferMSAdaptor_test.cpp b/components/libRamsesBase/tests/RenderBufferMSAdaptor_test.cpp new file mode 100644 index 00000000..18d13b07 --- /dev/null +++ b/components/libRamsesBase/tests/RenderBufferMSAdaptor_test.cpp @@ -0,0 +1,136 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include + +#include "RamsesBaseFixture.h" +#include "user_types/RenderBufferMS.h" +#include "user_types/RenderTarget.h" + +using namespace user_types; + +class RenderBufferMSAdaptorTest : public RamsesBaseFixture<> { +public: + TextFile defaultFile() { + return makeFile("interface.lua", + R"___( +function interface(INOUT) + INOUT.integer = Type:Int32() +end +)___"); + } +}; + +TEST_F(RenderBufferMSAdaptorTest, target_buffer_size_mismatch) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget_ms("render_target", { buffer_color, buffer_depth }); + dispatch(); + + ASSERT_FALSE(errors.hasError({ target })); + + commandInterface.set({ buffer_depth, &RenderBufferMS::width_ }, 100); + dispatch(); + + ASSERT_TRUE(errors.hasError({ target })); + + commandInterface.set({ buffer_color, &RenderBufferMS::width_ }, 100); + dispatch(); + + ASSERT_FALSE(errors.hasError({ target })); +} + +TEST_F(RenderBufferMSAdaptorTest, link_width) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget_ms("render_target", {buffer_color, buffer_depth}); + + dispatch(); + ASSERT_FALSE(errors.hasError({ target })); + + commandInterface.set({ lua, {"inputs", "integer"} }, 256); + commandInterface.addLink({ lua, {"inputs", "integer"} }, { buffer_depth, &RenderBufferMS::width_ }); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({ target })); + EXPECT_EQ(*buffer_depth->width_, 256); + + commandInterface.set({ lua, {"inputs", "integer"} }, 100); + dispatch(); + dispatch(); + ASSERT_TRUE(errors.hasError({ target })); + EXPECT_EQ(*buffer_depth->width_, 100); + + commandInterface.set({ buffer_color, &RenderBufferMS::width_ }, 100); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({ target })); +} + +TEST_F(RenderBufferMSAdaptorTest, link_height) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget_ms("render_target", {buffer_color, buffer_depth}); + + dispatch(); + ASSERT_FALSE(errors.hasError({ target })); + + commandInterface.set({ lua, {"inputs", "integer"} }, 256); + commandInterface.addLink({ lua, {"inputs", "integer"} }, { buffer_depth, &RenderBufferMS::height_ }); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({ target })); + EXPECT_EQ(*buffer_depth->height_, 256); + + commandInterface.set({ lua, {"inputs", "integer"} }, 100); + dispatch(); + dispatch(); + ASSERT_TRUE(errors.hasError({ target })); + EXPECT_EQ(*buffer_depth->height_, 100); + + commandInterface.set({ buffer_color, &RenderBufferMS::height_ }, 100); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({ target })); +} + +TEST_F(RenderBufferMSAdaptorTest, link_sample_count) { + auto interface_file = defaultFile(); + auto lua = create_lua_interface("lua", interface_file); + auto buffer_depth = create("buffer_depth"); + auto buffer_color = create("buffer_color"); + auto target = create_rendertarget_ms("render_target", {buffer_color, buffer_depth}); + + dispatch(); + ASSERT_FALSE(errors.hasError({target})); + + commandInterface.set({lua, {"inputs", "integer"}}, 1); + commandInterface.addLink({lua, {"inputs", "integer"}}, {buffer_depth, &RenderBufferMS::sampleCount_}); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({target})); + EXPECT_EQ(*buffer_depth->sampleCount_, 1); + + commandInterface.set({lua, {"inputs", "integer"}}, 3); + dispatch(); + dispatch(); + ASSERT_TRUE(errors.hasError({target})); + EXPECT_EQ(*buffer_depth->sampleCount_, 3); + + commandInterface.set({buffer_color, &RenderBufferMS::sampleCount_}, 3); + dispatch(); + dispatch(); + ASSERT_FALSE(errors.hasError({target})); +} diff --git a/components/libRamsesBase/tests/SceneContext_test.cpp b/components/libRamsesBase/tests/SceneContext_test.cpp index cd2f5f1e..235d3b88 100644 --- a/components/libRamsesBase/tests/SceneContext_test.cpp +++ b/components/libRamsesBase/tests/SceneContext_test.cpp @@ -330,6 +330,112 @@ TEST_F(SceneContextTest, construction_createSceneWithDeeperHierarchy_reverseNode dispatch(); } + +TEST_F(SceneContextTest, prefab_move_out) { + auto prefab = create("prefab"); + auto node_1 = create("node_1", prefab); + dispatch(); + + dontFind("node_1"); + + commandInterface.moveScenegraphChildren({node_1}, {}); + dispatch(); + + selectCheck(node_1); +} + +TEST_F(SceneContextTest, prefab_delete_then_move_out) { + auto prefab = create("prefab"); + auto node_1 = create("node_1"); + auto node_2 = create("node_2", prefab); + dispatch(); + + selectCheck(node_1); + dontFind("node_2"); + + commandInterface.deleteObjects({node_1}); + dispatch(); + + dontFind("node_1"); + dontFind("node_2"); + + commandInterface.moveScenegraphChildren({node_2}, {}); + dispatch(); + + dontFind("node_1"); + selectCheck(node_2); +} + +TEST_F(SceneContextTest, prefab_delete_and_move_out) { + auto prefab = create("prefab"); + auto node_1 = create("node_1"); + auto node_2 = create("node_2", prefab); + dispatch(); + + selectCheck(node_1); + dontFind("node_2"); + + commandInterface.deleteObjects({node_1}); + commandInterface.moveScenegraphChildren({node_2}, {}); + dispatch(); + + dontFind("node_1"); + selectCheck(node_2); +} + + +TEST_F(SceneContextTest, prefab_move_in) { + auto prefab = create("prefab"); + auto node_1 = create("node_1"); + dispatch(); + + selectCheck(node_1); + + commandInterface.moveScenegraphChildren({node_1}, prefab); + dispatch(); + + dontFind("node_1"); +} + +TEST_F(SceneContextTest, prefab_delete_then_move_in) { + auto prefab = create("prefab"); + auto node_1 = create("node_1"); + auto node_2 = create("node_2"); + dispatch(); + + selectCheck(node_1); + selectCheck(node_2); + + commandInterface.deleteObjects({node_1}); + dispatch(); + + dontFind("node_1"); + selectCheck(node_2); + + commandInterface.moveScenegraphChildren({node_2}, prefab); + dispatch(); + + dontFind("node_1"); + dontFind("node_2"); +} + +TEST_F(SceneContextTest, prefab_delete_and_move_in) { + auto prefab = create("prefab"); + auto node_1 = create("node_1"); + auto node_2 = create("node_2"); + dispatch(); + + selectCheck(node_1); + selectCheck(node_2); + + commandInterface.deleteObjects({node_1}); + commandInterface.moveScenegraphChildren({node_2}, prefab); + dispatch(); + + dontFind("node_1"); + dontFind("node_2"); +} + // TODO: this seems a little bit of an overkill to get all permutations of an array of size 4, find an easier way to tell INSTANTIATE_TEST_SUITE_P to do it for all permutations of the array struct CreationOrder { CreationOrder(const std::array& a) : order{a} {}; diff --git a/datamodel/libCore/include/core/CodeControlledPropertyModifier.h b/datamodel/libCore/include/core/CodeControlledPropertyModifier.h index 5a70a41e..9079747f 100644 --- a/datamodel/libCore/include/core/CodeControlledPropertyModifier.h +++ b/datamodel/libCore/include/core/CodeControlledPropertyModifier.h @@ -18,114 +18,146 @@ namespace raco::core { class CodeControlledPropertyModifier { public: template - static void setPrimitive(const core::ValueHandle& valueHandle, Type newValue, core::DataChangeRecorder& recorder) { + static bool setPrimitive(const core::ValueHandle& valueHandle, Type newValue, core::DataChangeRecorder& recorder) { auto oldValue = valueHandle.as(); if (oldValue != newValue) { valueHandle.valueRef()->set(static_cast(newValue)); recorder.recordValueChanged(valueHandle); + return true; } + return false; } - static void setVec2f(const core::ValueHandle& handle, double x, double y, core::DataChangeRecorder& recorder) { + static bool setVec2f(const core::ValueHandle& handle, double x, double y, core::DataChangeRecorder& recorder) { core::Vec2f& v = dynamic_cast(handle.valueRef()->asStruct()); + bool changed = false; if (*v.x != x) { v.x = x; recorder.recordValueChanged(handle[0]); + changed = true; } if (*v.y != y) { v.y = y; recorder.recordValueChanged(handle[1]); + changed = true; } + return changed; } - static void setVec3f(const core::ValueHandle& handle, double x, double y, double z, core::DataChangeRecorder& recorder) { + static bool setVec3f(const core::ValueHandle& handle, double x, double y, double z, core::DataChangeRecorder& recorder) { core::Vec3f& v = dynamic_cast(handle.valueRef()->asStruct()); + bool changed = false; if (*v.x != x) { v.x = x; recorder.recordValueChanged(handle[0]); + changed = true; } if (*v.y != y) { v.y = y; recorder.recordValueChanged(handle[1]); + changed = true; } if (*v.z != z) { v.z = z; recorder.recordValueChanged(handle[2]); + changed = true; } + return changed; } - static void setVec4f(const core::ValueHandle& handle, double x, double y, double z, double w, core::DataChangeRecorder& recorder) { + static bool setVec4f(const core::ValueHandle& handle, double x, double y, double z, double w, core::DataChangeRecorder& recorder) { core::Vec4f& v = dynamic_cast(handle.valueRef()->asStruct()); + bool changed = false; if (*v.x != x) { v.x = x; recorder.recordValueChanged(handle[0]); + changed = true; } if (*v.y != y) { v.y = y; recorder.recordValueChanged(handle[1]); + changed = true; } if (*v.z != z) { v.z = z; recorder.recordValueChanged(handle[2]); + changed = true; } if (*v.w != w) { v.w = w; recorder.recordValueChanged(handle[3]); + changed = true; } + return changed; } - static void setVec2i(const core::ValueHandle& handle, int x, int y, core::DataChangeRecorder& recorder) { + static bool setVec2i(const core::ValueHandle& handle, int x, int y, core::DataChangeRecorder& recorder) { core::Vec2i& v = dynamic_cast(handle.valueRef()->asStruct()); + bool changed = false; if (*v.i1_ != x) { v.i1_ = x; recorder.recordValueChanged(handle[0]); + changed = true; } if (*v.i2_ != y) { v.i2_ = y; recorder.recordValueChanged(handle[1]); + changed = true; } + return changed; } - static void setVec3i(const core::ValueHandle& handle, int x, int y, int z, core::DataChangeRecorder& recorder) { + static bool setVec3i(const core::ValueHandle& handle, int x, int y, int z, core::DataChangeRecorder& recorder) { core::Vec3i& v = dynamic_cast(handle.valueRef()->asStruct()); + bool changed = false; if (*v.i1_ != x) { v.i1_ = x; recorder.recordValueChanged(handle[0]); + changed = true; } if (*v.i2_ != y) { v.i2_ = y; recorder.recordValueChanged(handle[1]); + changed = true; } if (*v.i3_ != z) { v.i3_ = z; recorder.recordValueChanged(handle[2]); + changed = true; } + return changed; } - static void setVec4i(const core::ValueHandle& handle, int x, int y, int z, int w, core::DataChangeRecorder& recorder) { + static bool setVec4i(const core::ValueHandle& handle, int x, int y, int z, int w, core::DataChangeRecorder& recorder) { core::Vec4i& v = dynamic_cast(handle.valueRef()->asStruct()); + bool changed = false; if (*v.i1_ != x) { v.i1_ = x; recorder.recordValueChanged(handle[0]); + changed = true; } if (*v.i2_ != y) { v.i2_ = y; recorder.recordValueChanged(handle[1]); + changed = true; } if (*v.i3_ != z) { v.i3_ = z; recorder.recordValueChanged(handle[2]); + changed = true; } if (*v.i4_ != w) { v.i4_ = w; recorder.recordValueChanged(handle[3]); + changed = true; } + return changed; } }; } // namespace raco::core diff --git a/datamodel/libCore/include/core/CommandInterface.h b/datamodel/libCore/include/core/CommandInterface.h index a4569112..945540d4 100644 --- a/datamodel/libCore/include/core/CommandInterface.h +++ b/datamodel/libCore/include/core/CommandInterface.h @@ -32,7 +32,7 @@ class EngineInterface; /** * @brief The CommandInterface is the user-level API for modifying the data model in a safe way. - * + * * main characteristics * - all side-effects including Prefab update and undo stack push are taken care of. * - the consistency of the data model is ensured internally @@ -44,7 +44,7 @@ class EngineInterface; * - Prefab update * - undo stack push * - checking of operations for validity -*/ + */ class CommandInterface { public: CommandInterface(BaseContext* context, UndoStack* undostack); @@ -87,7 +87,7 @@ class CommandInterface { /** * @brief Set multiple double properties to the same value generating only a single undo stack entry. - */ + */ void set(const std::set& handles, double const& value); @@ -127,8 +127,8 @@ class CommandInterface { // Move scenegraph nodes to new parent at a position before the specified index. // - If ValueHandle is invalid/empty the scenegraph parent is removed. // - If insertionBeforeIndex = -1 the node will be appended at the end of the new parent children. - // - Only objects that are allowed to be moved to newParent will be actually moved there. - // Attempting to move objects not allowed to be moved is not considered an error but just leads to + // - Only objects that are allowed to be moved to newParent will be actually moved there. + // Attempting to move objects not allowed to be moved is not considered an error but just leads to // the remaining objects being moved. // @return Number of actually moved children. size_t moveScenegraphChildren(std::vector const& objects, SEditorObject const& newParent, int insertBeforeIndex = -1); @@ -167,6 +167,78 @@ class CommandInterface { */ std::vector duplicateObjects(const std::vector& objects); + /** + * @brief Converts an existing gltf-backed AnimationChannel object to an AnimationChannelRaco object + * while preserving all references to it and removing the old AnimationChannel object. + * + * Only deletable objects will be converted. + * + * @param objects Object to be converted. All objects must be of type AnimationChannel. + * @return Returns the newly created AnimationChannelRaco objects. + */ + std::vector convertToAnimationChannelRaco(const std::vector& objects); + + /** + * @brief Set animation data of an AnimationChannelRaco object. + * + * - The animation data passed in must be consistent with the componentType_, the interpolationType_, + * and the componentArraySize_ properties of the AnimationChannelRaco object or an exception is thrown. + * - Use this overload for component type double. + * + * @param object Object of AnimationChannelRaco type. + * @param timeStamps The time stamps for the key frames. + * @param keyFrames The output values for the key frames. + * @param tangentsIn The in tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + * @param tangentsOut The out tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + */ + void setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector& keyFrames, const std::vector& tangentsIn = {}, const std::vector& tangentsOut = {}); + + /** + * @brief Set animation data of an AnimationChannelRaco object. + * + * - The animation data passed in must be consistent with the componentType_, the interpolationType_, + * and the componentArraySize_ properties of the AnimationChannelRaco object or an exception is thrown. + * - Use this overload for Ve2f, Vec3f, Vec4f, and Array(float) component types. + * + * @param object Object of AnimationChannelRaco type. + * @param timeStamps The time stamps for the key frames. + * @param keyFrames The output values for the key frames. + * @param tangentsIn The in tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + * @param tangentsOut The out tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + */ + void setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector>& keyFrames, const std::vector>& tangentsIn = {}, const std::vector>& tangentsOut = {}); + + /** + * @brief Set animation data of an AnimationChannelRaco object. + * + * - The animation data passed in must be consistent with the componentType_, the interpolationType_, + * and the componentArraySize_ properties of the AnimationChannelRaco object or an exception is thrown. + * - Use this overload for component type int. + * + * @param object Object of AnimationChannelRaco type. + * @param timeStamps The time stamps for the key frames. + * @param keyFrames The output values for the key frames. + * @param tangentsIn The in tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + * @param tangentsOut The out tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + */ + void setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector& keyFrames, const std::vector& tangentsIn = {}, const std::vector& tangentsOut = {}); + + /** + * @brief Set animation data of an AnimationChannelRaco object. + * + * - The animation data passed in must be consistent with the componentType_, the interpolationType_, + * and the componentArraySize_ properties of the AnimationChannelRaco object or an exception is thrown. + * - Use this overload for Vec2i, Vec3i, and Vec4i component types. + * + * @param object Object of AnimationChannelRaco type. + * @param timeStamps The time stamps for the key frames. + * @param keyFrames The output values for the key frames. + * @param tangentsIn The in tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + * @param tangentsOut The out tangents in case of cubic interpolation types. Must be empty for step or linear interpolation. + */ + void setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector>& keyFrames, const std::vector>& tangentsIn = {}, const std::vector>& tangentsOut = {}); + + // Link operations SLink addLink(const ValueHandle& start, const ValueHandle& end, bool isWeak = false); void removeLink(const PropertyDescriptor& end); @@ -177,21 +249,21 @@ class CommandInterface { /** * @brief Execute a lambda function generating only a single undo stack entry. - * - * The given function may call any number of CommandInterface operations although these will not + * + * The given function may call any number of CommandInterface operations although these will not * generate individual undo stack entries. Only a single undo stack entry is generated for the whole * composite operation with the specified description. - * + * * Composite commands can be nested, i.e. the supplied function may itself call executeCompositeCommand. - * - * Composite commands are atomic, i.e. if an individual operation in the compositeCommand fails and + * + * Composite commands are atomic, i.e. if an individual operation in the compositeCommand fails and * throws an exception the composite command as a whole re-throws the exception and will roll back the * project to the state at the beginning of the composite command. In case of nested composite commands * the outermost composite command is rolled back. - * + * * @param compositeCommand Function to be executed as a composite command. * @param description Description for the composite undo stack entry. - */ + */ void executeCompositeCommand(std::function compositeCommand, const std::string& description); private: @@ -200,6 +272,12 @@ class CommandInterface { bool checkHandleForSet(ValueHandle const& handle, bool allowVolatile = false); bool checkScalarHandleForSet(ValueHandle const& handle, PrimitiveType type, bool allowVolatile = false); + template + bool checkAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut); + template + bool checkAnimationComponentSize(SEditorObject object, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut); + + static std::string getMergeId(const std::set& handles); BaseContext* context_; diff --git a/datamodel/libCore/include/core/EditorObject.h b/datamodel/libCore/include/core/EditorObject.h index c43a033f..dd659154 100644 --- a/datamodel/libCore/include/core/EditorObject.h +++ b/datamodel/libCore/include/core/EditorObject.h @@ -185,6 +185,8 @@ class EditorObject : public ClassWithReflectedMembers, public std::enable_shared // Returns the object ID without braces or hyphens in a pair of separated hexadecimal numbers {id[0,15], id[16-31]} std::pair objectIDAsRamsesLogicID() const; + static std::string ramsesLogicIDAsObjectID(std::pair idPair); + static std::string normalizedObjectID(std::string const& id); // Object IDs are calculated in the following cases @@ -208,6 +210,8 @@ class EditorObject : public ClassWithReflectedMembers, public std::enable_shared // Used to check back pointers in the unit tests. const std::set>& referencesToThis() const; + bool isValidProperty(const data_storage::Array& propNames) const; + protected: // Create file watchers for paths and associate them with the specified property. void recreatePropertyFileWatchers(BaseContext& context, const std::string& propertyName, const std::set& paths); diff --git a/datamodel/libCore/include/core/EngineInterface.h b/datamodel/libCore/include/core/EngineInterface.h index 6e4cb828..1b438ecd 100644 --- a/datamodel/libCore/include/core/EngineInterface.h +++ b/datamodel/libCore/include/core/EngineInterface.h @@ -35,7 +35,9 @@ enum class EUserTypeEnumerations { RenderLayerMaterialFilterMode = 12, FrustumType = 13, StencilFunction = 14, - StencilOperation = 15 + StencilOperation = 15, + AnimationComponentType = 16, + AnimationInterpolationType = 17 }; // Collects types of all possible dynamic properties, i.e. lua in/out properties and material uniforms. diff --git a/datamodel/libCore/include/core/MeshCacheInterface.h b/datamodel/libCore/include/core/MeshCacheInterface.h index 4e200328..b126a4b1 100644 --- a/datamodel/libCore/include/core/MeshCacheInterface.h +++ b/datamodel/libCore/include/core/MeshCacheInterface.h @@ -21,9 +21,13 @@ #include #include #include +#include #include #include +#include +#include +#include namespace raco::core { @@ -112,7 +116,7 @@ using SharedMeshData = std::shared_ptr; /** * @brief Holds the data needed to create a LogicEngine SkinBinding. Contains the inverse bind matrices. -*/ + */ struct SkinData { static constexpr const char* INV_BIND_MATRICES_UNIFORM_NAME = "u_jointMat"; @@ -124,28 +128,73 @@ struct SkinData { using SharedSkinData = std::shared_ptr; enum class MeshAnimationInterpolation { + Step = 0, Linear, CubicSpline, - Step, Linear_Quaternion, CubicSpline_Quaternion }; +template +struct AnimationOutputData { + std::vector keyFrames; + std::vector tangentsIn; + std::vector tangentsOut; + + bool operator==(const AnimationOutputData& rhs) const { + return keyFrames == rhs.keyFrames && + tangentsIn == rhs.tangentsIn && + tangentsOut == rhs.tangentsOut; + } +}; + +template +struct overloaded : Ts... { using Ts::operator()...; }; +template +overloaded(Ts...) -> overloaded; + // Animation sampler data holder - currently created using MeshCache::getAnimationSamplerData() struct AnimationSamplerData { MeshAnimationInterpolation interpolation; EnginePrimitive componentType; + size_t componentArraySize; std::vector timeStamps; - - // TODO the supported data types are currently restricted to float types only, - // although the logicengine also allows ints. - std::vector> keyFrames; - std::vector> tangentsIn; - std::vector> tangentsOut; + + using OutputDataVariant = std::variant< + AnimationOutputData, + AnimationOutputData, + AnimationOutputData, + AnimationOutputData, + AnimationOutputData, + AnimationOutputData, + AnimationOutputData, + AnimationOutputData, + AnimationOutputData>>; + + OutputDataVariant output; size_t getOutputComponentSize() { - return keyFrames.front().size(); + size_t componentSize = componentArraySize; + return std::visit( + overloaded{ + [](const AnimationOutputData& data) -> size_t { return 1; }, + [](const AnimationOutputData& data) -> size_t { return 2; }, + [](const AnimationOutputData& data) -> size_t { return 3; }, + [](const AnimationOutputData& data) -> size_t { return 4; }, + [](const AnimationOutputData& data) -> size_t { return 1; }, + [](const AnimationOutputData& data) -> size_t { return 2; }, + [](const AnimationOutputData& data) -> size_t { return 3; }, + [](const AnimationOutputData& data) -> size_t { return 4; }, + [componentSize](const AnimationOutputData>& data) -> size_t { return componentSize; }}, + output); + } + + bool operator==(const AnimationSamplerData& rhs) const { + return interpolation == rhs.interpolation && + componentType == rhs.componentType && + timeStamps == rhs.timeStamps && + output == rhs.output; } }; @@ -167,7 +216,7 @@ struct MeshAnimation { struct SkinDescription { std::string name; - int meshNodeIndex; + std::vector meshNodeIndices; std::vector jointNodeIndices; }; @@ -210,7 +259,6 @@ struct MeshScenegraph { } }; - // MeshDescriptor contains all information to uniquely identify a mesh within a file. // This includes at least the absolute path name of the file. It may include more information // when dealing with more complex file formats like Collada. @@ -253,7 +301,7 @@ class MeshCache : public FileChangeMonitor { virtual ~MeshCache() = default; virtual SharedMeshData loadMesh(const core::MeshDescriptor& descriptor) = 0; - + virtual const MeshScenegraph* getMeshScenegraph(const std::string& absPath) = 0; virtual std::string getMeshError(const std::string& absPath) = 0; diff --git a/datamodel/libCore/include/core/ProjectMigration.h b/datamodel/libCore/include/core/ProjectMigration.h index a029b98f..dcff17c4 100644 --- a/datamodel/libCore/include/core/ProjectMigration.h +++ b/datamodel/libCore/include/core/ProjectMigration.h @@ -132,9 +132,18 @@ namespace raco::serialization { * reset LinkEndAnnotation in enabled, renderOrder, clearColor properties * reset LinkEndAnnotation and removed FeatureLevel annotation in renderOnce property * - RenderLayer::renderableTags child properties: reset LinkEndAnnotation + * 2002: Change array element type of Animation::animationChannels_ from AnimationChannel to AnimationChannelBase + * Added AnimationChannelRaco user type + * 2003: Add python on-save script to the project settings + * 2004: Made RenderBuffer and RenderBufferMS properties 'width', 'height', and 'sampleCount' linkable. + * 2005: Increase max ranges to 8192 for the following properties: + * - ProjectSettings viewport i1 & i2 + * - RenderBuffer and RenderBufferMS height and width + * - BlitPass sourceX, sourceY, destinationX, destinationY, width, height + * - BaseCamera::viewport width, height, offsetX, offsetY */ -constexpr int RAMSES_PROJECT_FILE_VERSION = 2001; +constexpr int RAMSES_PROJECT_FILE_VERSION = 2005; void migrateProject(ProjectDeserializationInfoIR& deserializedIR, serialization::proxy::ProxyObjectFactory& factory); diff --git a/datamodel/libCore/include/core/ProjectSettings.h b/datamodel/libCore/include/core/ProjectSettings.h index 45c3d8e7..3bbe702a 100644 --- a/datamodel/libCore/include/core/ProjectSettings.h +++ b/datamodel/libCore/include/core/ProjectSettings.h @@ -85,7 +85,8 @@ class ProjectSettings : public EditorObject { featureLevel_(other.featureLevel_), viewport_(other.viewport_), backgroundColor_(other.backgroundColor_), - saveAsZip_(other.saveAsZip_) { + saveAsZip_(other.saveAsZip_), + pythonOnSaveScript_(other.pythonOnSaveScript_) { fillPropertyDescription(); } @@ -103,6 +104,7 @@ class ProjectSettings : public EditorObject { properties_.emplace_back("backgroundColor", &backgroundColor_); properties_.emplace_back("defaultResourceFolders", &defaultResourceDirectories_); properties_.emplace_back("saveAsZip", &saveAsZip_); + properties_.emplace_back("pythonOnSaveScript", &pythonOnSaveScript_); } Property> sceneId_{123u, DisplayNameAnnotation("Scene Id"), {1, 1024}}; @@ -111,11 +113,13 @@ class ProjectSettings : public EditorObject { // See ramses_base::BaseEngineBackend for definitions of min/max feature levels Property featureLevel_{1, {"Feature Level"}, {}}; - Property viewport_{{{1440, 720}, 0, 4096}, {"Display Size"}}; + // Viewport size constrained by texture size with RGBA format needing to fit into uint32_t + Property viewport_{{{1440, 720}, 0, 8192}, {"Display Size"}}; Property backgroundColor_{{}, {"Display Background Color"}}; Property saveAsZip_{false, {"Save As Zipped File"}}; Property defaultResourceDirectories_{{}, {"Default Resource Folders"}}; + Property pythonOnSaveScript_{std::string{}, DisplayNameAnnotation("Python on Save Script"), {"Python script(*.py);; All files (*.*)", PathManager::FolderTypeKeys::Script}}; }; } // namespace raco::core diff --git a/datamodel/libCore/include/core/ProxyObjectFactory.h b/datamodel/libCore/include/core/ProxyObjectFactory.h index 3d918447..94f729c0 100644 --- a/datamodel/libCore/include/core/ProxyObjectFactory.h +++ b/datamodel/libCore/include/core/ProxyObjectFactory.h @@ -155,6 +155,10 @@ class ProxyObjectFactory : public core::UserObjectFactoryInterface { // Animation Property, DisplayNameAnnotation>, Property, DisplayNameAnnotation, ResizableArray>, + Property, DisplayNameAnnotation, ResizableArray>, + + // AnimationChannelRaco + Property, // EditorObject Property, ArraySemanticAnnotation, HiddenProperty>, @@ -267,7 +271,13 @@ class ProxyObjectFactory : public core::UserObjectFactoryInterface { Property, Property, Property, - Property + Property, + + // AnimationChannelRaco data arrays + Value>, + Value>>, + Value>, + Value>> >; static ProxyObjectFactory& getInstance(); diff --git a/datamodel/libCore/include/core/ProxyTypes.h b/datamodel/libCore/include/core/ProxyTypes.h index 721ac208..db1cc032 100644 --- a/datamodel/libCore/include/core/ProxyTypes.h +++ b/datamodel/libCore/include/core/ProxyTypes.h @@ -68,10 +68,18 @@ extern const char animationTypeName[]; using Animation = Proxy; using SAnimation = std::shared_ptr; +extern const char animationChannelBaseTypeName[]; +using AnimationChannelBase = Proxy; +using SAnimationChannelBase = std::shared_ptr; + extern const char animationChannelTypeName[]; -using AnimationChannel = Proxy; +using AnimationChannel = Proxy; using SAnimationChannel = std::shared_ptr; +extern const char animationChannelRacoTypeName[]; +using AnimationChannelRaco = Proxy; +using SAnimationChannelRaco = std::shared_ptr; + extern const char textureSampler2DBaseTypeName[]; using TextureSampler2DBase = Proxy; using STextureSampler2DBase = std::shared_ptr; diff --git a/datamodel/libCore/src/CommandInterface.cpp b/datamodel/libCore/src/CommandInterface.cpp index b8224d25..257c3ae5 100644 --- a/datamodel/libCore/src/CommandInterface.cpp +++ b/datamodel/libCore/src/CommandInterface.cpp @@ -20,6 +20,7 @@ #include "core/UserObjectFactoryInterface.h" #include "utils/u8path.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/RenderLayer.h" #include @@ -642,6 +643,185 @@ std::vector CommandInterface::duplicateObjects(const std::vector< return duplicatedObjs; } + +std::vector CommandInterface::convertToAnimationChannelRaco(const std::vector& objects) { + for (auto obj : objects) { + if (!project()->isInstance(obj)) { + throw std::runtime_error(fmt::format("Convert AnimationChannel to AnimationChannelRaco: object '{}' not in project", obj->objectName())); + } + if (!obj->isType()) { + throw std::runtime_error(fmt::format("Convert AnimationChannel to AnimationChannelRaco: object '{}' is not an AnimationChannel", obj->objectName())); + } + } + + auto deletableObjects = Queries::filterForDeleteableObjects(*project(), objects); + if (!deletableObjects.empty()) { + std::vector racoChannels; + for (auto obj : deletableObjects) { + // Create new AnimationChannelRaco: + auto channel = obj->as(); + auto racoChannel = context_->createObject("AnimationChannelRaco", channel->objectName())->as(); + racoChannel->createPropertiesFromSamplerData(*context_, channel->currentSamplerData_); + + // Replace the old animation channel with the new raco animation channel: + // step 1: redirect references to the channel + auto refHandles = Queries::findAllReferencesTo(*project(), {channel}); + for (const auto& refHandle : refHandles) { + if (canSetHandle(refHandle)) { + context_->set(refHandle, racoChannel); + } + } + + // step 2: remove old object + context_->deleteObjects({channel}); + + racoChannels.emplace_back(racoChannel); + } + + PrefabOperations::globalPrefabUpdate(*context_); + undoStack_->push(fmt::format("Convert {} AnimationChannel{}", racoChannels.size(), racoChannels.size() > 1 ? "s" : "")); + + return racoChannels; + } + + return {}; +} + +template +bool CommandInterface::checkAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut) { + if (!project()->isInstance(object)) { + throw std::runtime_error(fmt::format("setAnimationData: object '{}' not in project", object->objectName())); + } + if (!object->isType()) { + throw std::runtime_error(fmt::format("setAnimationData: object '{}' is not an AnimationChannelRaco", object->objectName())); + } + + auto animationChannel = object->as(); + + auto numTimeStamps = timeStamps.size(); + if (keyFrames.size() != numTimeStamps) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': number of keyFrames {} is different from number of timeStamps {}.", object->objectName(), keyFrames.size(), numTimeStamps)); + } + + auto interpolationType = static_cast(*animationChannel->interpolationType_); + bool splineInterpolation = interpolationType == MeshAnimationInterpolation::CubicSpline || interpolationType == MeshAnimationInterpolation::CubicSpline_Quaternion; + if (splineInterpolation) { + if (tangentsIn.size() != numTimeStamps) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': number of tangentsIn {} is different from number of timeStamps {}.", object->objectName(), tangentsIn.size(), numTimeStamps)); + } + if (tangentsOut.size() != numTimeStamps) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': number of tangentsOut {} is different from number of timeStamps {}.", object->objectName(), tangentsOut.size(), numTimeStamps)); + } + } else { + if (tangentsIn.size() != 0) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': tangentsIn must be empty for non-cubic interpolation types.", object->objectName())); + } + if (tangentsOut.size() != 0) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': tangentsOut must be empty for non-cubic interpolation types.", object->objectName())); + } + } + + return true; +} + +template +bool CommandInterface::checkAnimationComponentSize(SEditorObject object, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector> & tangentsOut) { + auto animationChannel = object->as(); + + int compSize = animationChannel->getOuputComponentSize(); + if (!std::all_of(keyFrames.begin(), keyFrames.end(), [compSize](const auto& v) { + return v.size() == compSize; + })) { + throw std::runtime_error(fmt::format("setAnimationData for object '{}': component size mismatch in keyFrames.", object->objectName())); + } + + auto interpolationType = static_cast(*animationChannel->interpolationType_); + bool splineInterpolation = interpolationType == MeshAnimationInterpolation::CubicSpline || interpolationType == MeshAnimationInterpolation::CubicSpline_Quaternion; + if (splineInterpolation) { + if (!std::all_of(tangentsIn.begin(), tangentsIn.end(), [compSize](const auto& v) { + return v.size() == compSize; + })) { + throw std::runtime_error(fmt::format("setAnimationData for object '{}': component size mismatch in tangentsIn.", object->objectName())); + } + if (!std::all_of(tangentsOut.begin(), tangentsOut.end(), [compSize](const auto& v) { + return v.size() == compSize; + })) { + throw std::runtime_error(fmt::format("setAnimationData for object '{}': component size mismatch in tangentsOut.", object->objectName())); + } + } + return true; +} + +void CommandInterface::setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut) { + if (checkAnimationData(object, timeStamps, keyFrames, tangentsIn, tangentsOut)) { + auto animationChannel = object->as(); + + if (static_cast(*animationChannel->componentType_) != EnginePrimitive::Double) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': wrong componentType.", object->objectName())); + } + + animationChannel->setAnimationData(*context_, timeStamps, user_types::AnimationChannelRaco::makeAnimationOutputData(EnginePrimitive::Double, keyFrames, tangentsIn, tangentsOut)); + PrefabOperations::globalPrefabUpdate(*context_); + + undoStack_->push(fmt::format("Set animation data for AnimationChannelRaco '{}'", object->objectName())); + } +} + +void CommandInterface::setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut) { + if (checkAnimationData(object, timeStamps, keyFrames, tangentsIn, tangentsOut)) { + auto animationChannel = object->as(); + + if (static_cast(*animationChannel->componentType_) != EnginePrimitive::Int32) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': wrong componentType.", object->objectName())); + } + + animationChannel->setAnimationData(*context_, timeStamps, user_types::AnimationChannelRaco::makeAnimationOutputData(EnginePrimitive::Int32, keyFrames, tangentsIn, tangentsOut)); + PrefabOperations::globalPrefabUpdate(*context_); + + undoStack_->push(fmt::format("Set animation data for AnimationChannelRaco '{}'", object->objectName())); + } +} + +void CommandInterface::setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut) { + if (checkAnimationData(object, timeStamps, keyFrames, tangentsIn, tangentsOut)) { + auto animationChannel = object->as(); + + auto compType = static_cast(*animationChannel->componentType_); + std::set validTypes{EnginePrimitive::Vec2f, EnginePrimitive::Vec3f, EnginePrimitive::Vec4f, EnginePrimitive::Array}; + if (validTypes.find(compType) == validTypes.end()) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': wrong componentType.", object->objectName())); + } + + checkAnimationComponentSize(object, keyFrames, tangentsIn, tangentsOut); + + animationChannel->setAnimationData(*context_, timeStamps, user_types::AnimationChannelRaco::makeAnimationOutputData(compType, keyFrames, tangentsIn, tangentsOut)); + PrefabOperations::globalPrefabUpdate(*context_); + + undoStack_->push(fmt::format("Set animation data for AnimationChannelRaco '{}'", object->objectName())); + } +} + +void CommandInterface::setAnimationData(SEditorObject object, const std::vector& timeStamps, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut) { + if (checkAnimationData(object, timeStamps, keyFrames, tangentsIn, tangentsOut)) { + auto animationChannel = object->as(); + + auto compType = static_cast(*animationChannel->componentType_); + std::set validTypes{EnginePrimitive::Vec2i, EnginePrimitive::Vec3i, EnginePrimitive::Vec4i}; + if (validTypes.find(compType) == validTypes.end()) { + throw std::runtime_error(fmt::format("setAnimationdata for object '{}': wrong componentType.", object->objectName())); + } + + checkAnimationComponentSize(object, keyFrames, tangentsIn, tangentsOut); + + animationChannel->setAnimationData(*context_, timeStamps, user_types::AnimationChannelRaco::makeAnimationOutputData(compType, keyFrames, tangentsIn, tangentsOut)); + PrefabOperations::globalPrefabUpdate(*context_); + + undoStack_->push(fmt::format("Set animation data for AnimationChannelRaco '{}'", object->objectName())); + } +} + + + SLink CommandInterface::addLink(const ValueHandle& start, const ValueHandle& end, bool isWeak) { if (start && !context_->project()->isInstance(start.rootObject())) { throw std::runtime_error(fmt::format("Link starting object '{}' not in project", start.rootObject()->objectName())); diff --git a/datamodel/libCore/src/Context.cpp b/datamodel/libCore/src/Context.cpp index b761caee..8ca42f7b 100644 --- a/datamodel/libCore/src/Context.cpp +++ b/datamodel/libCore/src/Context.cpp @@ -1335,16 +1335,18 @@ void BaseContext::insertAssetScenegraph(const core::MeshScenegraph& scenegraph, } std::vector targetMeshNodes; - auto targetMeshNode = meshScenegraphNodes[sceneSkin->meshNodeIndex]; - if (targetMeshNode->isType()) { - targetMeshNodes.emplace_back(targetMeshNode); - } else { - auto submeshRootNode = targetMeshNode->children_->get(0)->asRef()->as(); - for (auto child : submeshRootNode->children_->asVector()) { - if (child->isType()) { - targetMeshNodes.emplace_back(child); - } else { - LOG_ERROR(log_system::CONTEXT, "Target child node is not a MeshNode '{}'", child->objectName()); + for (const auto& targetIndex : sceneSkin->meshNodeIndices) { + auto targetMeshNode = meshScenegraphNodes[targetIndex]; + if (targetMeshNode->isType()) { + targetMeshNodes.emplace_back(targetMeshNode); + } else { + auto submeshRootNode = targetMeshNode->children_->get(0)->asRef()->as(); + for (auto child : submeshRootNode->children_->asVector()) { + if (child->isType()) { + targetMeshNodes.emplace_back(child); + } else { + LOG_ERROR(log_system::CONTEXT, "Target child node is not a MeshNode '{}'", child->objectName()); + } } } } diff --git a/datamodel/libCore/src/EditorObject.cpp b/datamodel/libCore/src/EditorObject.cpp index 331aea4c..3d212723 100644 --- a/datamodel/libCore/src/EditorObject.cpp +++ b/datamodel/libCore/src/EditorObject.cpp @@ -75,6 +75,22 @@ std::pair EditorObject::objectIDAsRamsesLogicID() const { return {higher, lower}; } + std::string EditorObject::ramsesLogicIDAsObjectID(std::pair idPair) { + // Extract individual little-endian values. + auto id = QUuid{reinterpret_cast(&idPair.first)[1], + reinterpret_cast(&idPair.first)[1], + reinterpret_cast(&idPair.first)[0], + reinterpret_cast(&idPair.second)[7], + reinterpret_cast(&idPair.second)[6], + reinterpret_cast(&idPair.second)[5], + reinterpret_cast(&idPair.second)[4], + reinterpret_cast(&idPair.second)[3], + reinterpret_cast(&idPair.second)[2], + reinterpret_cast(&idPair.second)[1], + reinterpret_cast(&idPair.second)[0]}; + return id.toString(QUuid::WithoutBraces).toStdString(); + } + std::string EditorObject::normalizedObjectID(std::string const& id) { if (id.empty()) { return QUuid::createUuid().toString(QUuid::WithoutBraces).toStdString(); @@ -202,6 +218,24 @@ SEditorObject EditorObject::getParent() { return parent_.lock(); } + +bool EditorObject::isValidProperty(const data_storage::Array& propNames) const { + const ReflectionInterface* o = this; + for (size_t index = 0; index < propNames.size(); index++) { + auto propIndex = o->index(**propNames.get(index)); + if (propIndex == -1) { + return false; + } + const ValueBase* val = o->get(propIndex); + if (hasTypeSubstructure(val->type())) { + o = &val->getSubstructure(); + } + } + return true; +} + + + EditorObject::ChildIterator::ChildIterator(SEditorObject const& object, size_t index) : object_(object), index_(index) { } diff --git a/datamodel/libCore/src/ProjectMigration.cpp b/datamodel/libCore/src/ProjectMigration.cpp index 2cdf1f73..abcd8fd5 100644 --- a/datamodel/libCore/src/ProjectMigration.cpp +++ b/datamodel/libCore/src/ProjectMigration.cpp @@ -478,7 +478,6 @@ void recreateBackPointers(serialization::ProjectDeserializationInfoIR& deseriali } } - // Limitations // - Annotations and links are handled as static classes: // we can't change the class definition in a way that prevents deserialization of the old annotation: this means that @@ -1576,7 +1575,7 @@ void migrateProject(ProjectDeserializationInfoIR& deserializedIR, serialization: // !!! Wrong !!! // The save file optimization may have removed buffer references if the RenderTarget is an external reference. // In this case the check below may be wrong, i.e. different than without the save file optimization. - // Since the information needed to make the correct decision is not present in the file we can't make + // Since the information needed to make the correct decision is not present in the file we can't make // the right choice here in all cases. // Instead the external reference update itself contains fixup code for this case. @@ -1743,6 +1742,98 @@ void migrateProject(ProjectDeserializationInfoIR& deserializedIR, serialization: } } } -} - + + // Migration to file version 2002: + // - Change array element type of Animation::animationChannels_ from AnimationChannel to AnimationChannelBase + if (deserializedIR.fileVersion <= 2001) { + for (const auto& dynObj : deserializedIR.objects) { + if (dynObj->serializationTypeName() == "Animation") { + auto oldProp = dynObj->extractProperty("animationChannels"); + auto newProp = dynObj->addProperty("animationChannels", new Property, DisplayNameAnnotation, ResizableArray>({}, {"Animation Channels"}, {}), -1); + + ArrayBase& oldArray = oldProp->asArray(); + for (size_t i = 0; i < oldArray.size(); i++) { + *newProp->asArray().addProperty() = oldArray.get(i)->asRef(); + } + } + } + } + + // Migration to file version 2004: + // Make RenderBuffer and RenderBufferMS properties 'width', 'height', and'sampleCount' linkable. + if (deserializedIR.fileVersion <= 2004) { + for (const auto& dynObj : deserializedIR.objects) { + if (dynObj->serializationTypeName() == "RenderBuffer" || dynObj->serializationTypeName() == "RenderBufferMS") { + if (dynObj->hasProperty("width")) { + auto oldProp = dynObj->extractProperty("width"); + auto newProp = dynObj->addProperty("width", new Property, DisplayNameAnnotation, LinkEndAnnotation>(oldProp->asInt(), {1, 7680}, {"Width"}, {}), -1); + } + if (dynObj->hasProperty("height")) { + auto oldProp = dynObj->extractProperty("height"); + auto newProp = dynObj->addProperty("height", new Property, DisplayNameAnnotation, LinkEndAnnotation>(oldProp->asInt(), {1, 7680}, {"Height"}, {}), -1); + } + if (dynObj->hasProperty("sampleCount")) { + auto oldProp = dynObj->extractProperty("sampleCount"); + auto newProp = dynObj->addProperty("sampleCount", new Property, DisplayNameAnnotation, LinkEndAnnotation>(oldProp->asInt(), {1, 8}, {"Sample Count"}, {}), -1); + } + } + } + } + + // Migration to file version 2005: + if (deserializedIR.fileVersion <= 2005) { + for (const auto& dynObj : deserializedIR.objects) { + auto instanceType = dynObj->serializationTypeName(); + + if (instanceType == "ProjectSettings") { + if (dynObj->hasProperty("viewport")) { + auto& viewport = dynObj->get("viewport")->asStruct(); + viewport.get("i1")->query>()->max_ = 8192; + viewport.get("i2")->query>()->max_ = 8192; + } + } + + if (instanceType == "RenderBuffer" || instanceType == "RenderBufferMS") { + if (dynObj->hasProperty("width")) { + dynObj->get("width")->query>()->max_ = 8192; + } + if (dynObj->hasProperty("height")) { + dynObj->get("height")->query>()->max_ = 8192; + } + } + + if (instanceType == "BlitPass") { + if (dynObj->hasProperty("sourceX")) { + dynObj->get("sourceX")->query>()->max_ = 8192; + } + if (dynObj->hasProperty("sourceY")) { + dynObj->get("sourceY")->query>()->max_ = 8192; + } + if (dynObj->hasProperty("destinationX")) { + dynObj->get("destinationX")->query>()->max_ = 8192; + } + if (dynObj->hasProperty("destinationY")) { + dynObj->get("destinationY")->query>()->max_ = 8192; + } + if (dynObj->hasProperty("width")) { + dynObj->get("width")->query>()->max_ = 8192; + } + if (dynObj->hasProperty("height")) { + dynObj->get("height")->query>()->max_ = 8192; + } + } + + if (instanceType == "PerspectiveCamera" || instanceType == "OrthographicCamera") { + if (dynObj->hasProperty("viewport")) { + auto viewport = (&dynObj->get("viewport")->asStruct()); + viewport->get("offsetX")->query>()->max_ = 8192; + viewport->get("offsetY")->query>()->max_ = 8192; + viewport->get("width")->query>()->max_ = 8192; + viewport->get("height")->query>()->max_ = 8192; + } + } + } + } +} + } // namespace raco::serialization diff --git a/datamodel/libCore/src/ProxyObjectFactory.cpp b/datamodel/libCore/src/ProxyObjectFactory.cpp index c33440b6..8fe4e820 100644 --- a/datamodel/libCore/src/ProxyObjectFactory.cpp +++ b/datamodel/libCore/src/ProxyObjectFactory.cpp @@ -43,8 +43,8 @@ namespace raco::serialization::proxy { } template - std::map ProxyObjectFactory::makePropertyMapTuple(std::tuple* dummy) { - return std::map{ createTypeMapPair()...}; + std::map ProxyObjectFactory::makePropertyMapTuple(std::tuple* dummy) { + return std::map{ createTypeMapPair()...}; } template @@ -57,7 +57,7 @@ namespace raco::serialization::proxy { ProxyObjectFactory::ProxyObjectFactory() { properties_ = makePropertyMapTuple(static_cast(nullptr)); - // This contains proxy types defined in ProxyTypes.h from namespace raco::serialization::proxy + // This contains proxy types defined in ProxyTypes.h from namespace serialization::proxy // Don't add the normal user_types here. // Instead create a new proxy type in ProxyTypes.h and add that in the call below. types_ = makeTypeMap< @@ -65,6 +65,7 @@ namespace raco::serialization::proxy { AnchorPoint, Animation, AnimationChannel, + AnimationChannelRaco, BlitPass, CubeMap, Node, @@ -91,7 +92,7 @@ namespace raco::serialization::proxy { >(); annotations_ = makeAnnotationMap< - raco::core::ExternalReferenceAnnotation + core::ExternalReferenceAnnotation >(); } diff --git a/datamodel/libCore/src/ProxyTypes.cpp b/datamodel/libCore/src/ProxyTypes.cpp index 551092fd..224c00a4 100644 --- a/datamodel/libCore/src/ProxyTypes.cpp +++ b/datamodel/libCore/src/ProxyTypes.cpp @@ -22,6 +22,8 @@ const char luaScriptModuleTypeName[] = "LuaScriptModule"; const char anchorPointTypeName[] = "AnchorPoint"; const char animationTypeName[] = "Animation"; const char animationChannelTypeName[] = "AnimationChannel"; +const char animationChannelBaseTypeName[] = "AnimationChannelBase"; +const char animationChannelRacoTypeName[] = "AnimationChannelRaco"; const char textureSampler2DBaseTypeName[] = "TextureSampler2DBase"; const char textureTypeName[] = "Texture"; const char textureExternalTypeName[] = "TextureExternal"; diff --git a/datamodel/libCore/src/Queries.cpp b/datamodel/libCore/src/Queries.cpp index 257c2c8c..00a1ba4b 100644 --- a/datamodel/libCore/src/Queries.cpp +++ b/datamodel/libCore/src/Queries.cpp @@ -753,9 +753,10 @@ template std::map> Queries::getLinksConnectedToObje std::string Queries::getBrokenLinksErrorMessage(const Project& project, SEditorObject obj) { std::vector brokenLinks; for (auto link : Queries::getLinksConnectedToObject(project, obj, false, true)) { - core::ValueHandle endHandle(link->endProp()); - if (endHandle && !link->isValid()) { - brokenLinks.emplace_back(fmt::format("{} -> {}", link->startProp().getPropertyPath(), link->endProp().getPropertyPath())); + if (!link->isValid()) { + if ((*link->endObject_)->isValidProperty(*link->endProp_)) { + brokenLinks.emplace_back(fmt::format("{} -> {}", link->startProp().getPropertyPath(), link->endProp().getPropertyPath())); + } } } if (brokenLinks.size() > 0) { diff --git a/datamodel/libCore/tests/CMakeLists.txt b/datamodel/libCore/tests/CMakeLists.txt index bf570ecf..a1d0659b 100644 --- a/datamodel/libCore/tests/CMakeLists.txt +++ b/datamodel/libCore/tests/CMakeLists.txt @@ -183,6 +183,9 @@ raco_package_add_test_resources( migrationTestData/V58.rca migrationTestData/V59.rca migrationTestData/V60.rca + migrationTestData/V2001.rca + migrationTestData/V2003.rca + migrationTestData/V2004.rca migrationTestData/version-current.rca ) add_compile_definitions(libSerialization_test PRIVATE CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/datamodel/libCore/tests/CommandInterface_test.cpp b/datamodel/libCore/tests/CommandInterface_test.cpp index b08910df..ac7ab7c8 100644 --- a/datamodel/libCore/tests/CommandInterface_test.cpp +++ b/datamodel/libCore/tests/CommandInterface_test.cpp @@ -11,8 +11,9 @@ #include "testing/TestEnvironmentCore.h" #include "testing/TestUtil.h" -#include "user_types/Node.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/LuaScript.h" +#include "user_types/Node.h" #include "user_types/Timer.h" #include "gtest/gtest.h" @@ -330,7 +331,7 @@ TEST_F(CommandInterfaceTest, set_fail_read_only_prop_lua_output) { TEST_F(CommandInterfaceTest, set_fail_read_only_prop_timer_output) { auto timer = create("timer"); - + EXPECT_THROW(commandInterface.set({timer, {"outputs", "ticker_us"}}, int64_t{0}), std::runtime_error); } @@ -396,7 +397,7 @@ TEST_F(CommandInterfaceTest, set_multi_int_fail_invalid_enum) { TEST_F(CommandInterfaceTest, set_int_fail_read_only) { auto obj = create("name"); - + EXPECT_THROW(commandInterface.set({obj, {"readOnly"}}, 27), std::runtime_error); } @@ -425,7 +426,7 @@ TEST_F(CommandInterfaceTest, move_scenegraph_fail_prefab_loop_nested) { commandInterface.set({inst_1, &PrefabInstance::template_}, prefab_2); commandInterface.set({inst_2, &PrefabInstance::template_}, prefab_1); - + EXPECT_EQ(commandInterface.moveScenegraphChildren({inst_2}, prefab_2), 0); EXPECT_TRUE(inst_2->getParent() == nullptr); @@ -520,7 +521,7 @@ TEST_F(CommandInterfaceTest, move_fail_insertion_index_too_big) { TEST_F(CommandInterfaceTest, move_fail_insertion_index_invalid_to_root) { auto settings = project.settings(); auto node1 = create("node1"); - + ASSERT_EQ(project.instances(), std::vector({settings, node1})); EXPECT_EQ(commandInterface.moveScenegraphChildren({node1}, nullptr, 0), 1); @@ -544,7 +545,6 @@ TEST_F(CommandInterfaceTest, addLink_fail_no_end_object) { EXPECT_THROW(commandInterface.addLink({lua, {"outputs", "ovector3f"}}, {node, {"translation"}}), std::runtime_error); } - TEST_F(CommandInterfaceTest, addLink_fail_no_start_property) { auto node = create("node"); auto lua = create_lua("lua", "scripts/types-scalar.lua"); @@ -615,7 +615,6 @@ TEST_F(CommandInterfaceTest, addLink_fail_future_linkable) { EXPECT_THROW(commandInterface.addLink({start, &Foo::x_}, {end, &Foo::futureLinkable_}), std::runtime_error); } - TEST_F(CommandInterfaceTest, removeLink_fail_no_end) { auto node = create("node"); auto lua = create_lua("lua", "scripts/types-scalar.lua"); @@ -631,14 +630,13 @@ TEST_F(CommandInterfaceTest, removeLink_fail_end_object_readonly) { auto node = create("node", prefab); auto inst = create_prefabInstance("inst", prefab); - auto inst_node = raco::select(inst->children_->asVector(), "node"); - auto inst_lua = raco::select(inst->children_->asVector(), "lua"); + auto inst_node = select(inst->children_->asVector(), "node"); + auto inst_lua = select(inst->children_->asVector(), "lua"); auto [sprop, eprop] = link(lua, {"outputs", "ovector3f"}, node, {"translation"}); EXPECT_THROW(commandInterface.removeLink({inst_node, {"translation"}}), std::runtime_error); } - TEST_F(CommandInterfaceTest, copy_objects_fail_deleted) { auto node = create("node"); commandInterface.deleteObjects({node}); @@ -725,3 +723,278 @@ TEST_F(CommandInterfaceTest, array_resize_grow) { EXPECT_EQ(**obj->array_ref_resizable_->get(0), nullptr); EXPECT_EQ(**obj->array_ref_resizable_->get(1), nullptr); } + +TEST_F(CommandInterfaceTest, conv_anim_channel_fail) { + auto channel = create("channel"); + auto node = create("node"); + + EXPECT_THROW(commandInterface.convertToAnimationChannelRaco({channel, node}), std::runtime_error); + + commandInterface.deleteObjects({channel}); + EXPECT_THROW(commandInterface.convertToAnimationChannelRaco({channel}), std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_no_instance) { + auto channel = create("channel"); + + commandInterface.deleteObjects({channel}); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), std::vector({1, 2})), std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_wrong_user_type) { + auto node = create("node"); + + EXPECT_THROW(commandInterface.setAnimationData(node, std::vector({0, 1, 2}), std::vector({1, 2})), std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_array_size_mismatch) { + auto channel = create("channel"); + + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), std::vector({1, 2})), std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::CubicSpline)); + + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector({1, 2, 3}), std::vector({1, 2}), std::vector({1, 2, 3})), + std::runtime_error); + + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector({1, 2, 3}), std::vector({1, 2, 3}), std::vector({1, 2})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_invalid_tangents) { + auto channel = create("channel"); + + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector({1, 2, 3}), std::vector(), std::vector())); + + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector({1, 2, 3}), std::vector(3, 0.0), std::vector()), + std::runtime_error); + + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector({1, 2, 3}), std::vector(), std::vector(3, 1.0)), + std::runtime_error); + + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector({1, 2, 3}), std::vector(3, 0.0), std::vector(3, 1.0)), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_type_mismatch_double) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Int32)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), std::vector({1, 2, 3})), std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), std::vector({1, 2, 3})), std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_type_mismatch_int) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Double)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), std::vector({1, 2, 3})), std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), std::vector({1, 2, 3})), std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_type_mismatch_vector_double) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Double)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Array)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 2); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}))); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_type_mismatch_vector_int) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Int32)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Array)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 2); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_size_mismatch_vector_double_keyframes) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0, 0.0}, {3.0, 4.0}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec3f)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Array)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 2); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 3); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_size_mismatch_vector_double_tangents_in) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::CubicSpline)); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Array)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 2); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 3); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_size_mismatch_vector_double_tangents_out) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::CubicSpline)); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2f)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1, 1}, {1, 1}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Array)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 2); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 3); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1, 1}, {1, 1}})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_size_mismatch_vector_int_keyframes) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3, 0}, {3, 4}})), + std::runtime_error); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec3i)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3, 0}, {3, 4}})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_size_mismatch_vector_int_tangents_in) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::CubicSpline)); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}}), + std::vector>({{0, 0}, {0, 0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}})), + std::runtime_error); +} + +TEST_F(CommandInterfaceTest, anim_channel_raco_set_data_fail_comp_size_mismatch_vector_int_tangents_out) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::CubicSpline)); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_NO_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1}, {1, 1}}))); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec2i)); + EXPECT_THROW(commandInterface.setAnimationData(channel, std::vector({0, 1, 2}), + std::vector>({{1, 2}, {2, 3}, {3, 4}}), + std::vector>({{0, 0}, {0, 0}, {0, 0}}), + std::vector>({{1, 1}, {1, 1, 1}, {1, 1}})), + std::runtime_error); +} \ No newline at end of file diff --git a/datamodel/libCore/tests/Context_test.cpp b/datamodel/libCore/tests/Context_test.cpp index 8ac4a4ca..4ebd5e8e 100644 --- a/datamodel/libCore/tests/Context_test.cpp +++ b/datamodel/libCore/tests/Context_test.cpp @@ -820,7 +820,7 @@ TEST_F(ContextTest, deepCut) { } TEST_F(ContextTest, shallowCopyLink) { - auto objs { raco::createLinkedScene(context, test_relative_path()) }; + auto objs { createLinkedScene(context, test_relative_path()) }; ASSERT_EQ(1, context.project()->links().size()); context.pasteObjects(context.copyObjects({ std::get<1>(objs) })); @@ -829,7 +829,7 @@ TEST_F(ContextTest, shallowCopyLink) { } TEST_F(ContextTest, shallowCutLink) { - auto objs{raco::createLinkedScene(context, test_relative_path())}; + auto objs{createLinkedScene(context, test_relative_path())}; ASSERT_EQ(1, context.project()->links().size()); auto clipboard = context.cutObjects({ std::get<1>(objs) }); @@ -869,7 +869,7 @@ TEST_F(ContextTest, ShallowCopyNodeWithLink_pasteRoot) { } TEST_F(ContextTest, shallowCopyLink_deletedStartObject) { - auto objs{raco::createLinkedScene(context, test_relative_path())}; + auto objs{createLinkedScene(context, test_relative_path())}; ASSERT_EQ(1, context.project()->links().size()); auto clipboard = context.copyObjects({ std::get<1>(objs) }); @@ -964,7 +964,7 @@ TEST_F(ContextTest, cutAndPasteNodeUniqueName) { } TEST_F(ContextTest, queryLinkConnectedToObjectsReturnsNoDuplicateLinks) { - auto objs{raco::createLinkedScene(context, test_relative_path())}; + auto objs{createLinkedScene(context, test_relative_path())}; auto totalLinks = core::Queries::getLinksConnectedToObjects( *context.project(), SEditorObjectSet{context.project()->instances().begin(), context.project()->instances().end()}, true, true); diff --git a/datamodel/libCore/tests/Deserialization_test.cpp b/datamodel/libCore/tests/Deserialization_test.cpp index afbc8090..45e49bb2 100644 --- a/datamodel/libCore/tests/Deserialization_test.cpp +++ b/datamodel/libCore/tests/Deserialization_test.cpp @@ -188,7 +188,7 @@ TEST_F(DeserializationTest, deserializeObjects_luaScriptLinkedToNode_outputsAreD utils::file::read((test_path() / "expectations" / "LuaScriptLinkedToNode.json").string()), false); ASSERT_TRUE(result.has_value()); - user_types::SLuaScript sScript{ raco::select(result->objects)}; + user_types::SLuaScript sScript{ select(result->objects)}; ASSERT_EQ(3, sScript->outputs_->size()); } @@ -213,8 +213,8 @@ TEST_F(DeserializationTest, deserializeObjects_luaScriptLinkedToNode) { ASSERT_EQ(2, result->references.size()); auto sLink{std::dynamic_pointer_cast(result->links.at(0))}; - user_types::SLuaScript sLuaScript{raco::select(result->objects)}; - user_types::SNode sNode{raco::select(result->objects)}; + user_types::SLuaScript sLuaScript{select(result->objects)}; + user_types::SNode sNode{select(result->objects)}; core::PropertyDescriptor startProp {sLuaScript, {"outputs", "translation"}}; EXPECT_EQ(startProp, sLink->startProp()); @@ -235,9 +235,9 @@ TEST_F(DeserializationTest, deserializeArrays) { }); } - auto obj = raco::select(result->objects); - auto node_1 = raco::select(result->objects, "node_1"); - auto node_2 = raco::select(result->objects, "node_2"); + auto obj = select(result->objects); + auto node_1 = select(result->objects, "node_1"); + auto node_2 = select(result->objects, "node_2"); ASSERT_TRUE(obj != nullptr); ASSERT_TRUE(node_1 != nullptr); ASSERT_TRUE(node_2 != nullptr); diff --git a/datamodel/libCore/tests/Node_test.cpp b/datamodel/libCore/tests/Node_test.cpp index c2302c73..554c5c8d 100644 --- a/datamodel/libCore/tests/Node_test.cpp +++ b/datamodel/libCore/tests/Node_test.cpp @@ -75,4 +75,26 @@ TEST(NodeTest, ObjectAnnotation) { // Remove non-existing annotation: no effect n.removeAnnotation(); +} + +TEST(NodeTest, ramses_id_as_object_id) { + { + const auto ramsesIdLowerBytes = std::pair{1, 2}; + const auto convertedId1{EditorObject::ramsesLogicIDAsObjectID(ramsesIdLowerBytes)}; + EXPECT_EQ(convertedId1, "00000000-0000-0001-0000-000000000002"); + } + + { + const auto ramsesIdHigherBytes = std::pair{0x1000'0000'0000'0000ULL, 0x2000'0000'0000'0000ULL}; + const auto convertedId2{EditorObject::ramsesLogicIDAsObjectID(ramsesIdHigherBytes)}; + EXPECT_EQ(convertedId2, "10000000-0000-0000-2000-000000000000"); + } +} + +TEST(NodeTest, ramses_id_to_object_id_conversion) { + for (int i = 0; i < 10; i++) { + Node node; + std::string id = node.objectID(); + EXPECT_EQ(EditorObject::ramsesLogicIDAsObjectID(node.objectIDAsRamsesLogicID()), node.objectID()); + } } \ No newline at end of file diff --git a/datamodel/libCore/tests/Prefab_test.cpp b/datamodel/libCore/tests/Prefab_test.cpp index f07b0a71..b9d9890e 100644 --- a/datamodel/libCore/tests/Prefab_test.cpp +++ b/datamodel/libCore/tests/Prefab_test.cpp @@ -110,13 +110,13 @@ TEST_F(PrefabTest, check_id_copy_paste) { commandInterface.set({lua, {"uri"}}, (test_path() / "scripts/interface-scalar-types.lua").string()); auto inst = create_prefabInstance("inst", prefab); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); commandInterface.set({lua, {"inputs", "float"}}, 2.0); commandInterface.set({inst_lua, {"inputs", "float"}}, 3.0); auto pasted = commandInterface.pasteObjects(commandInterface.copyObjects({inst})); - auto inst_2 = raco::select(pasted); + auto inst_2 = select(pasted); auto inst_2_lua = inst_2->children_->get(0)->asRef(); ASSERT_TRUE(inst_2 != nullptr); ASSERT_TRUE(inst_2_lua != nullptr); @@ -155,7 +155,7 @@ TEST_F(PrefabTest, check_id_copy_paste_nesting) { EXPECT_EQ(lua_2->objectID(), EditorObject::XorObjectIDs(lua->objectID(), inst_3->objectID())); auto pasted = commandInterface.pasteObjects(commandInterface.copyObjects({inst_2})); - auto inst_2_copy = raco::select(pasted); + auto inst_2_copy = select(pasted); EXPECT_EQ(inst_2_copy->children_->size(), 1); auto inst_3_copy = inst_2_copy->children_->asVector()[0]; EXPECT_EQ(inst_3_copy->children_->size(), 1); @@ -259,8 +259,8 @@ end )"); commandInterface.set({lua, {"uri"}}, scriptFile); EXPECT_EQ(inst->children_->size(), 2); - auto inst_node = raco::select(inst->children_->asVector()); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_node = select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); EXPECT_TRUE(inst_node); EXPECT_TRUE(inst_lua); @@ -303,9 +303,9 @@ TEST_F(PrefabTest, link_broken_inside_prefab_status_gets_propagated_to_instances commandInterface.addLink({luaPrefabGlobal, {"outputs", "ovector3f"}} , {node, {"translation"}}); commandInterface.addLink({luaPrefabNodeChild, {"outputs", "out_float"}}, {luaPrefabGlobal, {"inputs", "float"}}); - auto inst_node = raco::select(inst->children_->asVector()); - auto inst_lua_prefab = raco::select(inst->children_->asVector()); - auto inst_lua_child = raco::select(inst_node->children_->asVector()); + auto inst_node = select(inst->children_->asVector()); + auto inst_lua_prefab = select(inst->children_->asVector()); + auto inst_lua_child = select(inst_node->children_->asVector()); std::vector refLinks{{ {{luaPrefabGlobal, {"outputs", "ovector3f"}}, {node, {"translation"}}}, {{luaPrefabNodeChild, {"outputs", "out_float"}}, {luaPrefabGlobal, {"inputs", "float"}}}, @@ -333,8 +333,8 @@ TEST_F(PrefabTest, link_lua_node_delete_lua_in_prefab) { commandInterface.set({inst, {"template"}}, prefab); EXPECT_EQ(inst->children_->size(), 2); - auto inst_node = raco::select(inst->children_->asVector()); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_node = select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); EXPECT_TRUE(inst_node); EXPECT_TRUE(inst_lua); @@ -538,7 +538,7 @@ TEST_F(PrefabTest, delete_prefab_with_node_with_meshnode_while_instance_exists) TEST_F(PrefabTest, update_inst_from_prefab_after_remove_link) { ramses_base::HeadlessEngineBackend backend; - raco::application::RaCoApplication app{backend}; + application::RaCoApplication app{backend}; auto& cmd = *app.activeRaCoProject().commandInterface(); auto prefab = create(cmd, "prefab"); @@ -558,8 +558,8 @@ end cmd.addLink({lua, {"inputs", "v"}}, {node, {"translation"}}); app.doOneLoop(); - auto inst_node = raco::select(inst->children_->asVector()); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_node = select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); cmd.set({lua, {"inputs", "v", "x"}}, 2.0); cmd.set({inst_lua, {"inputs", "v", "x"}}, 3.0); @@ -581,7 +581,7 @@ TEST_F(PrefabTest, restore_cached_lua_script_prop_when_breaking_uri) { auto inst = create("inst"); commandInterface.set({inst, {"template"}}, prefab); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); commandInterface.set({lua, {"inputs", "float"}}, 2.0); @@ -609,7 +609,7 @@ TEST_F(PrefabTest, restore_cached_lua_interface_prop_when_breaking_uri) { auto inst = create("inst"); commandInterface.set({inst, {"template"}}, prefab); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); commandInterface.set({lua, {"inputs", "float"}}, 2.0); commandInterface.set({inst_lua, {"inputs", "float"}}, 3.0); @@ -647,9 +647,9 @@ end )"); commandInterface.set({lua, {"uri"}}, scriptFile); EXPECT_EQ(inst->children_->size(), 2); - auto inst_node = raco::select(inst->children_->asVector()); - auto inst_meshnode = raco::select(inst->children_->asVector()); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_node = select(inst->children_->asVector()); + auto inst_meshnode = select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); EXPECT_TRUE(inst_node); EXPECT_FALSE(inst_meshnode); EXPECT_TRUE(inst_lua); @@ -664,8 +664,8 @@ end core::PrefabOperations::globalPrefabUpdate(context); EXPECT_EQ(inst->children_->size(), 2); - inst_meshnode = raco::select(inst->children_->asVector()); - inst_lua = raco::select(inst->children_->asVector()); + inst_meshnode = select(inst->children_->asVector()); + inst_lua = select(inst->children_->asVector()); EXPECT_TRUE(inst_meshnode); EXPECT_TRUE(inst_lua); // These are the crucial checks: @@ -686,7 +686,7 @@ TEST_F(PrefabTest, update_luascript_module_dependant_in_prefab_no_module) { auto lua = create_lua("lua", "scripts/moduleDependency.lua", prefab); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); ASSERT_NE(inst_lua, nullptr); ASSERT_TRUE(commandInterface.errors().hasError(ValueHandle{lua, {"luaModules", "coalas"}})); ASSERT_TRUE(commandInterface.errors().hasError(ValueHandle{inst_lua, {"luaModules", "coalas"}})); @@ -704,7 +704,7 @@ TEST_F(PrefabTest, update_luascript_module_dependant_in_prefab_add_module) { commandInterface.set({lua, {"luaModules", "coalas"}}, luaModule); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); ASSERT_NE(inst_lua, nullptr); ASSERT_FALSE(commandInterface.errors().hasError({lua})); ASSERT_FALSE(commandInterface.errors().hasError({inst_lua})); @@ -723,7 +723,7 @@ TEST_F(PrefabTest, update_luascript_module_dependant_in_prefab_remove_module) { commandInterface.set({lua, {"luaModules", "coalas"}}, luaModule); commandInterface.set({lua, {"luaModules", "coalas"}}, SEditorObject{}); - auto inst_lua = raco::select(inst->children_->asVector()); + auto inst_lua = select(inst->children_->asVector()); ASSERT_NE(inst_lua, nullptr); ASSERT_TRUE(commandInterface.errors().hasError(ValueHandle{lua, {"luaModules", "coalas"}})); ASSERT_TRUE(commandInterface.errors().hasError(ValueHandle{inst_lua, {"luaModules", "coalas"}})); @@ -999,8 +999,8 @@ TEST_F(PrefabTest, link_strong_to_weak_transition) { commandInterface.addLink(ValueHandle{start, {"outputs", "ofloat"}}, ValueHandle{end, {"inputs", "float"}}); auto inst = create_prefabInstance("inst", prefab); - auto inst_start = raco::select(inst->children_->asVector(), "start"); - auto inst_end = raco::select(inst->children_->asVector(), "end"); + auto inst_start = select(inst->children_->asVector(), "start"); + auto inst_end = select(inst->children_->asVector(), "end"); checkLinks({{{start, {"outputs", "ofloat"}}, {end, {"inputs", "float"}}, true, false}, {{inst_start, {"outputs", "ofloat"}}, {inst_end, {"inputs", "float"}}, true, false}}); @@ -1028,8 +1028,8 @@ TEST_F(PrefabTest, link_strong_valid_to_weak_invalid_transition) { commandInterface.addLink(ValueHandle{start, {"outputs", "ofloat"}}, ValueHandle{end, {"inputs", "float"}}); auto inst = create_prefabInstance("inst", prefab); - auto inst_start = raco::select(inst->children_->asVector(), "start"); - auto inst_end = raco::select(inst->children_->asVector(), "end"); + auto inst_start = select(inst->children_->asVector(), "start"); + auto inst_end = select(inst->children_->asVector(), "end"); checkLinks({{{start, {"outputs", "ofloat"}}, {end, {"inputs", "float"}}, true, false}, {{inst_start, {"outputs", "ofloat"}}, {inst_end, {"inputs", "float"}}, true, false}}); @@ -1060,7 +1060,7 @@ TEST_F(PrefabTest, prefab_update_from_optimized_saved_file) { std::string lua_id; { - raco::application::RaCoApplication app{backend}; + application::RaCoApplication app{backend}; auto& cmd = *app.activeRaCoProject().commandInterface(); auto prefab = create(cmd, "prefab"); @@ -1088,9 +1088,9 @@ TEST_F(PrefabTest, prefab_update_from_optimized_saved_file) { } { - raco::application::RaCoApplicationLaunchSettings settings; + application::RaCoApplicationLaunchSettings settings; settings.initialProject = (test_path() / "test.rca").string().c_str(); - raco::application::RaCoApplication app{backend, settings}; + application::RaCoApplication app{backend, settings}; auto& project = *app.activeRaCoProject().project(); diff --git a/datamodel/libCore/tests/ProjectMigration_test.cpp b/datamodel/libCore/tests/ProjectMigration_test.cpp index d0507cc1..e75674f6 100644 --- a/datamodel/libCore/tests/ProjectMigration_test.cpp +++ b/datamodel/libCore/tests/ProjectMigration_test.cpp @@ -28,6 +28,7 @@ #include "ramses_base/BaseEngineBackend.h" #include "user_types/Animation.h" +#include "user_types/BlitPass.h" #include "user_types/CubeMap.h" #include "user_types/Enumerations.h" #include "user_types/Material.h" @@ -54,7 +55,7 @@ static_assert(!std::is_same, serializa struct MigrationTest : public TestEnvironmentCore { ramses_base::HeadlessEngineBackend backend; - raco::application::RaCoApplication application{backend}; + application::RaCoApplication application{backend}; // Check if the property types coming out of the migration code agree with the types // in the current version of the user types. @@ -74,7 +75,7 @@ struct MigrationTest : public TestEnvironmentCore { } } - std::unique_ptr loadAndCheckJson(QString filename, int* outFileVersion = nullptr) { + std::unique_ptr loadAndCheckJson(QString filename, int* outFileVersion = nullptr) { QFile file{filename}; EXPECT_TRUE(file.open(QIODevice::ReadOnly | QIODevice::Text)); auto document{QJsonDocument::fromJson(file.readAll())}; @@ -92,7 +93,7 @@ struct MigrationTest : public TestEnvironmentCore { checkPropertyTypes(deserializedIR); LoadContext loadContext; - auto racoproject = raco::application::RaCoProject::loadFromFile(filename, &application, loadContext); + auto racoproject = application::RaCoProject::loadFromFile(filename, &application, loadContext); EXPECT_TRUE(racoproject != nullptr); return racoproject; @@ -474,17 +475,17 @@ TEST_F(MigrationTest, migrate_from_V35) { auto inst = core::Queries::findByName(racoproject->project()->instances(), "PrefabInstance")->as(); auto global_lua = core::Queries::findByName(racoproject->project()->instances(), "global_control")->as(); - auto prefab_lua_types = raco::select(prefab->children_->asVector(), "types-scalar"); - auto prefab_int_types = raco::select(prefab->children_->asVector(), "types-scalar"); - auto prefab_int_array = raco::select(prefab->children_->asVector(), "array"); + auto prefab_lua_types = select(prefab->children_->asVector(), "types-scalar"); + auto prefab_int_types = select(prefab->children_->asVector(), "types-scalar"); + auto prefab_int_array = select(prefab->children_->asVector(), "array"); EXPECT_EQ(prefab_int_types->inputs_->get("float")->asDouble(), 1.0); EXPECT_EQ(prefab_int_types->inputs_->get("integer")->asInt(), 2); EXPECT_EQ(prefab_int_types->inputs_->get("integer64")->asInt64(), 3); - auto inst_lua_types = raco::select(inst->children_->asVector(), "types-scalar"); - auto inst_int_types = raco::select(inst->children_->asVector(), "types-scalar"); - auto inst_int_array = raco::select(inst->children_->asVector(), "array"); + auto inst_lua_types = select(inst->children_->asVector(), "types-scalar"); + auto inst_int_types = select(inst->children_->asVector(), "types-scalar"); + auto inst_int_array = select(inst->children_->asVector(), "array"); EXPECT_EQ(inst_int_types->objectID(), EditorObject::XorObjectIDs(prefab_int_types->objectID(), inst->objectID())); @@ -510,15 +511,15 @@ TEST_F(MigrationTest, migrate_from_V35_extref) { auto inst = core::Queries::findByName(racoproject->project()->instances(), "PrefabInstance")->as(); auto global_lua = core::Queries::findByName(racoproject->project()->instances(), "global_control")->as(); - auto prefab_lua_types = raco::select(prefab->children_->asVector(), "types-scalar"); - auto prefab_int_types = raco::select(prefab->children_->asVector(), "types-scalar"); + auto prefab_lua_types = select(prefab->children_->asVector(), "types-scalar"); + auto prefab_int_types = select(prefab->children_->asVector(), "types-scalar"); EXPECT_EQ(prefab_int_types->inputs_->get("float")->asDouble(), 1.0); EXPECT_EQ(prefab_int_types->inputs_->get("integer")->asInt(), 2); EXPECT_EQ(prefab_int_types->inputs_->get("integer64")->asInt64(), 3); - auto inst_lua_types = raco::select(inst->children_->asVector(), "types-scalar"); - auto inst_int_types = raco::select(inst->children_->asVector(), "types-scalar"); + auto inst_lua_types = select(inst->children_->asVector(), "types-scalar"); + auto inst_int_types = select(inst->children_->asVector(), "types-scalar"); EXPECT_EQ(inst_int_types->objectID(), EditorObject::XorObjectIDs(prefab_int_types->objectID(), inst->objectID())); @@ -539,8 +540,8 @@ TEST_F(MigrationTest, migrate_from_V35_extref_nested) { auto inst = core::Queries::findByName(racoproject->project()->instances(), "PrefabInstance")->as(); auto global_lua = core::Queries::findByName(racoproject->project()->instances(), "global_control")->as(); - auto prefab_lua_types = raco::select(prefab->children_->asVector(), "types-scalar"); - auto prefab_int_types = raco::select(prefab->children_->asVector(), "types-scalar"); + auto prefab_lua_types = select(prefab->children_->asVector(), "types-scalar"); + auto prefab_int_types = select(prefab->children_->asVector(), "types-scalar"); EXPECT_EQ(prefab_int_types->inputs_->get("float")->asDouble(), 1.0); EXPECT_EQ(prefab_int_types->inputs_->get("integer")->asInt(), 2); @@ -548,9 +549,9 @@ TEST_F(MigrationTest, migrate_from_V35_extref_nested) { auto inst_nested = Queries::findByName(inst->children_->asVector(), "inst_nested"); - auto inst_lua_types = raco::select(inst_nested->children_->asVector(), "types-scalar"); - auto inst_int_types = raco::select(inst_nested->children_->asVector(), "types-scalar"); - auto inst_int_array = raco::select(inst_nested->children_->asVector(), "array"); + auto inst_lua_types = select(inst_nested->children_->asVector(), "types-scalar"); + auto inst_int_types = select(inst_nested->children_->asVector(), "types-scalar"); + auto inst_int_array = select(inst_nested->children_->asVector(), "array"); EXPECT_EQ(inst_int_types->objectID(), EditorObject::XorObjectIDs(prefab_int_types->objectID(), inst_nested->objectID())); @@ -960,8 +961,8 @@ TEST_F(MigrationTest, migrate_from_V54) { auto renderTarget = core::Queries::findByName(racoproject->project()->instances(), "RenderTarget")->as(); auto renderPass = core::Queries::findByName(racoproject->project()->instances(), "MainRenderPass")->as(); - EXPECT_EQ(animation->animationChannels_->asVector(), - std::vector({animationChannel, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr})); + EXPECT_EQ(animation->animationChannels_->asVector(), + std::vector({animationChannel, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr})); EXPECT_EQ(skin->targets_->asVector(), std::vector({meshnode})); EXPECT_EQ(renderTarget->buffers_->asVector(), @@ -1131,8 +1132,8 @@ TEST_F(MigrationTest, migrate_from_V58) { auto renderTargetMS = core::Queries::findByName(racoproject->project()->instances(), "RenderTargetMS")->as(); auto renderPass = core::Queries::findByName(racoproject->project()->instances(), "MainRenderPass")->as(); - EXPECT_EQ(animation->animationChannels_->asVector(), - std::vector({animationChannel, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr})); + EXPECT_EQ(animation->animationChannels_->asVector(), + std::vector({animationChannel, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr})); EXPECT_EQ(skin->targets_->asVector(), std::vector({meshnode})); EXPECT_EQ(renderTarget->buffers_->asVector(), @@ -1314,6 +1315,82 @@ TEST_F(MigrationTest, migrate_from_V60) { EXPECT_EQ(*meshnode_enabled_anno->featureLevel_, 1); } +TEST_F(MigrationTest, migrate_from_V2001) { + using namespace raco; + auto racoproject = loadAndCheckJson(QString::fromStdString((test_path() / "migrationTestData" / "V2001.rca").string())); + + + auto animation = core::Queries::findByName(racoproject->project()->instances(), "Animation")->as(); + auto channel_1 = core::Queries::findByName(racoproject->project()->instances(), "channel-1")->as(); + auto channel_2 = core::Queries::findByName(racoproject->project()->instances(), "channel-2")->as(); + + EXPECT_EQ(animation->animationChannels_->asVector(), + std::vector({channel_1, channel_2})); +} + +TEST_F(MigrationTest, migrate_from_V2003) { + using namespace raco; + auto racoproject = loadAndCheckJson(QString::fromStdString((test_path() / "migrationTestData" / "V2003.rca").string())); + + auto buffer= core::Queries::findByName(racoproject->project()->instances(), "RenderBuffer")->as(); + EXPECT_EQ(*buffer->width_, 12); + EXPECT_EQ(*buffer->height_, 13); + + auto buffer_ms = core::Queries::findByName(racoproject->project()->instances(), "RenderBufferMS")->as(); + EXPECT_EQ(*buffer_ms->width_, 14); + EXPECT_EQ(*buffer_ms->height_, 15); + EXPECT_EQ(*buffer_ms->sampleCount_, 3); +} + +TEST_F(MigrationTest, migrate_from_V2004) { + using namespace raco; + auto racoproject = loadAndCheckJson(QString::fromStdString((test_path() / "migrationTestData" / "V2004.rca").string())); + + auto settings = core::Queries::findByName(racoproject->project()->instances(), "V2004")->as(); + EXPECT_EQ(*settings->viewport_->i1_, 123); + EXPECT_EQ(*settings->viewport_->i2_, 234); + EXPECT_EQ(*settings->viewport_->i1_.staticQuery>().max_, 8192); + EXPECT_EQ(*settings->viewport_->i2_.staticQuery>().max_, 8192); + + auto perspCamera = core::Queries::findByName(racoproject->project()->instances(), "PerspectiveCamera")->as(); + EXPECT_EQ(*perspCamera->viewport_->width_, 888); + EXPECT_EQ(*perspCamera->viewport_->height_, 777); + EXPECT_EQ(*perspCamera->viewport_->width_.staticQuery>().max_, 8192); + EXPECT_EQ(*perspCamera->viewport_->height_.staticQuery>().max_, 8192); + + auto orthoCamera = core::Queries::findByName(racoproject->project()->instances(), "OrthographicCamera")->as(); + EXPECT_EQ(*orthoCamera->viewport_->width_, 888); + EXPECT_EQ(*orthoCamera->viewport_->height_, 777); + EXPECT_EQ(*orthoCamera->viewport_->width_.staticQuery>().max_, 8192); + EXPECT_EQ(*orthoCamera->viewport_->height_.staticQuery>().max_, 8192); + + auto buffer = core::Queries::findByName(racoproject->project()->instances(), "RenderBuffer")->as(); + EXPECT_EQ(*buffer->width_, 123); + EXPECT_EQ(*buffer->height_, 234); + EXPECT_EQ(*buffer->width_.staticQuery>().max_, 8192); + EXPECT_EQ(*buffer->height_.staticQuery>().max_, 8192); + + auto buffer_ms = core::Queries::findByName(racoproject->project()->instances(), "RenderBufferMS")->as(); + EXPECT_EQ(*buffer_ms->width_, 123); + EXPECT_EQ(*buffer_ms->height_, 234); + EXPECT_EQ(*buffer_ms->width_.staticQuery>().max_, 8192); + EXPECT_EQ(*buffer_ms->height_.staticQuery>().max_, 8192); + + auto blitpass = core::Queries::findByName(racoproject->project()->instances(), "BlitPass")->as(); + EXPECT_EQ(*blitpass->sourceX_, 12); + EXPECT_EQ(*blitpass->sourceY_, 13); + EXPECT_EQ(*blitpass->destinationX_, 14); + EXPECT_EQ(*blitpass->destinationY_, 15); + EXPECT_EQ(*blitpass->width_, 123); + EXPECT_EQ(*blitpass->height_, 234); + EXPECT_EQ(*blitpass->sourceX_.staticQuery>().max_, 8192); + EXPECT_EQ(*blitpass->sourceY_.staticQuery>().max_, 8192); + EXPECT_EQ(*blitpass->destinationX_.staticQuery>().max_, 8192); + EXPECT_EQ(*blitpass->destinationY_.staticQuery>().max_, 8192); + EXPECT_EQ(*blitpass->width_.staticQuery>().max_, 8192); + EXPECT_EQ(*blitpass->height_.staticQuery>().max_, 8192); +} + TEST_F(MigrationTest, migrate_from_current) { // Check for changes in serialized JSON in newest version. // Should detect changes in data model with missing migration code. diff --git a/datamodel/libCore/tests/Serialization_test.cpp b/datamodel/libCore/tests/Serialization_test.cpp index fd5d3a0f..60932dbd 100644 --- a/datamodel/libCore/tests/Serialization_test.cpp +++ b/datamodel/libCore/tests/Serialization_test.cpp @@ -239,7 +239,7 @@ TEST_F(SerializationTest, serializeNodeAndScript_withLink) { } TEST_F(SerializationTest, serializeObjects_luaScriptLinkedToNode) { - auto objs{raco::createLinkedScene(context, test_relative_path())}; + auto objs{createLinkedScene(context, test_relative_path())}; std::map externalProjectsMap; std::map originFolders; diff --git a/datamodel/libCore/tests/Undo_test.cpp b/datamodel/libCore/tests/Undo_test.cpp index ed332659..5ede8c4b 100644 --- a/datamodel/libCore/tests/Undo_test.cpp +++ b/datamodel/libCore/tests/Undo_test.cpp @@ -763,7 +763,7 @@ TEST_F(UndoTest, mesh_asset_with_anims_import_multiple_undo_redo) { desc.absPath = test_path().append("meshes/InterpolationTest/InterpolationTest.gltf").string(); desc.bakeAllSubmeshes = false; - auto [scenegraph, dummyCacheEntry] = raco::getMeshSceneGraphWithHandler(commandInterface.meshCache(), desc); + auto [scenegraph, dummyCacheEntry] = getMeshSceneGraphWithHandler(commandInterface.meshCache(), desc); commandInterface.insertAssetScenegraph(scenegraph, desc.absPath, nullptr); @@ -935,9 +935,6 @@ void main() { ASSERT_NO_THROW((core::ValueHandle{meshnode, {"materials", "material", "uniforms", "u_color"}}.asDouble())); } -#if (!defined(__linux__)) -// awaitPreviewDirty does not work in Linux as expected. See RAOS-692 - TEST_F(UndoTest, lua_resync_after_undo) { TextFile luaFile = makeFile("test.lua", R"( function interface(IN,OUT) @@ -966,7 +963,7 @@ end recorder.reset(); utils::file::write(luaFile.path.string(), altLuaScript); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, lua)); + EXPECT_TRUE(awaitPreviewDirty(recorder, lua)); EXPECT_FALSE(luaOutputs.hasProperty("vec")); EXPECT_TRUE(luaOutputs.hasProperty("renamed")); @@ -981,7 +978,6 @@ end EXPECT_TRUE(luaOutputs.hasProperty("renamed")); } - TEST_F(UndoTest, link_remove_break_on_undo) { TextFile luaFile = makeFile("test.lua", R"( function interface(IN,OUT) @@ -1018,7 +1014,7 @@ end recorder.reset(); utils::file::write(luaFile.path.string(), altLuaScript); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, lua)); + EXPECT_TRUE(awaitPreviewDirty(recorder, lua)); EXPECT_FALSE(luaOutputs.hasProperty("vec")); EXPECT_TRUE(luaOutputs.hasProperty("renamed")); @@ -1072,7 +1068,7 @@ end recorder.reset(); utils::file::write(luaFile.path.string(), altLuaScript); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, lua)); + EXPECT_TRUE(awaitPreviewDirty(recorder, lua)); EXPECT_FALSE(luaOutputs.hasProperty("vec")); EXPECT_TRUE(luaOutputs.hasProperty("renamed")); @@ -1126,7 +1122,7 @@ end recorder.reset(); utils::file::write(luaFile.path.string(), altLuaScript); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, lua)); + EXPECT_TRUE(awaitPreviewDirty(recorder, lua)); EXPECT_FALSE(luaOutputs.hasProperty("vec")); EXPECT_TRUE(luaOutputs.hasProperty("renamed")); @@ -1140,7 +1136,7 @@ end checkLinks({{sprop, eprop, true}}); utils::file::write(luaFile.path.string(), origLuaScript); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, lua)); + EXPECT_TRUE(awaitPreviewDirty(recorder, lua)); undoStack.undo(); checkLinks({}); @@ -1150,8 +1146,6 @@ end ASSERT_FALSE(static_cast(ValueHandle(sprop))); } -#endif - TEST_F(UndoTest, add_remove_property_ref) { auto refTarget = create("foo"); auto refSource = create("sourceObject"); diff --git a/datamodel/libCore/tests/expectations/MeshNodeWithMesh.json b/datamodel/libCore/tests/expectations/MeshNodeWithMesh.json index 02557c12..ed0844f5 100644 --- a/datamodel/libCore/tests/expectations/MeshNodeWithMesh.json +++ b/datamodel/libCore/tests/expectations/MeshNodeWithMesh.json @@ -112,7 +112,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -124,8 +124,8 @@ "annotations": [ { "properties": { - "max": 7680, - "min": -7680 + "max": 8192, + "min": -8192 }, "typeName": "RangeAnnotationInt" } @@ -136,8 +136,8 @@ "annotations": [ { "properties": { - "max": 7680, - "min": -7680 + "max": 8192, + "min": -8192 }, "typeName": "RangeAnnotationInt" } @@ -148,7 +148,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" diff --git a/datamodel/libCore/tests/migrationTestData/V2001.rca b/datamodel/libCore/tests/migrationTestData/V2001.rca new file mode 100644 index 00000000..215b7986 --- /dev/null +++ b/datamodel/libCore/tests/migrationTestData/V2001.rca @@ -0,0 +1,629 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2001, + "instances": [ + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "b53bd1d2-7d43-4b2f-9972-2b9a9d545e35", + "objectName": "V2001", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "animationChannels": [ + "f8ae9152-7197-4ace-b9b3-91ec510055e1", + "7ee8357f-418c-477f-a7a0-7940ac84860e" + ], + "objectID": "5db9ce5d-c034-49f5-8fcd-b1de0d7cbbef", + "objectName": "Animation", + "progress": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Animation" + }, + { + "properties": { + "animationIndex": 0, + "objectID": "7ee8357f-418c-477f-a7a0-7940ac84860e", + "objectName": "channel-2", + "samplerIndex": 0, + "uri": "" + }, + "typeName": "AnimationChannel" + }, + { + "properties": { + "animationIndex": 0, + "objectID": "f8ae9152-7197-4ace-b9b3-91ec510055e1", + "objectName": "channel-1", + "samplerIndex": 0, + "uri": "" + }, + "typeName": "AnimationChannel" + } + ], + "links": [ + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannel]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/datamodel/libCore/tests/migrationTestData/V2003.rca b/datamodel/libCore/tests/migrationTestData/V2003.rca new file mode 100644 index 00000000..9fb4b1cd --- /dev/null +++ b/datamodel/libCore/tests/migrationTestData/V2003.rca @@ -0,0 +1,691 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2003, + "instances": [ + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "083288de-0225-4bed-8135-4e07c6c5cd5a", + "objectName": "V2003", + "pythonOnSaveScript": "", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "format": 4, + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 15 + }, + "objectID": "d8a77eb6-06a0-43b2-95f4-e6ade78071fa", + "objectName": "RenderBufferMS", + "sampleCount": { + "annotations": [ + { + "properties": { + "max": 8, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 3 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 14 + } + }, + "typeName": "RenderBufferMS" + }, + { + "properties": { + "anisotropy": { + "annotations": [ + { + "properties": { + "max": 32000, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "format": 4, + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 13 + }, + "magSamplingMethod": 0, + "minSamplingMethod": 0, + "objectID": "e09fd811-6544-4848-b43d-1cacde7f055b", + "objectName": "RenderBuffer", + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 12 + }, + "wrapUMode": 0, + "wrapVMode": 0 + }, + "typeName": "RenderBuffer" + } + ], + "links": [ + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/datamodel/libCore/tests/migrationTestData/V2004.rca b/datamodel/libCore/tests/migrationTestData/V2004.rca new file mode 100644 index 00000000..7c4355c3 --- /dev/null +++ b/datamodel/libCore/tests/migrationTestData/V2004.rca @@ -0,0 +1,1307 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2004, + "instances": [ + { + "properties": { + "enabled": true, + "frustum": { + "bottomPlane": { + "annotations": [ + { + "properties": { + "max": 0, + "min": -1000 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": -10 + }, + "farPlane": { + "annotations": [ + { + "properties": { + "max": 10000, + "min": 100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1000 + }, + "leftPlane": { + "annotations": [ + { + "properties": { + "max": 0, + "min": -1000 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": -10 + }, + "nearPlane": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0.1 + }, + "rightPlane": { + "annotations": [ + { + "properties": { + "max": 1000, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 10 + }, + "topPlane": { + "annotations": [ + { + "properties": { + "max": 1000, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 10 + } + }, + "objectID": "2bf34d57-3ad1-48a4-ac27-ace003f55167", + "objectName": "OrthographicCamera", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "viewport": { + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 777 + }, + "offsetX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "offsetY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 888 + } + }, + "visibility": true + }, + "typeName": "OrthographicCamera" + }, + { + "properties": { + "enabled": true, + "frustum": { + "order": [ + "nearPlane", + "farPlane", + "fieldOfView", + "aspectRatio" + ], + "properties": { + "aspectRatio": { + "annotations": [ + { + "properties": { + "name": "aspectRatio" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 4, + "min": 0.5 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 2 + }, + "farPlane": { + "annotations": [ + { + "properties": { + "name": "farPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 10000, + "min": 100 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 1000 + }, + "fieldOfView": { + "annotations": [ + { + "properties": { + "name": "fieldOfView" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 120, + "min": 10 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 35 + }, + "nearPlane": { + "annotations": [ + { + "properties": { + "name": "nearPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 1, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 0.1 + } + } + }, + "frustumType": 0, + "objectID": "34d3f7f0-1d2d-4d1d-adc1-4eee283a7b80", + "objectName": "PerspectiveCamera", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "viewport": { + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 777 + }, + "offsetX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "offsetY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 888 + } + }, + "visibility": true + }, + "typeName": "PerspectiveCamera" + }, + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "71454add-eb56-4288-9057-825539914bed", + "objectName": "V2004", + "pythonOnSaveScript": "", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 234 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "anisotropy": { + "annotations": [ + { + "properties": { + "max": 32000, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "format": 4, + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 234 + }, + "magSamplingMethod": 0, + "minSamplingMethod": 0, + "objectID": "16718bb0-058f-4b13-8105-68d98bf23a9f", + "objectName": "RenderBuffer", + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "wrapUMode": 0, + "wrapVMode": 0 + }, + "typeName": "RenderBuffer" + }, + { + "properties": { + "destinationX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 14 + }, + "destinationY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 15 + }, + "enabled": true, + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 234 + }, + "objectID": "631bab5e-2a9e-407a-9c4a-59d2ea44ff8c", + "objectName": "BlitPass", + "renderOrder": 0, + "sourceRenderBuffer": null, + "sourceRenderBufferMS": null, + "sourceX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 12 + }, + "sourceY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 13 + }, + "targetRenderBuffer": null, + "targetRenderBufferMS": null, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + } + }, + "typeName": "BlitPass" + }, + { + "properties": { + "format": 4, + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 234 + }, + "objectID": "dc208dbd-5bc6-4bb0-b4f5-6710c82dd65c", + "objectName": "RenderBufferMS", + "sampleCount": { + "annotations": [ + { + "properties": { + "max": 8, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + } + }, + "typeName": "RenderBufferMS" + } + ], + "links": [ + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/datamodel/libCore/tests/migrationTestData/version-current.rca b/datamodel/libCore/tests/migrationTestData/version-current.rca index 6ca5fc1d..cab9413f 100644 --- a/datamodel/libCore/tests/migrationTestData/version-current.rca +++ b/datamodel/libCore/tests/migrationTestData/version-current.rca @@ -2,7 +2,7 @@ "externalProjects": { }, "featureLevel": 1, - "fileVersion": 2001, + "fileVersion": 2005, "instances": [ { "properties": { @@ -209,7 +209,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -221,7 +221,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": -7680 }, "typeName": "RangeAnnotationInt" @@ -233,7 +233,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": -7680 }, "typeName": "RangeAnnotationInt" @@ -245,7 +245,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -493,7 +493,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -505,7 +505,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": -7680 }, "typeName": "RangeAnnotationInt" @@ -517,7 +517,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": -7680 }, "typeName": "RangeAnnotationInt" @@ -529,7 +529,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -648,6 +648,7 @@ "featureLevel": 1, "objectID": "71454add-eb56-4288-9057-825539914bed", "objectName": "test-offscreen-tex-uniform-migration-material", + "pythonOnSaveScript": "", "saveAsZip": false, "sceneId": { "annotations": [ @@ -666,7 +667,7 @@ "annotations": [ { "properties": { - "max": 4096, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -678,7 +679,7 @@ "annotations": [ { "properties": { - "max": 4096, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -1421,7 +1422,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -1437,7 +1438,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -2237,7 +2238,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -2249,7 +2250,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -2262,7 +2263,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -2279,7 +2280,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -2291,7 +2292,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -2305,7 +2306,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 0 }, "typeName": "RangeAnnotationInt" @@ -2324,7 +2325,7 @@ "objectID": "9c2eeeea-cef0-42a5-9815-d32d38ccfd60", "objectName": "Timer", "outputs": { - "ticker_us": "5331962091" + "ticker_us": "2332962042566" } }, "typeName": "Timer" @@ -2376,6 +2377,16 @@ }, "typeName": "Mesh" }, + { + "properties": { + "componentArraySize": 1, + "componentType": 5, + "interpolationType": 0, + "objectID": "a5d43f2e-b91e-4f74-9ca0-33091a4b1d4e", + "objectName": "AnimationChannelRaco" + }, + "typeName": "AnimationChannelRaco" + }, { "properties": { "materialFilterMode": 0, @@ -2449,7 +2460,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -2475,7 +2486,7 @@ "annotations": [ { "properties": { - "max": 7680, + "max": 8192, "min": 1 }, "typeName": "RangeAnnotationInt" @@ -2706,7 +2717,7 @@ "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" }, "Animation": { - "animationChannels": "Array[AnimationChannel]::DisplayNameAnnotation::ResizableArray", + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", "metaData": "Table::DisplayNameAnnotation", "objectID": "String::HiddenProperty", @@ -2725,6 +2736,17 @@ "uri": "String::URIAnnotation::DisplayNameAnnotation", "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, "BlitPass": { "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", @@ -2928,6 +2950,7 @@ "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", "objectID": "String::HiddenProperty", "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", "saveAsZip": "Bool::DisplayNameAnnotation", "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", "viewport": "Vec2i::DisplayNameAnnotation" @@ -2936,27 +2959,27 @@ "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", - "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", "metaData": "Table::DisplayNameAnnotation", "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", "objectID": "String::HiddenProperty", "objectName": "String::DisplayNameAnnotation", "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", - "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" }, "RenderBufferMS": { "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", - "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", "metaData": "Table::DisplayNameAnnotation", "objectID": "String::HiddenProperty", "objectName": "String::DisplayNameAnnotation", - "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", - "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" }, "RenderLayer": { "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", diff --git a/datamodel/libDataStorage/include/data_storage/Table.h b/datamodel/libDataStorage/include/data_storage/Table.h index 7952ee71..be2c7a6d 100644 --- a/datamodel/libDataStorage/include/data_storage/Table.h +++ b/datamodel/libDataStorage/include/data_storage/Table.h @@ -13,6 +13,7 @@ #include "Value.h" #include +#include #include #include @@ -46,6 +47,7 @@ class Table : public ReflectionInterface { std::vector propertyNames() const; + std::set propertyNameSet() const; // array and dictionary interface // can add and remove array entries / named properties diff --git a/datamodel/libDataStorage/src/Table.cpp b/datamodel/libDataStorage/src/Table.cpp index 79347723..c0568719 100644 --- a/datamodel/libDataStorage/src/Table.cpp +++ b/datamodel/libDataStorage/src/Table.cpp @@ -264,4 +264,12 @@ std::vector Table::propertyNames() const { return result; } +std::set Table::propertyNameSet() const { + std::set result; + for (const auto& prop : properties_) { + result.insert(prop.first); + } + return result; +} + } diff --git a/datamodel/libTesting/include/testing/RaCoApplicationTest.h b/datamodel/libTesting/include/testing/RaCoApplicationTest.h index 10f6cdd4..5aa709b9 100644 --- a/datamodel/libTesting/include/testing/RaCoApplicationTest.h +++ b/datamodel/libTesting/include/testing/RaCoApplicationTest.h @@ -14,12 +14,21 @@ #include "ramses_base/HeadlessEngineBackend.h" #include "testing/RacoBaseTest.h" +#include "user_types/BlitPass.h" +#include "user_types/Mesh.h" +#include "user_types/MeshNode.h" +#include "user_types/Material.h" +#include "user_types/RenderLayer.h" +#include "user_types/RenderPass.h" + #pragma once +using namespace raco::user_types; + class RaCoApplicationTest : public RacoBaseTest<> { public: ramses_base::HeadlessEngineBackend backend{}; - raco::application::RaCoApplication application{backend, {{}, false, false, -1, -1, false}}; + application::RaCoApplication application{backend, {{}, false, false, -1, -1, false}}; core::ExternalProjectsStoreInterface* externalProjectStore() { return application.externalProjects(); @@ -38,11 +47,85 @@ class RaCoApplicationTest : public RacoBaseTest<> { }; template - std::shared_ptr create(std::string name, core::SEditorObject parent = nullptr) { + std::shared_ptr create(std::string name, core::SEditorObject parent = nullptr, const std::vector& tags = {}) { auto obj = std::dynamic_pointer_cast(commandInterface().createObject(C::typeDescription.typeName, name)); if (parent) { commandInterface().moveScenegraphChildren({obj}, parent); } + if (!tags.empty()) { + commandInterface().setTags({obj, {"tags"}}, tags); + } return obj; } + + user_types::SMesh create_mesh(const std::string& name, const std::string& relpath) { + auto mesh = create(name); + commandInterface().set({mesh, {"uri"}}, (RacoBaseTest<>::test_path() / relpath).string()); + return mesh; + } + + user_types::SMaterial create_material(const std::string& name, const std::string& relpathVertex, const std::string& relpathFragment, const std::string& relpathGeometry = std::string(), const std::vector& tags = {}) { + auto material = create(name, {}, tags); + if (relpathGeometry.length()) { + commandInterface().set({material, {"uriGeometry"}}, (RacoBaseTest<>::test_path() / relpathGeometry).string()); + } + commandInterface().set({material, {"uriVertex"}}, (RacoBaseTest<>::test_path() / relpathVertex).string()); + commandInterface().set({material, {"uriFragment"}}, (RacoBaseTest<>::test_path() / relpathFragment).string()); + return material; + } + + user_types::SMeshNode create_meshnode(const std::string& name, user_types::SMesh mesh, user_types::SMaterial material, user_types::SEditorObject parent = nullptr, const std::vector& tags = {}) { + auto meshnode = create(name, parent, tags); + commandInterface().set({meshnode, {"mesh"}}, mesh); + commandInterface().set({meshnode, {"materials", "material", "material"}}, material); + return meshnode; + } + + user_types::SRenderLayer create_layer(const std::string& name, + const std::vector& tags = {}, + const std::vector>& renderables = {}, + const std::vector& matFilterTags = {}, + bool filterExclusive = true) { + auto layer = create(name, nullptr, tags); + commandInterface().setRenderableTags({layer, &RenderLayer::renderableTags_}, renderables); + if (!matFilterTags.empty()) { + commandInterface().setTags({layer, &user_types::RenderLayer::materialFilterTags_}, matFilterTags); + } + commandInterface().set({layer, &user_types::RenderLayer::materialFilterMode_}, + static_cast(filterExclusive ? user_types::ERenderLayerMaterialFilterMode::Exclusive : user_types::ERenderLayerMaterialFilterMode::Inclusive)); + + return layer; + } + + user_types::SRenderPass create_renderpass(const std::string& name, + SRenderTarget target, + const std::vector& layers, + int renderOrder = 0) { + auto renderpass = create(name); + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), target); + commandInterface().resizeArray({renderpass, &RenderPass::layers_}, layers.size()); + for (int index = 0; index < layers.size(); index++) { + commandInterface().set(ValueHandle(renderpass, &RenderPass::layers_)[index], layers[index]); + } + commandInterface().set({renderpass, &RenderPass::renderOrder_}, renderOrder); + return renderpass; + } + + user_types::SRenderTarget create_rendertarget(const std::string& name, const std::vector & buffers) { + auto rendertarget = create(name); + commandInterface().resizeArray({rendertarget, &RenderTarget::buffers_}, buffers.size()); + for (int index = 0; index < buffers.size(); index++) { + commandInterface().set(ValueHandle(rendertarget, &RenderTarget::buffers_)[index], buffers[index]); + } + return rendertarget; + } + + + user_types::SBlitPass create_blitpass(const std::string& name, int renderOrder, SRenderBuffer srcBuffer, SRenderBuffer targetBuffer) { + auto renderpass = create(name); + commandInterface().set({renderpass, &BlitPass::renderOrder_}, renderOrder); + commandInterface().set({renderpass, &BlitPass::sourceRenderBuffer_}, srcBuffer); + commandInterface().set({renderpass, &BlitPass::targetRenderBuffer_}, targetBuffer); + return renderpass; + } }; diff --git a/datamodel/libTesting/include/testing/TestEnvironmentCore.h b/datamodel/libTesting/include/testing/TestEnvironmentCore.h index a017833a..39c680f6 100644 --- a/datamodel/libTesting/include/testing/TestEnvironmentCore.h +++ b/datamodel/libTesting/include/testing/TestEnvironmentCore.h @@ -28,6 +28,8 @@ #include "components/MeshCacheImpl.h" #include "user_types/UserObjectFactory.h" #include "utils/FileUtils.h" +#include "user_types/Animation.h" +#include "user_types/AnimationChannel.h" #include "user_types/Mesh.h" #include "user_types/MeshNode.h" #include "user_types/Material.h" @@ -35,6 +37,9 @@ #include "user_types/LuaScriptModule.h" #include "user_types/LuaInterface.h" #include "user_types/RenderLayer.h" +#include "user_types/RenderBuffer.h" +#include "user_types/RenderBufferMS.h" +#include "user_types/RenderTarget.h" #include "user_types/Skin.h" #include "user_types/Texture.h" #include "user_types/UserObjectFactory.h" @@ -50,13 +55,6 @@ #include #include -inline void clearQEventLoop() { - int argc = 0; - QCoreApplication eventLoop_{argc, nullptr}; - QCoreApplication::processEvents(); -} - - class TestUndoStack : public core::UndoStack { public: using Entry = core::UndoStack::Entry; @@ -92,7 +90,7 @@ class TestObjectFactory : public user_types::UserObjectFactory { }; -template +template struct TestEnvironmentCoreT : public RacoBaseTest { using BaseContext = core::BaseContext; using Project = core::Project; @@ -126,6 +124,24 @@ struct TestEnvironmentCoreT : public RacoBaseTest { return obj; } + user_types::SAnimationChannel create_animation_channel(const std::string& name, const std::string& relpath, int animationIndex, int samplerIndex) { + auto channel = create(name); + commandInterface.set({channel, &user_types::AnimationChannel::uri_}, (RacoBaseTest::test_path() / relpath).string()); + commandInterface.set({channel, &user_types::AnimationChannel::animationIndex_}, animationIndex); + commandInterface.set({channel, &user_types::AnimationChannel::samplerIndex_}, samplerIndex); + return channel; + } + + user_types::SAnimation create_animation(const std::string& name, const std::vector& channels) { + auto animation = create(name); + core::ValueHandle channelsHandle(animation, &user_types::Animation::animationChannels_); + commandInterface.resizeArray(channelsHandle, channels.size()); + for (auto index = 0; index < channels.size(); index++) { + commandInterface.set(channelsHandle[index], channels[index]); + } + return animation; + } + user_types::SMesh create_mesh(const std::string& name, const std::string& relpath) { auto mesh = create(name); commandInterface.set({mesh, {"uri"}}, (RacoBaseTest::test_path() / relpath).string()); @@ -206,6 +222,24 @@ struct TestEnvironmentCoreT : public RacoBaseTest { return layer; } + user_types::SRenderTarget create_rendertarget(const std::string& name, const std::vector& buffers) { + auto rendertarget = create(name); + commandInterface.resizeArray({rendertarget, &user_types::RenderTarget::buffers_}, buffers.size()); + for (int index = 0; index < buffers.size(); index++) { + commandInterface.set(core::ValueHandle(rendertarget, &user_types::RenderTarget::buffers_)[index], buffers[index]); + } + return rendertarget; + } + + user_types::SRenderTargetMS create_rendertarget_ms(const std::string& name, const std::vector& buffers) { + auto rendertarget = create(name); + commandInterface.resizeArray({rendertarget, &user_types::RenderTargetMS::buffers_}, buffers.size()); + for (int index = 0; index < buffers.size(); index++) { + commandInterface.set(core::ValueHandle(rendertarget, &user_types::RenderTargetMS::buffers_)[index], buffers[index]); + } + return rendertarget; + } + user_types::SSkin create_skin(const std::string& name, const std::string& relpath, int skinIndex, @@ -269,6 +303,25 @@ struct TestEnvironmentCoreT : public RacoBaseTest { ASSERT_LE(opTimeMs, maxMs) << "Operation took longer than allowed boundary of " << maxMs << " ms\nActual operation duration: " << opTimeMs << " ms"; } + inline void clearQEventLoop() { + QCoreApplication::processEvents(); + } + + inline bool awaitPreviewDirty(const core::DataChangeRecorder& recorder, const core::SEditorObject& obj, long long timeout = 5) { + const std::chrono::steady_clock::time_point timeoutTS = std::chrono::steady_clock::now() + std::chrono::seconds{timeout}; + auto dirtyObjects{recorder.getPreviewDirtyObjects()}; + while (std::find(dirtyObjects.begin(), dirtyObjects.end(), obj) == dirtyObjects.end()) { + if (std::chrono::steady_clock::now() > timeoutTS) { + assert(false && "Timeout"); + return false; + } + std::this_thread::sleep_for(std::chrono::milliseconds{5}); + QCoreApplication::processEvents(); + dirtyObjects = recorder.getPreviewDirtyObjects(); + } + return true; + } + TestEnvironmentCoreT(UserObjectFactoryInterface* objectFactory = &UserObjectFactory::getInstance(), ramses::EFeatureLevel featureLevel = ramses_base::BaseEngineBackend::maxFeatureLevel) : backend{}, meshCache{}, @@ -297,6 +350,12 @@ struct TestEnvironmentCoreT : public RacoBaseTest { clearQEventLoop(); } + // Apparently QCoreApplication needs to be initialized before the ProjectFileChangeMonitor is created, since that + // will create signal connections which don't work on Linux otherwise (but they do work on Windows). + // The application therefore needs to be defined before the MeshCacheImpl below which sets up + // a GenericFileChangeMonitorImpl. + int argc = 0; + ApplicationClass application{argc, nullptr}; ramses_base::HeadlessEngineBackend backend; components::MeshCacheImpl meshCache; diff --git a/datamodel/libTesting/include/testing/TestUtil.h b/datamodel/libTesting/include/testing/TestUtil.h index 8aa60226..b936fd3b 100644 --- a/datamodel/libTesting/include/testing/TestUtil.h +++ b/datamodel/libTesting/include/testing/TestUtil.h @@ -99,23 +99,6 @@ inline auto createAnimatedScene(ContextOrCommandInterface& context, const utils: link); } -inline bool awaitPreviewDirty(const core::DataChangeRecorder& recorder, const core::SEditorObject& obj, long long timeout = 5) { - const std::chrono::steady_clock::time_point timeoutTS = std::chrono::steady_clock::now() + std::chrono::seconds{timeout}; - auto dirtyObjects{recorder.getPreviewDirtyObjects()}; - int argc = 0; - QCoreApplication eventLoop_{argc, nullptr}; - while (std::find(dirtyObjects.begin(), dirtyObjects.end(), obj) == dirtyObjects.end()) { - if (std::chrono::steady_clock::now() > timeoutTS) { - assert(false && "Timeout"); - return false; - } - std::this_thread::sleep_for(std::chrono::milliseconds{5}); - QCoreApplication::processEvents(); - dirtyObjects = recorder.getPreviewDirtyObjects(); - } - return true; -} - inline void createGitLfsPlaceholderFile(const std::string& path) { std::fstream file; file.open(path, std::ios::out); diff --git a/datamodel/libUserTypes/CMakeLists.txt b/datamodel/libUserTypes/CMakeLists.txt index 050f31d1..43ce9799 100644 --- a/datamodel/libUserTypes/CMakeLists.txt +++ b/datamodel/libUserTypes/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(libUserTypes include/user_types/AnchorPoint.h include/user_types/Animation.h src/Animation.cpp include/user_types/AnimationChannel.h src/AnimationChannel.cpp + include/user_types/AnimationChannelRaco.h src/AnimationChannelRaco.cpp include/user_types/BaseCamera.h include/user_types/BaseObject.h include/user_types/BaseTexture.h diff --git a/datamodel/libUserTypes/include/user_types/Animation.h b/datamodel/libUserTypes/include/user_types/Animation.h index 05e8d0a0..093bc4cb 100644 --- a/datamodel/libUserTypes/include/user_types/Animation.h +++ b/datamodel/libUserTypes/include/user_types/Animation.h @@ -53,7 +53,7 @@ class Animation : public BaseObject { Property, LinkEndAnnotation> progress_{0.0, {"Progress"}, {0.0, 1.0}, {}}; - Property, DisplayNameAnnotation, ResizableArray> animationChannels_{{}, {"Animation Channels"}, {}}; + Property, DisplayNameAnnotation, ResizableArray> animationChannels_{{}, {"Animation Channels"}, {}}; Property outputs_{{}, {"Outputs"}}; }; diff --git a/datamodel/libUserTypes/include/user_types/AnimationChannel.h b/datamodel/libUserTypes/include/user_types/AnimationChannel.h index 05b77f53..b3823e92 100644 --- a/datamodel/libUserTypes/include/user_types/AnimationChannel.h +++ b/datamodel/libUserTypes/include/user_types/AnimationChannel.h @@ -12,18 +12,39 @@ #include "user_types/Mesh.h" #include "core/EngineInterface.h" +#include "user_types/Enumerations.h" namespace raco::user_types { -class AnimationChannel : public BaseObject { +class AnimationChannelBase : public BaseObject { public: - static inline const TypeDescriptor typeDescription = { "AnimationChannel", true }; + static inline const TypeDescriptor typeDescription = {"AnimationChannelBase", true}; + TypeDescriptor const& getTypeDescription() const override { + return typeDescription; + } + + AnimationChannelBase(std::string name = std::string(), std::string id = std::string()) + : BaseObject(name, id) { + } + + + PropertyInterface getOutputProperty() const; + + raco::core::SharedAnimationSamplerData currentSamplerData_; +}; + +using SAnimationChannelBase = std::shared_ptr; + + +class AnimationChannel : public AnimationChannelBase { +public: + static inline const TypeDescriptor typeDescription = {"AnimationChannel", true}; TypeDescriptor const& getTypeDescription() const override { return typeDescription; } AnimationChannel(const AnimationChannel& other) - : BaseObject(other), + : AnimationChannelBase(other), uri_(other.uri_), animationIndex_(other.animationIndex_), samplerIndex_(other.samplerIndex_) { @@ -31,7 +52,7 @@ class AnimationChannel : public BaseObject { } AnimationChannel(std::string name = std::string(), std::string id = std::string()) - : BaseObject(name, id) { + : AnimationChannelBase(name, id) { fillPropertyDescription(); } @@ -45,19 +66,15 @@ class AnimationChannel : public BaseObject { void updateFromExternalFile(BaseContext& context) override; - PropertyInterface getOutputProperty() const; - Property uri_{std::string(), {"glTF files (*.glTF *.glb);;All Files (*.*)", core::PathManager::FolderTypeKeys::Mesh}, DisplayNameAnnotation("Animation Source")}; Property animationIndex_{{}, DisplayNameAnnotation("Animation Index")}; Property samplerIndex_{{}, DisplayNameAnnotation("Sampler Index")}; - core::SharedAnimationSamplerData currentSamplerData_; - private: void createSamplerInfoBox(BaseContext& context, int animationAmount, int samplerAmount); }; using SAnimationChannel = std::shared_ptr; -} +} // namespace raco::user_types diff --git a/datamodel/libUserTypes/include/user_types/AnimationChannelRaco.h b/datamodel/libUserTypes/include/user_types/AnimationChannelRaco.h new file mode 100644 index 00000000..4f30c5b1 --- /dev/null +++ b/datamodel/libUserTypes/include/user_types/AnimationChannelRaco.h @@ -0,0 +1,79 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "user_types/AnimationChannel.h" + +namespace raco::user_types { + +class AnimationChannelRaco : public AnimationChannelBase { +public: + static inline const char* PROPNAME_TIME_STAMPS{"timeStamps"}; + static inline const char* PROPNAME_KEYFRAMES{"keyframes"}; + static inline const char* PROPNAME_TANGENTS_IN{"tangentsIn"}; + static inline const char* PROPNAME_TANGENTS_OUT{"tangentsOut"}; + + static inline const TypeDescriptor typeDescription = {"AnimationChannelRaco", true}; + TypeDescriptor const& getTypeDescription() const override { + return typeDescription; + } + + AnimationChannelRaco(const AnimationChannelRaco& other) + : AnimationChannelBase(other), + componentType_(other.componentType_), + interpolationType_(other.interpolationType_), + componentArraySize_(other.componentArraySize_), + data_(other.data_) { + fillPropertyDescription(); + } + + AnimationChannelRaco(std::string name = std::string(), std::string id = std::string()) + : AnimationChannelBase(name, id) { + fillPropertyDescription(); + } + + void fillPropertyDescription() { + properties_.emplace_back("componentType", &componentType_); + properties_.emplace_back("interpolationType", &interpolationType_); + properties_.emplace_back("componentArraySize", &componentArraySize_); + properties_.emplace_back("data", &data_); + } + + int getOuputComponentSize() const; + + void onAfterContextActivated(BaseContext& context) override; + void onAfterValueChanged(BaseContext& context, ValueHandle const& value) override; + + void createPropertiesFromSamplerData(BaseContext& context, core::SharedAnimationSamplerData currentSamplerData); + + void setAnimationData(BaseContext& context, const std::vector& timeStamps, const core::AnimationSamplerData::OutputDataVariant& outputData); + + + static core::AnimationSamplerData::OutputDataVariant makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut); + + static core::AnimationSamplerData::OutputDataVariant makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut); + + static core::AnimationSamplerData::OutputDataVariant makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut); + + static core::AnimationSamplerData::OutputDataVariant makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut); + + + void validate(BaseContext& context); + void adjustDataArray(BaseContext& context); + void updateSamplerData(BaseContext& context); + + Property componentType_{static_cast(core::EnginePrimitive::Double), {"Component Type"}, {EUserTypeEnumerations::AnimationComponentType}}; + Property interpolationType_{static_cast(core::MeshAnimationInterpolation::Step), {"Interpolation Type"}, {EUserTypeEnumerations::AnimationInterpolationType}}; + Property componentArraySize_{1, {"Component Array Size"}}; + + Property data_{{}, {}}; +}; + +} // namespace raco::user_types diff --git a/datamodel/libUserTypes/include/user_types/BaseCamera.h b/datamodel/libUserTypes/include/user_types/BaseCamera.h index 7c484859..32a99f71 100644 --- a/datamodel/libUserTypes/include/user_types/BaseCamera.h +++ b/datamodel/libUserTypes/include/user_types/BaseCamera.h @@ -57,10 +57,13 @@ class CameraViewport : public StructBase { {"height", &height_}}; } - Property, DisplayNameAnnotation, LinkEndAnnotation> offsetX_{0, {-7680, 7680}, {"offsetX"}, {}}; - Property, DisplayNameAnnotation, LinkEndAnnotation> offsetY_{0, {-7680, 7680}, {"offsetY"}, {}}; - Property, DisplayNameAnnotation, LinkEndAnnotation> width_{1440, {1, 7680}, {"width"}, {}}; - Property, DisplayNameAnnotation, LinkEndAnnotation> height_{720, {1, 7680}, {"height"}, {}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> offsetX_{0, {-8192, 8192}, {"offsetX"}, {}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> offsetY_{0, {-8192, 8192}, {"offsetY"}, {}}; + + // ramses::Camera::setViewport enforces a limit of 32768 on the width and height of the viewport. + // But we choose the same limit here as the preview and the render buffer size limits. + Property, DisplayNameAnnotation, LinkEndAnnotation> width_{1440, {1, 8192}, {"width"}, {}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> height_{720, {1, 8192}, {"height"}, {}}; }; class BaseCamera : public Node { diff --git a/datamodel/libUserTypes/include/user_types/BlitPass.h b/datamodel/libUserTypes/include/user_types/BlitPass.h index 2aeaf5e1..54ca2d3e 100644 --- a/datamodel/libUserTypes/include/user_types/BlitPass.h +++ b/datamodel/libUserTypes/include/user_types/BlitPass.h @@ -65,12 +65,12 @@ class BlitPass : public BaseObject { Property sourceRenderBufferMS_{{}, {"Source Render Buffer (Multisampled)"}, {}}; Property targetRenderBufferMS_{{}, {"Target Render Buffer (Multisampled)"}, {}}; - Property, DisplayNameAnnotation> sourceX_{0, {0, 7680}, {"Source Buffer Offset X"}}; - Property, DisplayNameAnnotation> sourceY_{0, {0, 7680}, {"Source Buffer Offset Y"}}; - Property, DisplayNameAnnotation> destinationX_{0, {0, 7680}, {"Destination Buffer Offset X"}}; - Property, DisplayNameAnnotation> destinationY_{0, {0, 7680}, {"Destination Buffer Offset Y"}}; - Property, DisplayNameAnnotation> width_{256, {0, 7680}, {"Blitting Region Width"}}; - Property, DisplayNameAnnotation> height_{256, {0, 7680}, {"Blitting Region Height"}}; + Property, DisplayNameAnnotation> sourceX_{0, {0, 8192}, {"Source Buffer Offset X"}}; + Property, DisplayNameAnnotation> sourceY_{0, {0, 8192}, {"Source Buffer Offset Y"}}; + Property, DisplayNameAnnotation> destinationX_{0, {0, 8192}, {"Destination Buffer Offset X"}}; + Property, DisplayNameAnnotation> destinationY_{0, {0, 8192}, {"Destination Buffer Offset Y"}}; + Property, DisplayNameAnnotation> width_{256, {0, 8192}, {"Blitting Region Width"}}; + Property, DisplayNameAnnotation> height_{256, {0, 8192}, {"Blitting Region Height"}}; Property enabled_{true, {"Enabled"}}; Property renderOrder_{0, {"Render Order"}}; diff --git a/datamodel/libUserTypes/include/user_types/Enumerations.h b/datamodel/libUserTypes/include/user_types/Enumerations.h index 9346ae39..1580e0eb 100644 --- a/datamodel/libUserTypes/include/user_types/Enumerations.h +++ b/datamodel/libUserTypes/include/user_types/Enumerations.h @@ -9,7 +9,7 @@ */ #pragma once -#include "core/CoreAnnotations.h" +#include "core/EngineInterface.h" #include #include @@ -213,4 +213,12 @@ enum class EFrustumType { extern std::map enumDescriptionFrustumType; +// using core::MeshAnimationInterpolation +extern std::map enumDescriptionAnimationInterpolationType; + +// using core::EnginePrimitive +extern std::map enumDescriptionAnimationComponentType; + + + } // namespace raco::user_types \ No newline at end of file diff --git a/datamodel/libUserTypes/include/user_types/RenderBuffer.h b/datamodel/libUserTypes/include/user_types/RenderBuffer.h index ec815585..c9210804 100644 --- a/datamodel/libUserTypes/include/user_types/RenderBuffer.h +++ b/datamodel/libUserTypes/include/user_types/RenderBuffer.h @@ -53,8 +53,8 @@ class RenderBuffer : public TextureSampler2DBase { valueHandle.isRefToProp(&TextureSampler2DBase::anisotropy_); } - Property, DisplayNameAnnotation> width_{256, {1, 7680}, {"Width"}}; - Property, DisplayNameAnnotation> height_{256, {1, 7680}, {"Height"}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> width_{256, {1, 8192}, {"Width"}, {}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> height_{256, {1, 8192}, {"Height"}, {}}; Property format_{DEFAULT_VALUE_RENDER_BUFFER_FORMAT, DisplayNameAnnotation("Format"), EnumerationAnnotation{EUserTypeEnumerations::RenderBufferFormat}}; diff --git a/datamodel/libUserTypes/include/user_types/RenderBufferMS.h b/datamodel/libUserTypes/include/user_types/RenderBufferMS.h index 190edf1b..53a807ed 100644 --- a/datamodel/libUserTypes/include/user_types/RenderBufferMS.h +++ b/datamodel/libUserTypes/include/user_types/RenderBufferMS.h @@ -46,11 +46,11 @@ class RenderBufferMS : public BaseObject { void onAfterContextActivated(BaseContext& context) override; void onAfterValueChanged(BaseContext& context, ValueHandle const& value) override; - Property, DisplayNameAnnotation> width_{256, {1, 7680}, {"Width"}}; - Property, DisplayNameAnnotation> height_{256, {1, 7680}, {"Height"}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> width_{256, {1, 8192}, {"Width"}, {}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> height_{256, {1, 8192}, {"Height"}, {}}; Property format_{DEFAULT_VALUE_RENDER_BUFFER_FORMAT, DisplayNameAnnotation("Format"), EnumerationAnnotation{EUserTypeEnumerations::RenderBufferFormat}}; - Property, DisplayNameAnnotation> sampleCount_{SAMPLE_COUNT_MIN, {SAMPLE_COUNT_MIN, SAMPLE_COUNT_MAX}, {"Sample Count"}}; + Property, DisplayNameAnnotation, LinkEndAnnotation> sampleCount_{SAMPLE_COUNT_MIN, {SAMPLE_COUNT_MIN, SAMPLE_COUNT_MAX}, {"Sample Count"}, {}}; private: void validateSampleCount(BaseContext& context); diff --git a/datamodel/libUserTypes/include/user_types/RenderLayer.h b/datamodel/libUserTypes/include/user_types/RenderLayer.h index d9ae5ac2..92a67d04 100644 --- a/datamodel/libUserTypes/include/user_types/RenderLayer.h +++ b/datamodel/libUserTypes/include/user_types/RenderLayer.h @@ -44,8 +44,12 @@ class RenderLayer : public BaseObject { return renderableTags_->propertyNames(); } + std::set renderableTagSet() const { + return renderableTags_->propertyNameSet(); + } + std::set materialFilterTags() const { - std::set r; + std::set r; for (int i = 0; i < materialFilterTags_->size(); ++i) { r.emplace(materialFilterTags_->get(i)->asString()); } diff --git a/datamodel/libUserTypes/include/user_types/UserObjectFactory.h b/datamodel/libUserTypes/include/user_types/UserObjectFactory.h index 15996d42..80717b86 100644 --- a/datamodel/libUserTypes/include/user_types/UserObjectFactory.h +++ b/datamodel/libUserTypes/include/user_types/UserObjectFactory.h @@ -24,8 +24,8 @@ class DefaultResourceDirectories; namespace raco::user_types { -class AnimationChannel; -using SAnimationChannel = std::shared_ptr; +class AnimationChannelBase; +using SAnimationChannelBase = std::shared_ptr; class Mesh; using SMesh = std::shared_ptr; @@ -196,7 +196,10 @@ class UserObjectFactory : public core::UserObjectFactoryInterface { Property, // Animation - Property, DisplayNameAnnotation, ResizableArray>, + Property, DisplayNameAnnotation, ResizableArray>, + + // AnimationChannelRaco + Property, // EditorObject Property, ArraySemanticAnnotation, HiddenProperty>, @@ -299,7 +302,13 @@ class UserObjectFactory : public core::UserObjectFactoryInterface { Property, Property, Property, - Property + Property, + + // AnimationChannelRaco data arrays + Value>, + Value>>, + Value>, + Value>> >; using StructCreationFunction = std::function()>; diff --git a/datamodel/libUserTypes/src/AnimationChannel.cpp b/datamodel/libUserTypes/src/AnimationChannel.cpp index 646b112e..30dc4a0d 100644 --- a/datamodel/libUserTypes/src/AnimationChannel.cpp +++ b/datamodel/libUserTypes/src/AnimationChannel.cpp @@ -10,8 +10,8 @@ #include "user_types/AnimationChannel.h" -#include "core/Errors.h" #include "core/CoreFormatter.h" +#include "core/Errors.h" #include "Validation.h" @@ -25,7 +25,7 @@ void AnimationChannel::onAfterValueChanged(BaseContext& context, ValueHandle con } } -core::PropertyInterface AnimationChannel::getOutputProperty() const { +core::PropertyInterface AnimationChannelBase::getOutputProperty() const { if (currentSamplerData_->componentType == EnginePrimitive::Array) { return PropertyInterface::makeArrayOf(objectName(), EnginePrimitive::Double, currentSamplerData_->getOutputComponentSize()); } @@ -95,7 +95,7 @@ void AnimationChannel::updateFromExternalFile(BaseContext& context) { return; } - if (currentSamplerData_->keyFrames.empty()) { + if (std::visit([](const auto& data) -> bool { return data.keyFrames.empty(); }, currentSamplerData_->output)) { context.errors().addError(core::ErrorCategory::PARSING, core::ErrorLevel::ERROR, {shared_from_this(), &AnimationChannel::samplerIndex_}, "Selected animation sampler does not contain valid output data."); currentSamplerData_.reset(); return; diff --git a/datamodel/libUserTypes/src/AnimationChannelRaco.cpp b/datamodel/libUserTypes/src/AnimationChannelRaco.cpp new file mode 100644 index 00000000..2b73b491 --- /dev/null +++ b/datamodel/libUserTypes/src/AnimationChannelRaco.cpp @@ -0,0 +1,381 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "user_types/AnimationChannelRaco.h" + +#include "core/CoreFormatter.h" +#include "core/Errors.h" + +#include "Validation.h" + +namespace raco::user_types { + +template +struct RamsesToPropertyTypeTraits {}; + +template <> +struct RamsesToPropertyTypeTraits { + using PropType = double; +}; + +template <> +struct RamsesToPropertyTypeTraits { + using PropType = int; +}; + + +template +void convertDataAsArray(BaseContext& context, const ValueHandle& handle, const std::vector>& data, const std::string& propName) { + auto outputsProp = std::make_unique::PropType>>>>(); + for (size_t index = 0; index < data.size(); index++) { + auto& v = data[index]; + auto& valueProp = (*outputsProp)->addProperty()->asArray(); + for (size_t component = 0; component < N; component++) { + auto compProp = valueProp.addProperty(); + *compProp = v[component]; + } + } + context.addProperty(handle, propName, std::move(outputsProp)); +} + +void convertDataAsArray(BaseContext& context, const ValueHandle& handle, const std::vector>& data, const std::string& propName) { + auto outputsProp = std::make_unique>>>(); + for (size_t index = 0; index < data.size(); index++) { + auto& v = data[index]; + auto& valueProp = (*outputsProp)->addProperty()->asArray(); + for (size_t component = 0; component < v.size(); component++) { + auto compProp = valueProp.addProperty(); + *compProp = v[component]; + } + } + context.addProperty(handle, propName, std::move(outputsProp)); +} + +template +void convertDataAsArray(BaseContext& context, const ValueHandle& handle, const std::vector& data, const std::string& propName) { + auto inputs = std::make_unique::PropType>>>(); + for (size_t index = 0; index < data.size(); index++) { + auto elem = (*inputs)->addProperty(); + *elem = data[index]; + } + context.addProperty(handle, propName, std::move(inputs)); +} + +template +void createCurveDataProperties(BaseContext& context, ValueHandle dataHandle, const core::AnimationOutputData& samplerData) { + convertDataAsArray(context, dataHandle, samplerData.keyFrames, AnimationChannelRaco::PROPNAME_KEYFRAMES); + if (!samplerData.tangentsIn.empty()) { + convertDataAsArray(context, dataHandle, samplerData.tangentsIn, AnimationChannelRaco::PROPNAME_TANGENTS_IN); + } + if (!samplerData.tangentsOut.empty()) { + convertDataAsArray(context, dataHandle, samplerData.tangentsOut, AnimationChannelRaco::PROPNAME_TANGENTS_OUT); + } +} + +void AnimationChannelRaco::createPropertiesFromSamplerData(BaseContext& context, core::SharedAnimationSamplerData samplerData) { + ValueHandle dataHandle({shared_from_this(), &AnimationChannelRaco::data_}); + + context.removeAllProperties(dataHandle); + + context.set({shared_from_this(), &AnimationChannelRaco::interpolationType_}, static_cast(samplerData->interpolation)); + context.set({shared_from_this(), &AnimationChannelRaco::componentType_}, static_cast(samplerData->componentType)); + if (samplerData->componentType == core::EnginePrimitive::Array) { + const auto& keyFrames = std::get>>(samplerData->output).keyFrames; + int compSize = keyFrames.empty() ? 1 : keyFrames.begin()->size(); + if (compSize > 0) { + context.set({shared_from_this(), &AnimationChannelRaco::componentArraySize_}, compSize); + } + } + + convertDataAsArray(context, dataHandle, samplerData->timeStamps, PROPNAME_TIME_STAMPS); + + std::visit( + [this, dataHandle, &context](const auto& data) { + createCurveDataProperties(context, dataHandle, data); + }, + samplerData->output); + + // Need to update the sampler data for the engine since the BaseContext::addProperty calls will not invoke onAfterValueChanged + updateSamplerData(context); +} + +void AnimationChannelRaco::setAnimationData(BaseContext& context, const std::vector& timeStamps, const core::AnimationSamplerData::OutputDataVariant& outputData) { + ValueHandle dataHandle({shared_from_this(), &AnimationChannelRaco::data_}); + + context.removeAllProperties(dataHandle); + convertDataAsArray(context, dataHandle, timeStamps, PROPNAME_TIME_STAMPS); + + std::visit( + [this, dataHandle, &context](const auto& data) { + createCurveDataProperties(context, dataHandle, data); + }, + outputData); + + // Need to update the sampler data for the engine since the BaseContext::addProperty calls will not invoke onAfterValueChanged + updateSamplerData(context); +} + + +template +std::vector> convertVectorToGlm(const std::vector>& data) { + using ComponentType = glm::vec; + std::vector result; + for (size_t index = 0; index < data.size(); index++) { + ComponentType v; + for (size_t compIndex = 0; compIndex < N; compIndex++) { + v[compIndex] = data[index][compIndex]; + } + result.emplace_back(v); + } + return result; +} + +core::AnimationSamplerData::OutputDataVariant AnimationChannelRaco::makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut) { + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{keyFrames, tangentsIn, tangentsOut}); +} + +core::AnimationSamplerData::OutputDataVariant AnimationChannelRaco::makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector& keyFrames, const std::vector& tangentsIn, const std::vector& tangentsOut) { + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{keyFrames, tangentsIn, tangentsOut}); +} + + +core::AnimationSamplerData::OutputDataVariant AnimationChannelRaco::makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut) { + switch (static_cast(componentType)) { + case core::EnginePrimitive::Array: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData>{keyFrames, tangentsIn, tangentsOut}); + break; + case core::EnginePrimitive::Vec2f: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convertVectorToGlm(keyFrames), convertVectorToGlm(tangentsIn), convertVectorToGlm(tangentsOut)}); + break; + case core::EnginePrimitive::Vec3f: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convertVectorToGlm(keyFrames), convertVectorToGlm(tangentsIn), convertVectorToGlm(tangentsOut)}); + break; + case core::EnginePrimitive::Vec4f: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convertVectorToGlm(keyFrames), convertVectorToGlm(tangentsIn), convertVectorToGlm(tangentsOut)}); + break; + default: + assert(false); + } + return {}; +} + +core::AnimationSamplerData::OutputDataVariant AnimationChannelRaco::makeAnimationOutputData(core::EnginePrimitive componentType, const std::vector>& keyFrames, const std::vector>& tangentsIn, const std::vector>& tangentsOut) { + switch (static_cast(componentType)) { + case core::EnginePrimitive::Vec2i: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convertVectorToGlm(keyFrames), convertVectorToGlm(tangentsIn), convertVectorToGlm(tangentsOut)}); + break; + case core::EnginePrimitive::Vec3i: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convertVectorToGlm(keyFrames), convertVectorToGlm(tangentsIn), convertVectorToGlm(tangentsOut)}); + break; + case core::EnginePrimitive::Vec4i: + return core::AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{convertVectorToGlm(keyFrames), convertVectorToGlm(tangentsIn), convertVectorToGlm(tangentsOut)}); + break; + default: + assert(false); + } + return {}; +} + + +template +std::vector getSamplerDataArray(data_storage::Table& cont, const char* propName) { + using PropType = typename RamsesToPropertyTypeTraits::PropType; + std::vector data; + if (cont.hasProperty(propName)) { + const ValueBase* prop = cont.get(propName); + const ArrayBase& array = prop->asArray(); + for (size_t index = 0; index < array.size(); index++) { + data.emplace_back(array.get(index)->as()); + } + } + return data; +} + +std::vector> getSamplerDataArrayVec(data_storage::Table& cont, const char* propName) { + std::vector> data; + if (cont.hasProperty(propName)) { + const ValueBase* prop = cont.get(propName); + const ArrayBase& array = prop->asArray(); + for (size_t index = 0; index < array.size(); index++) { + const auto& component = array.get(index)->asArray(); + std::vector v; + for (size_t compIndex = 0; compIndex < component.size(); compIndex++) { + v.emplace_back(component.get(compIndex)->asDouble()); + } + data.emplace_back(v); + } + } + return data; +} + +template +std::vector> getSamplerDataArrayGlm(data_storage::Table& data, const char* propName) { + if (data.hasProperty(propName)) { + const ValueBase* prop = data.get(propName); + const ArrayBase& array = prop->asArray(); + using ComponentType = glm::vec; + using PropType = typename RamsesToPropertyTypeTraits::PropType; + std::vector data; + for (size_t index = 0; index < array.size(); index++) { + const auto& component = array.get(index)->asArray(); + ComponentType v; + for (size_t compIndex = 0; compIndex < N; compIndex++) { + v[compIndex] = component.get(compIndex)->as(); + } + data.emplace_back(v); + } + return data; + } + return {}; +} + +template +AnimationSamplerData::OutputDataVariant makeOutputData(data_storage::Table& data) { + using ComponentType = glm::vec; + + return AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{ + getSamplerDataArrayGlm(data, AnimationChannelRaco::PROPNAME_KEYFRAMES), + getSamplerDataArrayGlm(data, AnimationChannelRaco::PROPNAME_TANGENTS_IN), + getSamplerDataArrayGlm(data, AnimationChannelRaco::PROPNAME_TANGENTS_OUT)}); +} + + +void AnimationChannelRaco::updateSamplerData(BaseContext& context) { + context.changeMultiplexer().recordPreviewDirty(shared_from_this()); + + if (data_->size() == 0) { + currentSamplerData_.reset(); + return; + } + + std::vector timeStamps = getSamplerDataArray(*data_, PROPNAME_TIME_STAMPS); + + AnimationSamplerData::OutputDataVariant outputData; + + switch (static_cast(*componentType_)) { + case core::EnginePrimitive::Double: + outputData = AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{ + getSamplerDataArray(*data_, PROPNAME_KEYFRAMES), getSamplerDataArray(*data_, PROPNAME_TANGENTS_IN), getSamplerDataArray(*data_, PROPNAME_TANGENTS_OUT)}); + break; + + case core::EnginePrimitive::Array: { + outputData = AnimationSamplerData::OutputDataVariant(core::AnimationOutputData>{ + getSamplerDataArrayVec(*data_, PROPNAME_KEYFRAMES), getSamplerDataArrayVec(*data_, PROPNAME_TANGENTS_IN), getSamplerDataArrayVec(*data_, PROPNAME_TANGENTS_OUT)}); + break; + } + + case core::EnginePrimitive::Vec2f: + outputData = makeOutputData(*data_); + break; + + case core::EnginePrimitive::Vec3f: + outputData = makeOutputData(*data_); + break; + + case core::EnginePrimitive::Vec4f: + outputData = makeOutputData(*data_); + break; + + case core::EnginePrimitive::Int32: + outputData = AnimationSamplerData::OutputDataVariant(core::AnimationOutputData{ + getSamplerDataArray(*data_, PROPNAME_KEYFRAMES), getSamplerDataArray(*data_, PROPNAME_TANGENTS_IN), getSamplerDataArray(*data_, PROPNAME_TANGENTS_OUT)}); + break; + + case core::EnginePrimitive::Vec2i: + outputData = makeOutputData(*data_); + break; + + case core::EnginePrimitive::Vec3i: + outputData = makeOutputData(*data_); + break; + + case core::EnginePrimitive::Vec4i: + outputData = makeOutputData(*data_); + break; + + default: + assert(false); + } + + currentSamplerData_ = std::make_shared(core::AnimationSamplerData{ + static_cast(*interpolationType_), + static_cast(*componentType_), + static_cast(*componentArraySize_), + timeStamps, outputData}); +} + +int AnimationChannelRaco::getOuputComponentSize() const { + switch (static_cast(*componentType_)) { + case EnginePrimitive::Double: + return 1; + break; + case EnginePrimitive::Vec2f: + return 2; + break; + case EnginePrimitive::Vec3f: + return 3; + break; + case EnginePrimitive::Vec4f: + return 4; + break; + case EnginePrimitive::Int32: + return 1; + break; + case EnginePrimitive::Vec2i: + return 2; + break; + case EnginePrimitive::Vec3i: + return 3; + break; + case EnginePrimitive::Vec4i: + return 4; + break; + case EnginePrimitive::Array: + return *componentArraySize_; + break; + } + return 0; +} + +void AnimationChannelRaco::onAfterContextActivated(BaseContext& context) { + validate(context); + updateSamplerData(context); +} + +void AnimationChannelRaco::onAfterValueChanged(BaseContext& context, ValueHandle const& value) { + BaseObject::onAfterValueChanged(context, value); + + if (value.isRefToProp(&AnimationChannelRaco::componentType_) || value.isRefToProp(&AnimationChannelRaco::interpolationType_) || value.isRefToProp(&AnimationChannelRaco::componentArraySize_)) { + validate(context); + adjustDataArray(context); + updateSamplerData(context); + } else if (ValueHandle(shared_from_this(), &AnimationChannelRaco::data_).contains(value)) { + updateSamplerData(context); + } +} + +void AnimationChannelRaco::validate(BaseContext& context) { + bool quaternionInterpolation = (*interpolationType_ == static_cast(core::MeshAnimationInterpolation::Linear_Quaternion)) || (*interpolationType_ == static_cast(core::MeshAnimationInterpolation::CubicSpline_Quaternion)); + + ValueHandle interpolationHandle(shared_from_this(), &AnimationChannelRaco::interpolationType_); + + if (quaternionInterpolation && *componentType_ != static_cast(core::EnginePrimitive::Vec4f)) { + context.errors().addError(core::ErrorCategory::GENERAL, core::ErrorLevel::ERROR, interpolationHandle, "Primitive type must be Vec4f if quaternion interpolation is used."); + } else { + context.errors().removeError(interpolationHandle); + } +} + +void AnimationChannelRaco::adjustDataArray(BaseContext& context) { + ValueHandle dataHandle({shared_from_this(), &AnimationChannelRaco::data_}); + context.removeAllProperties(dataHandle); +} + +} // namespace raco::user_types \ No newline at end of file diff --git a/datamodel/libUserTypes/src/Enumerations.cpp b/datamodel/libUserTypes/src/Enumerations.cpp index ee9b60f6..8f2e3c28 100644 --- a/datamodel/libUserTypes/src/Enumerations.cpp +++ b/datamodel/libUserTypes/src/Enumerations.cpp @@ -10,9 +10,11 @@ #include "user_types/Enumerations.h" +#include "core/MeshCacheInterface.h" + +#include #include #include -#include namespace raco::user_types { @@ -21,39 +23,43 @@ const std::map& enumerationDescription(core::EUserTypeEnumerat switch (type) { case core::EUserTypeEnumerations::CullMode: - return raco::user_types::enumDescriptionCullMode; + return enumDescriptionCullMode; case core::EUserTypeEnumerations::BlendOperation: - return raco::user_types::enumDescriptionBlendOperation; + return enumDescriptionBlendOperation; case core::EUserTypeEnumerations::BlendFactor: - return raco::user_types::enumDescriptionBlendFactor; + return enumDescriptionBlendFactor; case core::EUserTypeEnumerations::DepthFunction: - return raco::user_types::enumDescriptionDepthFunction; + return enumDescriptionDepthFunction; case core::EUserTypeEnumerations::TextureAddressMode: - return raco::user_types::enumDescriptionTextureAddressMode; + return enumDescriptionTextureAddressMode; case core::EUserTypeEnumerations::TextureMinSamplingMethod: - return raco::user_types::enumDescriptionTextureMinSamplingMethod; + return enumDescriptionTextureMinSamplingMethod; case core::EUserTypeEnumerations::TextureMagSamplingMethod: - return raco::user_types::enumDescriptionTextureMagSamplingMethod; + return enumDescriptionTextureMagSamplingMethod; case core::EUserTypeEnumerations::TextureFormat: - return raco::user_types::enumDescriptionTextureFormat; + return enumDescriptionTextureFormat; case core::EUserTypeEnumerations::RenderBufferFormat: - return raco::user_types::enumDescriptionRenderBufferFormat; + return enumDescriptionRenderBufferFormat; case core::EUserTypeEnumerations::RenderLayerOrder: - return raco::user_types::enumDescriptionRenderLayerOrder; + return enumDescriptionRenderLayerOrder; case core::EUserTypeEnumerations::RenderLayerMaterialFilterMode: - return raco::user_types::enumDescriptionRenderLayerMaterialFilterMode; + return enumDescriptionRenderLayerMaterialFilterMode; case core::EUserTypeEnumerations::FrustumType: - return raco::user_types::enumDescriptionFrustumType; - + return enumDescriptionFrustumType; case core::EUserTypeEnumerations::StencilFunction: - return raco::user_types::enumDescriptionStencilFunction; + return enumDescriptionStencilFunction; case core::EUserTypeEnumerations::StencilOperation: - return raco::user_types::enumDescriptionStencilOperation; + return enumDescriptionStencilOperation; + + case core::EUserTypeEnumerations::AnimationComponentType: + return enumDescriptionAnimationComponentType; + case core::EUserTypeEnumerations::AnimationInterpolationType: + return enumDescriptionAnimationInterpolationType; default: assert(false); @@ -112,8 +118,7 @@ std::map enumDescriptionStencilFunction{ {static_cast(EStencilFunc::Less), "<"}, {static_cast(EStencilFunc::LessEqual), "<="}, {static_cast(EStencilFunc::Greater), ">"}, - {static_cast(EStencilFunc::GreaterEqual), ">="} -}; + {static_cast(EStencilFunc::GreaterEqual), ">="}}; std::map enumDescriptionStencilOperation{ {static_cast(EStencilOperation::Keep), "Keep"}, @@ -123,8 +128,7 @@ std::map enumDescriptionStencilOperation{ {static_cast(EStencilOperation::IncrementWrap), "IncrementWrap"}, {static_cast(EStencilOperation::Decrement), "Decrement"}, {static_cast(EStencilOperation::DecrementWrap), "DecrementWrap"}, - {static_cast(EStencilOperation::Invert), "Invert"} -}; + {static_cast(EStencilOperation::Invert), "Invert"}}; std::map enumDescriptionTextureAddressMode{ {static_cast(ETextureAddressMode::Clamp), "Clamp"}, @@ -186,4 +190,25 @@ std::map enumDescriptionFrustumType{ {static_cast(EFrustumType::Aspect_FieldOfView), "Aspect & Field Of View"}, {static_cast(EFrustumType::Planes), "Planes"}}; +std::map enumDescriptionAnimationInterpolationType{ + {static_cast(core::MeshAnimationInterpolation::Step), "Step"}, + {static_cast(core::MeshAnimationInterpolation::Linear), "Linear"}, + {static_cast(core::MeshAnimationInterpolation::CubicSpline), "Cubic Spline"}, + {static_cast(core::MeshAnimationInterpolation::Linear_Quaternion), "Linear Quaternion"}, + {static_cast(core::MeshAnimationInterpolation::CubicSpline_Quaternion), "Cubic Spline Quaternion"}}; + +std::map enumDescriptionAnimationComponentType{ + {static_cast(core::EnginePrimitive::Double), "Float"}, + {static_cast(core::EnginePrimitive::Vec2f), "Vec2f"}, + {static_cast(core::EnginePrimitive::Vec3f), "Vec3f"}, + {static_cast(core::EnginePrimitive::Vec4f), "Vec4f"}, + + {static_cast(core::EnginePrimitive::Int32), "Int"}, + {static_cast(core::EnginePrimitive::Vec2i), "Vec2i"}, + {static_cast(core::EnginePrimitive::Vec3i), "Vec3i"}, + {static_cast(core::EnginePrimitive::Vec4i), "Vec4i"}, + + // RamsesLogic can also animate float arrays to be used in the morph target weights. + {static_cast(core::EnginePrimitive::Array), "Array(Float)"}}; + } // namespace raco::user_types \ No newline at end of file diff --git a/datamodel/libUserTypes/src/SyncTableWithEngineInterface.cpp b/datamodel/libUserTypes/src/SyncTableWithEngineInterface.cpp index 34c2a934..79f72584 100644 --- a/datamodel/libUserTypes/src/SyncTableWithEngineInterface.cpp +++ b/datamodel/libUserTypes/src/SyncTableWithEngineInterface.cpp @@ -149,7 +149,7 @@ inline void removeProperties(core::BaseContext& context, const PropertyInterface EnginePrimitive engineType = anno->type(); auto fullPropPath = propertyPath + propertyPathSeparator + name; - if (it == interface.end() || it->type != engineType || std::distance(interface.begin(), it) != propertyIndex) { + if (it == interface.end() || it->type != engineType) { toRemove.emplace_back(name); if (value->type() != PrimitiveType::Table) { outdatedPropertiesStore[std::make_pair(fullPropPath, engineType)] = value->clone(nullptr); @@ -201,7 +201,12 @@ inline void addProperties(core::BaseContext& context, const PropertyInterfaceLis } } ValueBase* newValue = context.addProperty(property, name, std::move(uniqueValue), interfaceIndex); + } else if (interfaceIndex != property.constValueRef()->getSubstructure().index(name)) { + auto currentIndex = property.constValueRef()->getSubstructure().index(name); + assert(currentIndex > interfaceIndex); + context.swapProperties(property, interfaceIndex, currentIndex); } + if (iEntry.primitiveType() == PrimitiveType::Table) { addProperties(context, iEntry.children, property.get(name), propertyPath + propertyPathSeparator + name, outdatedPropertiesStore, linkStart, linkEnd, cacheLookupFunc); } diff --git a/datamodel/libUserTypes/src/UserObjectFactory.cpp b/datamodel/libUserTypes/src/UserObjectFactory.cpp index f8b3235b..b476c626 100644 --- a/datamodel/libUserTypes/src/UserObjectFactory.cpp +++ b/datamodel/libUserTypes/src/UserObjectFactory.cpp @@ -15,6 +15,7 @@ #include "user_types/AnchorPoint.h" #include "user_types/Animation.h" #include "user_types/AnimationChannel.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/BaseCamera.h" #include "user_types/BaseObject.h" #include "user_types/BaseTexture.h" @@ -94,6 +95,7 @@ UserObjectFactory::UserObjectFactory() { AnchorPoint, Animation, AnimationChannel, + AnimationChannelRaco, BlitPass, CubeMap, Node, diff --git a/datamodel/libUserTypes/tests/AnimationChannelRaco_test.cpp b/datamodel/libUserTypes/tests/AnimationChannelRaco_test.cpp new file mode 100644 index 00000000..179271e9 --- /dev/null +++ b/datamodel/libUserTypes/tests/AnimationChannelRaco_test.cpp @@ -0,0 +1,335 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include "testing/TestEnvironmentCore.h" + +#include "testing/TestUtil.h" +#include "user_types/AnimationChannelRaco.h" + +#include + +using namespace raco; +using namespace raco::core; +using namespace raco::user_types; + +template +std::vector> toVector(const std::vector>& data) { + std::vector> result; + for (size_t index = 0; index < data.size(); index++) { + std::vector v; + for (size_t component = 0; component < N; component++) { + v.push_back(data[index][component]); + } + result.push_back(v); + } + return result; +} + +template +std::vector toVector(const std::vector& data) { + return data; +} + + +class AnimationChannelRacoTest : public TestEnvironmentCore { +public: + template + void check_set_get(EnginePrimitive componentType, MeshAnimationInterpolation interpolation, + std::vector timeStamps, + std::vector keyFrames, std::vector tangentsIn = {}, std::vector tangentsOut = {}) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(componentType)); + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(interpolation)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 5); + + commandInterface.setAnimationData(channel, timeStamps, keyFrames, tangentsIn, tangentsOut); + + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)); + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)); + EXPECT_EQ(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_IN), !tangentsIn.empty()); + EXPECT_EQ(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_OUT), !tangentsOut.empty()); + + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)->asArray().size(), timeStamps.size()); + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)->asArray().size(), keyFrames.size()); + + EXPECT_EQ(channel->currentSamplerData_->timeStamps, timeStamps); + + EXPECT_TRUE(std::holds_alternative>(channel->currentSamplerData_->output)); + + auto data = std::get>(channel->currentSamplerData_->output); + EXPECT_EQ(toVector(data.keyFrames), keyFrames); + EXPECT_EQ(toVector(data.tangentsIn), tangentsIn); + EXPECT_EQ(toVector(data.tangentsOut), tangentsOut); + } +}; + +TEST_F(AnimationChannelRacoTest, creation) { + auto channel = create("channel"); +} + +TEST_F(AnimationChannelRacoTest, validate_interpolation) { + auto channel = create("channel"); + + ValueHandle interpolationHandle{channel, &AnimationChannelRaco::interpolationType_}; + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec3f)); + + commandInterface.set(interpolationHandle, static_cast(MeshAnimationInterpolation::Linear)); + EXPECT_FALSE(commandInterface.errors().hasError(interpolationHandle)); + + commandInterface.set(interpolationHandle, static_cast(MeshAnimationInterpolation::Linear_Quaternion)); + EXPECT_TRUE(commandInterface.errors().hasError(interpolationHandle)); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Vec4f)); + + commandInterface.set(interpolationHandle, static_cast(MeshAnimationInterpolation::Linear)); + EXPECT_FALSE(commandInterface.errors().hasError(interpolationHandle)); + + commandInterface.set(interpolationHandle, static_cast(MeshAnimationInterpolation::Linear_Quaternion)); + EXPECT_FALSE(commandInterface.errors().hasError(interpolationHandle)); +} + +TEST_F(AnimationChannelRacoTest, set_data_float_empty_linear) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Double)); + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::Linear)); + + std::vector timeStamps; + std::vector keyFrames; + + commandInterface.setAnimationData(channel, timeStamps, keyFrames); + + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)); + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)); + EXPECT_FALSE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_IN)); + EXPECT_FALSE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_OUT)); + + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)->asArray().size(), 0); + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)->asArray().size(), 0); +} + +TEST_F(AnimationChannelRacoTest, set_data_array_empty_linear) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Array)); + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::Linear)); + commandInterface.set({channel, &AnimationChannelRaco::componentArraySize_}, 5); + + std::vector timeStamps; + std::vector> keyFrames; + + commandInterface.setAnimationData(channel, timeStamps, keyFrames); + + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)); + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)); + EXPECT_FALSE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_IN)); + EXPECT_FALSE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_OUT)); + + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)->asArray().size(), 0); + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)->asArray().size(), 0); + + EXPECT_EQ(channel->currentSamplerData_->getOutputComponentSize(), 5); +} + + +TEST_F(AnimationChannelRacoTest, set_data_float_empty_cubic) { + auto channel = create("channel"); + + commandInterface.set({channel, &AnimationChannelRaco::componentType_}, static_cast(EnginePrimitive::Double)); + commandInterface.set({channel, &AnimationChannelRaco::interpolationType_}, static_cast(MeshAnimationInterpolation::CubicSpline)); + + std::vector timeStamps; + std::vector keyFrames; + std::vector tangentsIn; + std::vector tangentsOut; + + commandInterface.setAnimationData(channel, timeStamps, keyFrames, tangentsIn, tangentsOut); + + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)); + EXPECT_TRUE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)); + EXPECT_FALSE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_IN)); + EXPECT_FALSE(channel->data_->hasProperty(user_types::AnimationChannelRaco::PROPNAME_TANGENTS_OUT)); + + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_TIME_STAMPS)->asArray().size(), 0); + EXPECT_EQ(channel->data_->get(user_types::AnimationChannelRaco::PROPNAME_KEYFRAMES)->asArray().size(), 0); +} + +TEST_F(AnimationChannelRacoTest, set_data_float_linear) { + check_set_get(EnginePrimitive::Double, MeshAnimationInterpolation::Linear, + {0.0, 1.0, 2.0}, {0.0, 1.0, 4.0}); +} + +TEST_F(AnimationChannelRacoTest, set_data_float_cubic) { + check_set_get(EnginePrimitive::Double, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0, 2.0}, {0.0, 1.0, 4.0}, std::vector(3, 0.0), std::vector(3, 1.0)); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec2f_linear) { + check_set_get, glm::vec2>(EnginePrimitive::Vec2f, MeshAnimationInterpolation::Linear, + {0.0, 1.0, 2.0}, {{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec2f_cubic) { + check_set_get, glm::vec2>(EnginePrimitive::Vec2f, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0, 2.0}, {{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}}, + {{0, 0}, {0, 0}, {0, 0}}, {{1, 1}, {1, 1}, {1, 1}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec3f_linear) { + check_set_get, glm::vec3>(EnginePrimitive::Vec3f, MeshAnimationInterpolation::Linear, + {0.0, 1.0, 2.0}, {{1.0, 2.0, 3.0}, {2.0, 3.0, 4.0}, {3.0, 4.0, 5.0}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec3f_cubic) { + check_set_get, glm::vec3>(EnginePrimitive::Vec3f, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0, 2.0}, {{1.0, 2.0, 3.0}, {2.0, 3.0, 4.0}, {3.0, 4.0, 5.0}}, + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {{1, 1,1 }, {1, 1, 1}, {1, 1, 1}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec4f_linear) { + check_set_get, glm::vec4>(EnginePrimitive::Vec4f, MeshAnimationInterpolation::Linear, + {0.0, 1.0, 2.0}, {{1.0, 2.0, 3.0, 4.0}, {2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec4f_cubic) { + check_set_get, glm::vec4>(EnginePrimitive::Vec4f, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0, 2.0}, {{1.0, 2.0, 3.0, 4.0}, {2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0}}, + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}); +} + + +TEST_F(AnimationChannelRacoTest, set_data_int_linear) { + check_set_get(EnginePrimitive::Int32, MeshAnimationInterpolation::Linear, + {0.0, 1.0, 2.0}, {0, 1, 4}); +} + +TEST_F(AnimationChannelRacoTest, set_data_int_cubic) { + check_set_get(EnginePrimitive::Int32, MeshAnimationInterpolation::CubicSpline, + {0, 1, 2}, {0, 1, 4}, std::vector(3, 0), std::vector(3, 1)); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec2i_linear) { + check_set_get, glm::ivec2>(EnginePrimitive::Vec2i, MeshAnimationInterpolation::Linear, + {0, 1, 2}, {{1, 2}, {2, 3}, {3, 4}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec2i_cubic) { + check_set_get, glm::ivec2>(EnginePrimitive::Vec2i, MeshAnimationInterpolation::CubicSpline, + {0, 1, 2}, {{1, 2}, {2, 3}, {3, 4}}, + {{0, 0}, {0, 0}, {0, 0}}, {{1, 1}, {1, 1}, {1, 1}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec3i_linear) { + check_set_get, glm::ivec3>(EnginePrimitive::Vec3i, MeshAnimationInterpolation::Linear, + {0, 1, 2}, {{1, 2, 3}, {2, 3, 4}, {3, 4, 5}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec3i_cubic) { + check_set_get, glm::ivec3>(EnginePrimitive::Vec3i, MeshAnimationInterpolation::CubicSpline, + {0, 1, 2}, {{1, 2, 3}, {2, 3, 4}, {3, 4, 5}}, + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec4i_linear) { + check_set_get, glm::ivec4>(EnginePrimitive::Vec4i, MeshAnimationInterpolation::Linear, + {0, 1, 2}, {{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_vec4i_cubic) { + check_set_get, glm::ivec4>(EnginePrimitive::Vec4i, MeshAnimationInterpolation::CubicSpline, + {0, 1, 2}, {{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}}, + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}); +} + + +TEST_F(AnimationChannelRacoTest, set_data_array_linear) { + check_set_get, std::vector>(EnginePrimitive::Array, MeshAnimationInterpolation::Linear, + {0.0, 1.0, 2.0}, {{1.0, 2.0, 3.0, 4.0, 5.0}, {2.0, 3.0, 4.0, 5.0, 6.0}, {3.0, 4.0, 5.0, 6.0, 7.0}}); +} + +TEST_F(AnimationChannelRacoTest, set_data_array_cubic) { + check_set_get, std::vector>(EnginePrimitive::Array, MeshAnimationInterpolation::CubicSpline, + {0.0, 1.0, 2.0}, {{1.0, 2.0, 3.0, 4.0, 5.0}, {2.0, 3.0, 4.0, 5.0, 6.0}, {3.0, 4.0, 5.0, 6.0, 7.0}}, + {{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}, {{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}}); +} + +TEST_F(AnimationChannelRacoTest, conv_gtlf_to_raco_morph_weights) { + auto channel_gltf = create_animation_channel("channel", "meshes/AnimatedMorphCube/AnimatedMorphCube.gltf", 0, 0); + auto animation = create_animation("animation", {channel_gltf}); + + auto data_gltf = channel_gltf->currentSamplerData_; + + ASSERT_EQ(project.instances().size(), 3); + ASSERT_TRUE(select(project.instances()) != nullptr); + EXPECT_EQ(**animation->animationChannels_->get(0), channel_gltf); + + auto raco_channels = commandInterface.convertToAnimationChannelRaco({channel_gltf}); + ASSERT_EQ(raco_channels.size(), 1); + + ASSERT_EQ(project.instances().size(), 3); + ASSERT_TRUE(select(project.instances()) == nullptr); + ASSERT_TRUE(select(project.instances()) != nullptr); + + auto channel_raco = raco_channels[0]->as(); + ASSERT_TRUE(channel_raco != nullptr); + EXPECT_EQ(**animation->animationChannels_->get(0), channel_raco); + + EXPECT_EQ(*channel_raco->componentType_, static_cast(EnginePrimitive::Array)); + EXPECT_EQ(*channel_raco->interpolationType_, static_cast(MeshAnimationInterpolation::Linear)); + EXPECT_EQ(*channel_raco->componentArraySize_, 2); + + EXPECT_EQ(*data_gltf, *channel_raco->currentSamplerData_); +} + +TEST_F(AnimationChannelRacoTest, conv_gtlf_to_raco_transformation) { + std::map interpolation = { + // Scale + {0, MeshAnimationInterpolation::Step}, + {1, MeshAnimationInterpolation::Linear}, + {2, MeshAnimationInterpolation::CubicSpline}, + // Rotation + {3, MeshAnimationInterpolation::Step}, + {4, MeshAnimationInterpolation::CubicSpline_Quaternion}, + {5, MeshAnimationInterpolation::Linear_Quaternion}, + // Translation + {6, MeshAnimationInterpolation::Step}, + {7, MeshAnimationInterpolation::CubicSpline}, + {8, MeshAnimationInterpolation::Linear} + }; + + for (auto animIndex = 0; animIndex < 9; animIndex++) { + auto channel_gltf = create_animation_channel("channel", "meshes/InterpolationTest/InterpolationTest.gltf", animIndex, 0); + + auto data_gltf = channel_gltf->currentSamplerData_; + + ASSERT_EQ(project.instances().size(), 2); + ASSERT_TRUE(select(project.instances()) != nullptr); + + auto raco_channels = commandInterface.convertToAnimationChannelRaco({channel_gltf}); + ASSERT_EQ(raco_channels.size(), 1); + + ASSERT_EQ(project.instances().size(), 2); + ASSERT_TRUE(select(project.instances()) == nullptr); + ASSERT_TRUE(select(project.instances()) != nullptr); + + auto channel_raco = raco_channels[0]->as(); + ASSERT_TRUE(channel_raco != nullptr); + + auto refComponentType = (animIndex / 3) == 1 ? EnginePrimitive::Vec4f : EnginePrimitive::Vec3f; + EXPECT_EQ(*channel_raco->componentType_, static_cast(refComponentType)) << fmt::format("anim index = {}", animIndex); + EXPECT_EQ(*channel_raco->interpolationType_, static_cast(interpolation[animIndex])) << fmt::format("anim index = {}", animIndex); + EXPECT_EQ(*channel_raco->componentArraySize_, 1); + + EXPECT_EQ(*data_gltf, *channel_raco->currentSamplerData_); + + commandInterface.deleteObjects({channel_raco}); + } +} diff --git a/datamodel/libUserTypes/tests/AnimationChannel_test.cpp b/datamodel/libUserTypes/tests/AnimationChannel_test.cpp index b5c464e5..fde345e2 100644 --- a/datamodel/libUserTypes/tests/AnimationChannel_test.cpp +++ b/datamodel/libUserTypes/tests/AnimationChannel_test.cpp @@ -145,22 +145,17 @@ TEST_F(AnimationChannelTest, invalidAnim_weights_supported) { ASSERT_FALSE(commandInterface.errors().hasError(samplerIndexHandle)); } -#if (!defined(__linux__)) -// awaitPreviewDirty does not work in Linux as expected. See RAOS-692 - TEST_F(AnimationChannelTest, validAnim_madeInvalid) { auto animChannel = create("anim_channel"); ValueHandle uriHandle{animChannel, &user_types::AnimationChannel::uri_}; - + auto animChannelPath = test_path().append("meshes/CesiumMilkTruck/CesiumMilkTruck.gltf").string(); commandInterface.set(uriHandle, animChannelPath); ASSERT_FALSE(commandInterface.errors().hasError(uriHandle)); recorder.reset(); utils::file::write(animChannelPath, ""); - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, animChannel)); + EXPECT_TRUE(awaitPreviewDirty(recorder, animChannel)); ASSERT_TRUE(commandInterface.errors().hasError(uriHandle)); } - -#endif \ No newline at end of file diff --git a/datamodel/libUserTypes/tests/CMakeLists.txt b/datamodel/libUserTypes/tests/CMakeLists.txt index bbb990af..3cf5421e 100644 --- a/datamodel/libUserTypes/tests/CMakeLists.txt +++ b/datamodel/libUserTypes/tests/CMakeLists.txt @@ -13,6 +13,7 @@ If a copy of the MPL was not distributed with this file, You can obtain one at h set(TEST_SOURCES Animation_test.cpp AnimationChannel_test.cpp + AnimationChannelRaco_test.cpp CubeMap_test.cpp DefaultValues_test.cpp Material_test.cpp diff --git a/datamodel/libUserTypes/tests/Material_test.cpp b/datamodel/libUserTypes/tests/Material_test.cpp index 3b6fccca..7ebc5ed1 100644 --- a/datamodel/libUserTypes/tests/Material_test.cpp +++ b/datamodel/libUserTypes/tests/Material_test.cpp @@ -53,7 +53,7 @@ class MaterialTest : public TestEnvironmentCore { out.close(); // Expect file watcher was executed and shader was reloaded - EXPECT_TRUE(raco::awaitPreviewDirty(recorder, material, 5)); + EXPECT_TRUE(awaitPreviewDirty(recorder, material, 5)); } }; @@ -222,9 +222,6 @@ TEST_F(MaterialTest, preprocessorHandlesShaderIncludes) { ASSERT_FALSE(commandInterface.errors().hasError(material)); } -#if (!defined (__linux__)) -// awaitPreviewDirty does not work in Linux as expected. See RAOS-692 - TEST_F(MaterialTest, shaderFileWatcherTest) { const std::vector files{ "shaders/include/main_mat_adapter_test.vert", @@ -245,5 +242,3 @@ TEST_F(MaterialTest, shaderFileWatcherTest) { verifyFileWatcher(file); } } - -#endif diff --git a/datamodel/libUserTypes/tests/Texture_test.cpp b/datamodel/libUserTypes/tests/Texture_test.cpp index d0aa1a32..0ec05986 100644 --- a/datamodel/libUserTypes/tests/Texture_test.cpp +++ b/datamodel/libUserTypes/tests/Texture_test.cpp @@ -55,7 +55,7 @@ TEST_F(TextureTest, error_present_after_load) { ramses_base::HeadlessEngineBackend backend; { - raco::application::RaCoApplication app{backend}; + application::RaCoApplication app{backend}; auto& cmd = *app.activeRaCoProject().commandInterface(); auto texture{cmd.createObject(Texture::typeDescription.typeName, "texture")}; @@ -67,9 +67,9 @@ TEST_F(TextureTest, error_present_after_load) { } { - raco::application::RaCoApplicationLaunchSettings settings; + application::RaCoApplicationLaunchSettings settings; settings.initialProject = (test_path() / "test.rca").string().c_str(); - raco::application::RaCoApplication app{backend, settings}; + application::RaCoApplication app{backend, settings}; auto& project = *app.activeRaCoProject().project(); diff --git a/doc/advanced/python_api/README.md b/doc/advanced/python_api/README.md index ad712b3b..e0ffe4d6 100644 --- a/doc/advanced/python_api/README.md +++ b/doc/advanced/python_api/README.md @@ -254,6 +254,15 @@ Member functions: > setRenderableTags(renderableTags) >> Set the `renderableTags` property of `RenderLayer` object from a list of (tag, priority) tuples. +> getAnimationTimeStamps() +>> Return the time stamps of the animation curve of an `AnimationChannelRaco` object as a list of numbers. + +> getAnimationOutputData() +>> Return the output data of the animation curve of an `AnimationChannelRaco` object as a list `[keyFrames, tangentsIn, tangentsOut]` where `keyFrames`, `tangentsIn`, and `tangentsOut` are themselves lists containing the individual values. The individual values are numbers if the component type is either `Int` or `Float` and a list if the component type is a vector or an array type. Both `tangentsIn` and `tangentsOut` will be empty lists if the `interpolationType` property is not either `CubicSpline` or `CubicSpline_Quaternion`. + +> setAnimationData(timeStamps, keyFrames[, tangentsIn, tangentsOut]) +>> Set the animation data of an `AnimationChannelRaco` object. The data must match the component and interpolation types set in the `componentType` and `interpolationType` properties of the object. The expected format of the data matches the data returned by the `getAnimationTimeStamps` and `getAnimationOuputData` functions, i.e. the `timeStamps` must be a list of floats while the `keyFrames`, `tangentsIn`, and `tangentsOut` parameters must be either lists of numbers for scalar component types or lists of lists of numbers for vector/array component types. The `tangentsIn` and `tangentsOut` parameters are optional and need to be specified only for `CubicSpline` or `CubicSpline_Quaternion` interpolation types. + ### Properties diff --git a/gui/libCommonWidgets/CMakeLists.txt b/gui/libCommonWidgets/CMakeLists.txt index 4928b0fa..bd9be00c 100644 --- a/gui/libCommonWidgets/CMakeLists.txt +++ b/gui/libCommonWidgets/CMakeLists.txt @@ -20,12 +20,17 @@ add_library(libCommonWidgets include/common_widgets/LogView.h src/LogView.cpp include/common_widgets/MeshAssetImportDialog.h src/MeshAssetImportDialog.cpp include/common_widgets/NoContentMarginsLayout.h + include/common_widgets/PerformanceTableView.h src/PerformanceTableView.cpp + include/common_widgets/PerformanceModel.h src/PerformanceModel.cpp include/common_widgets/PreferencesView.h src/PreferencesView.cpp include/common_widgets/PropertyBrowserButton.h src/PropertyBrowserButton.cpp include/common_widgets/QtGuiFormatter.h include/common_widgets/RaCoClipboard.h src/RaCoClipboard.cpp + include/common_widgets/PythonConsole.h src/PythonConsole.cpp + include/common_widgets/PythonHighlighter.h src/PythonHighlighter.cpp + include/common_widgets/PythonScriptEditor.h src/PythonScriptEditor.cpp + include/common_widgets/PythonOutputDialog.h include/common_widgets/RunScriptDialog.h src/RunScriptDialog.cpp - include/common_widgets/TimingsWidget.h include/common_widgets/TracePlayerWidget.h src/TracePlayerWidget.cpp include/common_widgets/UndoView.h src/UndoView.cpp ) @@ -45,10 +50,10 @@ target_link_libraries(libCommonWidgets Qt5::Widgets raco::Components raco::ApplicationLib - raco::Style PRIVATE raco::LogSystem raco::Style + raco::PythonAPI ) add_library(raco::CommonWidgets ALIAS libCommonWidgets) diff --git a/gui/libCommonWidgets/include/common_widgets/PerformanceModel.h b/gui/libCommonWidgets/include/common_widgets/PerformanceModel.h new file mode 100644 index 00000000..067691c0 --- /dev/null +++ b/gui/libCommonWidgets/include/common_widgets/PerformanceModel.h @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "components/DataChangeDispatcher.h" + +#include + +namespace raco::application { +class RaCoApplication; +} + +namespace raco::common_widgets { + +class PerformanceModel : public QAbstractTableModel { + Q_OBJECT + + using base = QAbstractTableModel; + + enum class Columns : int { + ID = 0, + Current = 1, + Average = 2, + Maximum = 3, + COLUMN_COUNT + }; + +public: + explicit PerformanceModel(application::RaCoApplication* application, QObject* parent = nullptr); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + QVariant data(const QModelIndex& index, int role) const override; + + std::string objectID(const QModelIndex& index) const; + +private: + void rebuildItems(); + + struct Item { + std::string objectID; + std::string objectName; + std::chrono::microseconds time_cur; + std::chrono::microseconds time_avg; + std::chrono::microseconds time_max; + }; + + application::RaCoApplication* application_; + + std::vector items_; + bool dirty_ = false; + + components::Subscription lifeCycleSubscription_; + components::Subscription afterDispatchSubscription_; +}; + +} // namespace raco::common_widgets \ No newline at end of file diff --git a/gui/libCommonWidgets/include/common_widgets/PerformanceTableView.h b/gui/libCommonWidgets/include/common_widgets/PerformanceTableView.h new file mode 100644 index 00000000..056c8db8 --- /dev/null +++ b/gui/libCommonWidgets/include/common_widgets/PerformanceTableView.h @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once +#include "application/RaCoApplication.h" + +#include + +namespace raco::common_widgets { + +class PerformanceTableView : public QWidget { + Q_OBJECT +public: + explicit PerformanceTableView(application::RaCoApplication* application, components::SDataChangeDispatcher dispatcher, QWidget* parent); + +Q_SIGNALS: + void objectSelectionRequested(const QString& objectID); + +private: + static inline const auto ROW_HEIGHT = 22; + + application::RaCoApplication* application_; + components::SDataChangeDispatcher dispatcher_; +}; + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/PreferencesView.h b/gui/libCommonWidgets/include/common_widgets/PreferencesView.h index 4ca78b92..04462459 100644 --- a/gui/libCommonWidgets/include/common_widgets/PreferencesView.h +++ b/gui/libCommonWidgets/include/common_widgets/PreferencesView.h @@ -10,6 +10,7 @@ #pragma once #include "components/RaCoPreferences.h" +#include "application/RaCoApplication.h" #include #include @@ -25,7 +26,7 @@ namespace raco::common_widgets { class PreferencesView final : public QDialog { Q_OBJECT public: - explicit PreferencesView(QWidget* parent); + explicit PreferencesView(application::RaCoApplication* racoApp, QWidget* parent); bool dirty(); @@ -33,12 +34,18 @@ class PreferencesView final : public QDialog { Q_SIGNAL void dirtyChanged(bool dirty); private: + application::RaCoApplication* racoApp_; + QLineEdit* userProjectEdit_; QSpinBox* featureLevelEdit_; QCheckBox* uriValidationCaseSensitiveCheckbox_; QCheckBox* preventAccidentalUpgradeEdit_; QCheckBox* preventAccidentalUpgradeCheckbox_; QLineEdit* screenshotDirectoryEdit_; + QLineEdit* globalPythonScriptEdit_; + QCheckBox* projectPythonScriptCheckbox_; + + QString convertPathToAbsolute(const QString& path) const; }; } // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/PythonConsole.h b/gui/libCommonWidgets/include/common_widgets/PythonConsole.h new file mode 100644 index 00000000..8906561a --- /dev/null +++ b/gui/libCommonWidgets/include/common_widgets/PythonConsole.h @@ -0,0 +1,73 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace raco::common_widgets { + +class PythonConsole : public QPlainTextEdit { + Q_OBJECT + +public: + PythonConsole(QWidget* parent = nullptr); + void clearConsole(); + void addOutput(const QString& output, const QString& error); + void addOutputFromScriptEditor(const QString& output, const QString& error); + +Q_SIGNALS: + void runPythonScript(const QString& script); + +protected: + void keyPressEvent(QKeyEvent* event) override; + void insertFromMimeData(const QMimeData* source) override; + +private slots: + void insertCompletion(const QString& completion); + +private: + QString getCompletionPrefix() const; + void updateCompleterModel(const QString& prefix) const; + void appendNewLine(); + void appendInputArrows(); + void insertInputArrows(); + void appendInputDots(); + void insertPythonVersion(); + void moveCursorToLineBeginning(); + void moveCursorToLastPosition(); + void recallPreviousCommand(); + void recallNextCommand(); + void accumulateCommand(); + void executeCommand(const QString& command); + void addCommandToHistory(const QString& command); + void cleanCurrentLine(); + bool isMovingLeftAllowed() const; + bool isMovingRightAllowed() const; + bool isDeletingAllowed() const; + bool isActionAllowed(int positionOffset, bool checkLine = false) const; + bool isTypingAllowed() const; + QString getCurrentCommand() const; + + QString pythonVersion_{""}; + int commandHistoryIndex_{0}; + QStringList commandHistory_{}; + QString commandAccumulator_{""}; + QString lastCommand_{""}; + QCompleter* completer_; +}; + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/PythonHighlighter.h b/gui/libCommonWidgets/include/common_widgets/PythonHighlighter.h new file mode 100644 index 00000000..88c991f0 --- /dev/null +++ b/gui/libCommonWidgets/include/common_widgets/PythonHighlighter.h @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "style/Colors.h" + +#include +#include +#include +#include + +namespace raco::common_widgets { + +class PythonHighlighter : public QSyntaxHighlighter { +public: + PythonHighlighter(QTextDocument *parent = nullptr, bool consoleMode = false); + +protected: + void highlightBlock(const QString &text) override; + +private: + struct HighlightingRule { + QRegularExpression pattern; + QTextCharFormat format; + }; + + bool isConsole_{false}; + + QList highlightingRules_; + + QRegularExpression commentStartExpression_; + QRegularExpression commentEndExpression_; + + QTextCharFormat numberFormat_; + QTextCharFormat keywordFormat_; + QTextCharFormat classFormat; + QTextCharFormat singleLineCommentFormat_; + QTextCharFormat multiLineCommentFormat_; + QTextCharFormat quotationFormat_; + QTextCharFormat operatorsFormat_; + QTextCharFormat indentationFormat_; + QTextCharFormat arrowsFormat_; +}; + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/PythonOutputDialog.h b/gui/libCommonWidgets/include/common_widgets/PythonOutputDialog.h new file mode 100644 index 00000000..6e40fbf8 --- /dev/null +++ b/gui/libCommonWidgets/include/common_widgets/PythonOutputDialog.h @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "style/Colors.h" + +#include +#include +#include +#include + +namespace raco::common_widgets { + +class PythonOutputDialog : public QDialog { +public: + PythonOutputDialog(const QString& title, const QString& output, const QString& error, QWidget* parent = nullptr) : QDialog(parent) { + setWindowTitle(title); + + auto icon = style()->standardIcon(QStyle::SP_MessageBoxInformation); + + auto* textEdit = new QTextEdit(); + textEdit->setReadOnly(true); + + if (!output.isEmpty()) { + textEdit->append("Script output:\n"); + textEdit->append(output + "\n"); + } + + if (!error.isEmpty()) { + const auto errorColorHEX = style::Colors::color(style::Colormap::errorColorLight).name(); + textEdit->append("Script error:\n"); + textEdit->append(QString("" + error + "").arg(errorColorHEX)); + icon = style()->standardIcon(QStyle::SP_MessageBoxWarning); + } + + setWindowIcon(icon); + + auto* okButton = new QPushButton("Ok"); + connect(okButton, &QPushButton::clicked, this, &QDialog::accept); + + auto* layout = new QVBoxLayout(this); + layout->addWidget(textEdit); + layout->addWidget(okButton); + + resize(600, 400); + } +}; + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/PythonScriptEditor.h b/gui/libCommonWidgets/include/common_widgets/PythonScriptEditor.h new file mode 100644 index 00000000..e1d787a3 --- /dev/null +++ b/gui/libCommonWidgets/include/common_widgets/PythonScriptEditor.h @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace raco::common_widgets { + +class PythonScriptEditor : public QPlainTextEdit { +public: + PythonScriptEditor(QWidget* parent = nullptr); + QString getExpression() const; + void updateText(QString text); + +protected: + void insertFromMimeData(const QMimeData* source) override; + QMimeData* createMimeDataFromSelection() const override; + void keyPressEvent(QKeyEvent* event) override; + +private slots: + void insertCompletion(const QString& completion); + void duplicateCurrentLine() const; + void updateCompleterModel(const QString& prefix) const; + +private: + QString getCompletionPrefix() const; + void addSpaces(int spaceCount); + int getSpacesAtBeginningOfLine() const; + + QCompleter* completer_; + const QChar indentationSymbol_{QChar(0x2219)}; +}; + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/RunScriptDialog.h b/gui/libCommonWidgets/include/common_widgets/RunScriptDialog.h index ca9ae928..88a474ea 100644 --- a/gui/libCommonWidgets/include/common_widgets/RunScriptDialog.h +++ b/gui/libCommonWidgets/include/common_widgets/RunScriptDialog.h @@ -9,46 +9,61 @@ */ #pragma once -#include "common_widgets/log_model/LogViewSortFilterProxyModel.h" +#include "PythonHighlighter.h" +#include "PythonScriptEditor.h" +#include "PythonConsole.h" -#include #include #include #include #include -#include #include -#include namespace raco::common_widgets { +class RaCoApplication; + class RunScriptDialog final : public QWidget { Q_OBJECT public: + enum class ScriptSource { + Editor, + Console + }; + static constexpr auto ENTRIES_SIZE = 3; RunScriptDialog(std::map& scriptEntries, std::map& commandLineParamEntries, QWidget* parent = nullptr); - - void addPythonOutput(const std::string& outBuffer, const std::string& errorBuffer); - void setScriptIsRunning(bool isRunning); + + void addOutputFromScriptEditor(const std::string& outBuffer, const std::string& errorBuffer) const; + void addOutputFromConsole(const std::string& outBuffer, const std::string& errorBuffer) const; + void setScriptIsRunning(bool isRunning) const; Q_SIGNALS: - void pythonScriptRunRequested(const QString& pythonFilePath, const QStringList& arguments); + void runScriptRequested(const QString& script, const ScriptSource source); + +private slots: + void updateButtonStates() const; + void runScript(const QString& script, const ScriptSource source); + void saveScript(const QString& filePath) const; + void saveScriptAs() const; + void clearConsole() const; private: - Q_SLOT void updateButtonStates(); - Q_SLOT void runScript(); - void updateComboBoxItems(); + void updateComboBoxItems() const; + QString getPythonFileContent(const QString& filePath) const; - QGridLayout* scriptSettingsLayout_; - QGridLayout* layout_; QComboBox* scriptPathEdit_; - QComboBox* argumentsEdit_; QPushButton* scriptPathURIButton_; - QPlainTextEdit* statusTextBlock_; - QDialogButtonBox* buttonBox_; + + PythonScriptEditor* scriptTextEdit_; + QDialogButtonBox* scriptButtonBox_; + PythonConsole* pythonConsole_; + QDialogButtonBox* clearConsoleButtonBox_; + + PythonHighlighter* scriptEditorHighlighter_; + PythonHighlighter* consoleHighlighter_; + std::map& scriptEntries_; - std::map& commandLineParamEntries_; - LogViewModel* logModel_; }; } // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/include/common_widgets/TimingsWidget.h b/gui/libCommonWidgets/include/common_widgets/TimingsWidget.h deleted file mode 100644 index 43b1fd4e..00000000 --- a/gui/libCommonWidgets/include/common_widgets/TimingsWidget.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-License-Identifier: MPL-2.0 - * - * This file is part of Ramses Composer - * (see https://github.com/bmwcarit/ramses-composer). - * - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -#pragma once - -#include "common_widgets/NoContentMarginsLayout.h" -#include -#include -#include -#include -#include - -namespace raco::common_widgets { - -class TimingsModel : public QObject { - Q_OBJECT -public: - explicit TimingsModel(QObject* parent = nullptr) : QObject{parent} {} - -public Q_SLOTS: - void addLogicEngineTotalExecutionDuration(long long microseconds) { - logicEngineExecutionTimeAverage_ = static_cast(logicEngineExecutionTimeAverage_ * averageDampening_ + (microseconds * (1.0 - averageDampening_))); - Q_EMIT logicEngineExecutionTimeAverageUpdated(logicEngineExecutionTimeAverage_); - } - -Q_SIGNALS: - void logicEngineExecutionTimeAverageUpdated(long long value); - -private: - double averageDampening_{0.9}; - long long logicEngineExecutionTimeAverage_{0}; -}; - -class TimingsWidget : public QWidget { -public: - explicit TimingsWidget(TimingsModel* model, QWidget* parent = nullptr) : QWidget{parent} { - layout_.addWidget(new QLabel{"Total logic engine execution time:", this}, 0, 0); - auto valueLabel = new QLabel{"", this}; - QObject::connect(model, &TimingsModel::logicEngineExecutionTimeAverageUpdated, this, [this, valueLabel](long long value) { - valueLabel->setText(QString{"%1"}.arg(value)); - }); - layout_.addWidget(valueLabel, 0, 1); - } - -private: - NoContentMarginsLayout layout_{this}; -}; - -} // namespace raco::common_widgets \ No newline at end of file diff --git a/gui/libCommonWidgets/src/ErrorView.cpp b/gui/libCommonWidgets/src/ErrorView.cpp index eacd88fb..71b3cf17 100644 --- a/gui/libCommonWidgets/src/ErrorView.cpp +++ b/gui/libCommonWidgets/src/ErrorView.cpp @@ -107,11 +107,13 @@ ErrorView::ErrorView(core::CommandInterface* commandInterface, components::SData tableView_->verticalHeader()->setMinimumSectionSize(ROW_HEIGHT); tableView_->verticalHeader()->setMaximumSectionSize(ROW_HEIGHT); tableView_->verticalHeader()->setDefaultSectionSize(ROW_HEIGHT); - connect(tableView_, &QTableView::doubleClicked, [this](const auto& selectedIndex) { - auto modelIndex = proxyModel_->mapToSource(selectedIndex); - Q_EMIT objectSelectionRequested(QString::fromStdString(indexToObjID_[modelIndex.row()])); - }); - connect(tableView_, &QTableView::customContextMenuRequested, this, &ErrorView::createCustomContextMenu); + if (!embeddedInExportView) { + connect(tableView_, &QTableView::doubleClicked, [this](const auto& selectedIndex) { + auto modelIndex = proxyModel_->mapToSource(selectedIndex); + Q_EMIT objectSelectionRequested(QString::fromStdString(indexToObjID_[modelIndex.row()])); + }); + connect(tableView_, &QTableView::customContextMenuRequested, this, &ErrorView::createCustomContextMenu); + } errorViewLayout->addWidget(tableView_); if (showFilterLayout_) { diff --git a/gui/libCommonWidgets/src/ExportDialog.cpp b/gui/libCommonWidgets/src/ExportDialog.cpp index ca6cd783..4574f4f9 100644 --- a/gui/libCommonWidgets/src/ExportDialog.cpp +++ b/gui/libCommonWidgets/src/ExportDialog.cpp @@ -163,7 +163,9 @@ ExportDialog::ExportDialog(application::RaCoApplication* application, LogViewMod textBox->setAcceptRichText(false); textBox->setText(QString::fromStdString(message)); - showExportWithErrors = true; + if (sceneStatus == core::ErrorLevel::ERROR) { + showExportWithErrors = true; + } tabWidget->setCurrentIndex(tabWidget->addTab(textBox, sceneStatus == core::ErrorLevel::ERROR ? "Ramses Errors" : "Ramses Warnings")); } diff --git a/gui/libCommonWidgets/src/PerformanceModel.cpp b/gui/libCommonWidgets/src/PerformanceModel.cpp new file mode 100644 index 00000000..47d215db --- /dev/null +++ b/gui/libCommonWidgets/src/PerformanceModel.cpp @@ -0,0 +1,96 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "common_widgets/PerformanceModel.h" + +#include "application/RaCoApplication.h" +#include "core/Project.h" + +namespace raco::common_widgets { + +PerformanceModel::PerformanceModel(application::RaCoApplication* application, QObject* parent) + : QAbstractTableModel(parent), + application_(application) { + QObject::connect(application, &application::RaCoApplication::performanceStatisticsUpdated, this, [this]() { + dirty_ = true; + }); + + lifeCycleSubscription_ = application->dataChangeDispatcher()->registerOnObjectsLifeCycle( + [this](auto SEditorObject) { dirty_ = true; }, + [this](auto SEditorObject) { dirty_ = true; }); + + afterDispatchSubscription_ = application->dataChangeDispatcher()->registerOnAfterDispatch([this]() { + if (dirty_) { + rebuildItems(); + } + }); +} + +void PerformanceModel::rebuildItems() { + beginResetModel(); + items_.clear(); + items_.reserve(application_->getLogicStats().getTimingData().size()); + for (const auto& [objectID, timings] : application_->getLogicStats().getTimingData()) { + if (auto obj = application_->activeRaCoProject().project()->getInstanceByID(objectID)) { + auto current = timings.back(); + auto max = *std::max_element(timings.begin(), timings.end()); + auto avg = std::accumulate(timings.begin(), timings.end(), std::chrono::microseconds{0}) / timings.size(); + items_.emplace_back(Item{objectID, obj->objectName(), current, avg, max}); + } + } + endResetModel(); + dirty_ = false; +} + +int PerformanceModel::rowCount(const QModelIndex& parent) const { + return items_.size(); +} + +int PerformanceModel::columnCount(const QModelIndex& parent) const { + return static_cast(Columns::COLUMN_COUNT); +} + +QVariant PerformanceModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role == Qt::DisplayRole) { + switch (static_cast(section)) { + case Columns::ID: + return {"Name"}; + case Columns::Current: + return {"Current (us)"}; + case Columns::Average: + return {"Average (us)"}; + case Columns::Maximum: + return {"Maximum (us)"}; + } + } + return base::headerData(section, orientation, role); +} + +QVariant PerformanceModel::data(const QModelIndex& index, int role) const { + if (role == Qt::DisplayRole) { + switch (static_cast(index.column())) { + case Columns::ID: + return QVariant(QString::fromStdString(items_[index.row()].objectName)); + case Columns::Current: + return QVariant(static_cast(items_[index.row()].time_cur.count())); + case Columns::Average: + return QVariant(static_cast(items_[index.row()].time_avg.count())); + case Columns::Maximum: + return QVariant(static_cast(items_[index.row()].time_max.count())); + } + } + return {}; +} + +std::string PerformanceModel::objectID(const QModelIndex& index) const { + return items_[index.row()].objectID; +} + +} // namespace raco::common_widgets \ No newline at end of file diff --git a/gui/libCommonWidgets/src/PerformanceTableView.cpp b/gui/libCommonWidgets/src/PerformanceTableView.cpp new file mode 100644 index 00000000..e63cafa8 --- /dev/null +++ b/gui/libCommonWidgets/src/PerformanceTableView.cpp @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "common_widgets/PerformanceTableView.h" + +#include "common_widgets/NoContentMarginsLayout.h" +#include "common_widgets/PerformanceModel.h" + +#include "style/Icons.h" + +#include +#include +#include +#include +#include +#include + +namespace raco::common_widgets { + +PerformanceTableView::PerformanceTableView(application::RaCoApplication* application, components::SDataChangeDispatcher dispatcher, QWidget* parent) + : QWidget(parent), application_(application), dispatcher_(dispatcher) { + auto mainLayout{new NoContentMarginsLayout(this)}; + + const auto tableModel = new PerformanceModel{application_, this}; + + const auto sortModel = new QSortFilterProxyModel(this); + sortModel->setSourceModel(tableModel); + + const auto tableView = new QTableView(this); + + tableView->setModel(sortModel); + tableView->setSelectionMode(QAbstractItemView::NoSelection); + tableView->setContextMenuPolicy(Qt::NoContextMenu); + tableView->setDragDropMode(QAbstractItemView::NoDragDrop); + tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + tableView->setSortingEnabled(true); + tableView->setAlternatingRowColors(true); + tableView->horizontalHeader()->setStretchLastSection(true); + tableView->verticalHeader()->setVisible(false); + tableView->verticalHeader()->setMinimumSectionSize(ROW_HEIGHT); + tableView->verticalHeader()->setMaximumSectionSize(ROW_HEIGHT); + tableView->verticalHeader()->setDefaultSectionSize(ROW_HEIGHT); + + // Note: we have to used the pressed instead of the clicked or doubleClicked events here to avoid + // interference from the rendering timer: clicked events only seem to be generated by the button up + // event. However if the model is reset between the button down and buttont up events no clicked event + // will be generated. This happens when recording statistics is active since the model is then reset every frame. + connect(tableView, &QTableView::pressed, [this, tableModel, sortModel](const auto& selectedIndex) { + auto modelIndex = sortModel->mapToSource(selectedIndex); + Q_EMIT objectSelectionRequested(QString::fromStdString(tableModel->objectID(modelIndex))); + }); + + const auto toolbarWidget = new QWidget(); + const auto toolbarLayout = new NoContentMarginsLayout(toolbarWidget); + toolbarLayout->setContentsMargins(2, 3, 2, 0); + + const auto recordButton = new QPushButton(this); + recordButton->setCheckable(true); + recordButton->setIcon(style::Icons::instance().recordInactive); + recordButton->setToolTip("Record/Stop"); + connect(recordButton, &QPushButton::toggled, this, [this, recordButton](bool checked) { + application_->setRecordingStats(checked); + recordButton->setIcon(checked ? style::Icons::instance().recordActive : style::Icons::instance().recordInactive); + }); + toolbarLayout->addWidget(recordButton); + + const auto resetButton = new QPushButton(this); + resetButton->setIcon(style::Icons::instance().remove); + resetButton->setToolTip("Reset"); + connect(resetButton, &QPushButton::clicked, this, [this]() { + application_->resetStats(); + }); + toolbarLayout->addWidget(resetButton); + + toolbarLayout->addStretch(); + + mainLayout->addWidget(toolbarWidget); + mainLayout->addWidget(tableView); +} + +} // namespace raco::common_widgets \ No newline at end of file diff --git a/gui/libCommonWidgets/src/PreferencesView.cpp b/gui/libCommonWidgets/src/PreferencesView.cpp index 104c3894..a28c3119 100644 --- a/gui/libCommonWidgets/src/PreferencesView.cpp +++ b/gui/libCommonWidgets/src/PreferencesView.cpp @@ -14,24 +14,21 @@ #include "common_widgets/PropertyBrowserButton.h" #include "core/PathManager.h" #include "log_system/log.h" -#include "application/RaCoApplication.h" #include #include #include #include #include -#include #include #include #include -#include namespace raco::common_widgets { using RaCoPreferences = components::RaCoPreferences; -PreferencesView::PreferencesView(QWidget* parent) : QDialog{parent} { +PreferencesView::PreferencesView(application::RaCoApplication* racoApp, QWidget* parent) : QDialog{parent}, racoApp_{racoApp} { auto layout = new QVBoxLayout{this}; auto form = new QWidget{this}; layout->addWidget(form, Qt::AlignTop); @@ -90,6 +87,7 @@ PreferencesView::PreferencesView(QWidget* parent) : QDialog{parent} { Q_EMIT dirtyChanged(dirty()); }); + // Screenshot { auto* selectScreenshotDirectoryButton = new PropertyBrowserButton(" ... ", this); @@ -117,6 +115,43 @@ PreferencesView::PreferencesView(QWidget* parent) : QDialog{parent} { }); } + // Global onSave Python script (stored as an absolute path) + { + auto* selectGlobalPythonButton = new PropertyBrowserButton(" ... ", this); + + auto container = new QWidget{this}; + auto containerLayout = new QGridLayout{container}; + globalPythonScriptEdit_ = new QLineEdit{this}; + + containerLayout->addWidget(globalPythonScriptEdit_, 0, 0); + containerLayout->addWidget(selectGlobalPythonButton, 0, 1); + containerLayout->setColumnStretch(0, 1); + containerLayout->setMargin(0); + + formLayout->addRow("Python Script on Save (Global)", container); + const auto globalPythonOnSaveScript = RaCoPreferences::instance().globalPythonOnSaveScript; + globalPythonScriptEdit_->setText(convertPathToAbsolute(globalPythonOnSaveScript)); + QObject::connect(globalPythonScriptEdit_, &QLineEdit::textChanged, this, [this](auto) { + Q_EMIT dirtyChanged(dirty()); + }); + + QObject::connect(selectGlobalPythonButton, &QPushButton::clicked, [this]() { + auto globalPythonOnSaveScript = globalPythonScriptEdit_->text(); + globalPythonOnSaveScript = QFileDialog::getOpenFileName(this, "Select Python Script (Global)", globalPythonOnSaveScript, "*.py"); + globalPythonScriptEdit_->setText(convertPathToAbsolute(globalPythonOnSaveScript)); + }); + } + + // Project onSave Python script (stored as a relative path) + projectPythonScriptCheckbox_ = new QCheckBox(this); + projectPythonScriptCheckbox_->setCheckState(RaCoPreferences::instance().enableProjectPythonScript ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + projectPythonScriptCheckbox_->setToolTip("Enable running Python Script on Save (Project)"); + formLayout->addRow("Enable Python Script on Save (Project)", projectPythonScriptCheckbox_); + + QObject::connect(projectPythonScriptCheckbox_, &QCheckBox::stateChanged, this, [this]() { + Q_EMIT dirtyChanged(dirty()); + }); + auto buttonBox = new QDialogButtonBox{this}; auto cancelButton{new QPushButton{"Close", buttonBox}}; QObject::connect(cancelButton, &QPushButton::clicked, this, &PreferencesView::close); @@ -156,6 +191,9 @@ void PreferencesView::save() { prefs.isUriValidationCaseSensitive = uriValidationCaseSensitiveCheckbox_->checkState() == Qt::CheckState::Checked; prefs.preventAccidentalUpgrade = preventAccidentalUpgradeCheckbox_->checkState() == Qt::CheckState::Checked; prefs.screenshotDirectory = screenshotDirectoryEdit_->text(); + prefs.screenshotDirectory = screenshotDirectoryEdit_->text(); + prefs.globalPythonOnSaveScript = convertPathToAbsolute(globalPythonScriptEdit_->text()); + prefs.enableProjectPythonScript = projectPythonScriptCheckbox_->checkState() == Qt::CheckState::Checked; if (!prefs.save()) { LOG_ERROR(log_system::COMMON, "Saving settings failed: {}", core::PathManager::preferenceFilePath().string()); @@ -171,7 +209,18 @@ bool PreferencesView::dirty() { prefs.featureLevel != featureLevelEdit_->value() || prefs.isUriValidationCaseSensitive != (uriValidationCaseSensitiveCheckbox_->checkState() == Qt::CheckState::Checked) || prefs.preventAccidentalUpgrade != (preventAccidentalUpgradeCheckbox_->checkState() == Qt::CheckState::Checked) || - prefs.screenshotDirectory != screenshotDirectoryEdit_->text(); + prefs.screenshotDirectory != screenshotDirectoryEdit_->text() || + prefs.globalPythonOnSaveScript != globalPythonScriptEdit_->text() || + prefs.enableProjectPythonScript != (projectPythonScriptCheckbox_->checkState() == Qt::CheckState::Checked); +} + +QString PreferencesView::convertPathToAbsolute(const QString& path) const { + if (!path.isEmpty()) { + auto scriptPath = utils::u8path(path.toStdString()); + scriptPath = scriptPath.normalizedAbsolutePath(racoApp_->activeProjectFolder()); + return QString::fromStdString(scriptPath.string()); + } + return {}; } } // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/src/PythonConsole.cpp b/gui/libCommonWidgets/src/PythonConsole.cpp new file mode 100644 index 00000000..18a9c14c --- /dev/null +++ b/gui/libCommonWidgets/src/PythonConsole.cpp @@ -0,0 +1,350 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "common_widgets/PythonConsole.h" + +#include "python_api/PythonAPI.h" + +namespace raco::common_widgets { + +PythonConsole::PythonConsole(QWidget* parent) : QPlainTextEdit(parent) { + pythonVersion_ = QString::fromStdString(python_api::getPythonVersion()); + + setUndoRedoEnabled(false); + + appendInputArrows(); + insertPythonVersion(); + appendInputArrows(); + + // Setup the completer + QStringListModel* model = new QStringListModel(this); + completer_ = new QCompleter(this); + completer_->setModel(model); + completer_->setWidget(this); + completer_->setCompletionMode(QCompleter::PopupCompletion); + completer_->setCaseSensitivity(Qt::CaseInsensitive); + connect(completer_, QOverload::of(&QCompleter::activated), this, &PythonConsole::insertCompletion); + + setWordWrapMode(QTextOption::WrapMode::WrapAnywhere); + show(); +} + +void PythonConsole::keyPressEvent(QKeyEvent* event) { + // Handle only key presses + if (event->type() != QEvent::KeyPress) { + return; + } + + // Ignore undo/redo shortcuts + if (event->matches(QKeySequence::Undo) || event->matches(QKeySequence::Redo)) { + return; + } + + // Code completer events + if (completer_ && completer_->popup()->isVisible()) { + // The following keys are forwarded by the completer to the widget + switch (event->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Escape: + case Qt::Key_Tab: + case Qt::Key_Backtab: + event->ignore(); + return; // let the completer handle the event + default: + break; + } + } + + // Handle control buttons (Page Up/Down, Home/End, Arrow Up/Down, Enter...) + bool needsComleterUpdate = false; + switch (event->key()) { + case Qt::Key_Up: + recallPreviousCommand(); + break; + case Qt::Key_Down: + recallNextCommand(); + break; + case Qt::Key_Left: + if (isMovingLeftAllowed()) { + QPlainTextEdit::keyPressEvent(event); + } + break; + case Qt::Key_Right: + if (isMovingRightAllowed()) { + QPlainTextEdit::keyPressEvent(event); + } + break; + case Qt::Key_Home: + moveCursorToLineBeginning(); + break; + case Qt::Key_Backspace: + if (isDeletingAllowed()) { + QPlainTextEdit::keyPressEvent(event); + needsComleterUpdate = true; + } + break; + case Qt::Key_Return: + case Qt::Key_Enter: + accumulateCommand(); + break; + default: // Handle the rest of the buttons + if (isTypingAllowed()) { + QPlainTextEdit::keyPressEvent(event); + needsComleterUpdate = true; + } + break; + } + + if (needsComleterUpdate) { + const QString completionPrefix = getCompletionPrefix(); + if (completionPrefix.isEmpty()) { + completer_->popup()->close(); + return; + } + + if (completer_->completionPrefix() != completionPrefix) { + updateCompleterModel(completionPrefix); + + QRect cr = cursorRect(); + cr.setWidth(completer_->popup()->sizeHintForColumn(0) + completer_->popup()->verticalScrollBar()->sizeHint().width()); + completer_->complete(cr); + } + } +} + +void PythonConsole::insertFromMimeData(const QMimeData* source) { + QString textToInsert = source->text(); + textToInsert.replace("\n", "\n. . . "); + + QTextCursor cursor = textCursor(); + cursor.insertText(textToInsert); + setTextCursor(cursor); +} + +void PythonConsole::insertCompletion(const QString& completion) { + if (completer_->widget() != this) + return; + + QTextCursor cursor = textCursor(); + const auto trimmedCompletion = completion.mid(completer_->completionPrefix().length()); + cursor.insertText(trimmedCompletion); + setTextCursor(cursor); +} + +QString PythonConsole::getCompletionPrefix() const { + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + while (cursor.position() > 0 && document()->characterAt(cursor.position() - 1) == '.') { + cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); + } + return cursor.selectedText(); +} + +void PythonConsole::updateCompleterModel(const QString& prefix) const { + QStringList completions; + for (const auto& match : python_api::getCompletions(prefix.toStdString())) { + completions << QString::fromStdString(match); + } + + static_cast(completer_->model())->setStringList(completions); + completer_->setCompletionPrefix(prefix); + completer_->popup()->setCurrentIndex(completer_->completionModel()->index(0, 0)); +} + +void PythonConsole::appendNewLine() { + appendPlainText("\n"); +} + +void PythonConsole::appendInputArrows() { + appendPlainText(">>> "); +} + +void PythonConsole::insertInputArrows() { + insertPlainText(">>> "); +} + +void PythonConsole::appendInputDots() { + appendPlainText(". . . "); +} + +void PythonConsole::insertPythonVersion() { + insertPlainText("Python " + pythonVersion_); +} + +void PythonConsole::moveCursorToLineBeginning() { + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 4); + setTextCursor(cursor); +} + +void PythonConsole::moveCursorToLastPosition() { + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::End); + setTextCursor(cursor); +} + +bool PythonConsole::isMovingLeftAllowed() const { + return isActionAllowed(0); +} + +bool PythonConsole::isMovingRightAllowed() const { + return isActionAllowed(-1); +} + +bool PythonConsole::isDeletingAllowed() const { + return isActionAllowed(0, true); +} + +bool PythonConsole::isTypingAllowed() const { + return isActionAllowed(-1, true); +} + +bool PythonConsole::isActionAllowed(int positionOffset, bool checkLine) const { + const auto cursor = textCursor(); + const auto currentPositionInBlock = cursor.positionInBlock(); + const auto startsWithArrows = cursor.block().text().startsWith(">>> "); + // Position in line must be outside of arrows (4 position) or dots (8 positions) minus one + const auto minAllowedPosition = startsWithArrows ? (4 + positionOffset) : (8 + positionOffset); + + if (checkLine) { + const auto currentBlockNumber = cursor.blockNumber(); + const auto totalBlocks = document()->blockCount(); + return currentBlockNumber == totalBlocks - 1 && currentPositionInBlock > minAllowedPosition; + } else { + return currentPositionInBlock > minAllowedPosition; + } +} + +void PythonConsole::cleanCurrentLine() { + QTextCursor cursor = textCursor(); + + const QString lineContent = cursor.block().text(); + QString lineBeginning; + if (lineContent.startsWith(">>> ")) { + lineBeginning = ">>> "; + } else if (lineContent.startsWith(". . . ")) { + lineBeginning = ". . . "; + } + + cursor.movePosition(QTextCursor::End); + cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); + cursor.removeSelectedText(); + + insertPlainText(lineBeginning); +} + +void PythonConsole::clearConsole() { + clear(); + appendInputArrows(); + insertPythonVersion(); + appendInputArrows(); +} + +void PythonConsole::addOutput(const QString& output, const QString& error) { + if (!output.trimmed().isEmpty()) { + appendPlainText(output.trimmed()); + } + + if (!error.trimmed().isEmpty()) { + appendPlainText(error.trimmed()); + } + + appendInputArrows(); +} + +void PythonConsole::addOutputFromScriptEditor(const QString& output, const QString& error) { + insertPlainText("Running script from the editor..."); + addOutput(output, error); +} + +void PythonConsole::recallPreviousCommand() { + if (!isTypingAllowed()) { + return; + } + + if (commandHistoryIndex_ > 0) { + commandHistoryIndex_--; + cleanCurrentLine(); + insertPlainText(commandHistory_[commandHistoryIndex_]); + } +} + +void PythonConsole::recallNextCommand() { + if (!isTypingAllowed()) { + return; + } + + if (commandHistoryIndex_ < commandHistory_.size() - 1) { + commandHistoryIndex_++; + cleanCurrentLine(); + insertPlainText(commandHistory_[commandHistoryIndex_]); + } else { + // If we reach the latest command, clear the console + cleanCurrentLine(); + commandHistoryIndex_ = commandHistory_.size(); + } +} + +void PythonConsole::accumulateCommand() { + if (!isTypingAllowed()) { + return; + } + + const auto command = getCurrentCommand(); + if (!command.isEmpty()) { + commandAccumulator_ += command + "\n"; + } + + if (command.isEmpty()) { + if (!commandAccumulator_.isEmpty()) { + executeCommand(commandAccumulator_.trimmed()); + commandAccumulator_.clear(); + } else { + appendInputArrows(); + } + } else { + if (python_api::isCompleteCommand(commandAccumulator_.trimmed().toStdString())) { + executeCommand(commandAccumulator_.trimmed()); + commandAccumulator_.clear(); + } else { + appendInputDots(); + } + addCommandToHistory(command); + } +} + +void PythonConsole::executeCommand(const QString& command) { + moveCursorToLastPosition(); + Q_EMIT runPythonScript(command); +} + +void PythonConsole::addCommandToHistory(const QString& command) { + if (command != lastCommand_) { + commandHistory_ << command; + lastCommand_ = command; + } + + commandHistoryIndex_ = commandHistory_.size(); +} + +QString PythonConsole::getCurrentCommand() const { + QString command = textCursor().block().text(); + if (command.startsWith(">>> ")) { + command.remove(">>> "); + } else if (command.startsWith(". . . ")) { + command.remove(". . . "); + } + return command; +} + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/src/PythonHighlighter.cpp b/gui/libCommonWidgets/src/PythonHighlighter.cpp new file mode 100644 index 00000000..765eb481 --- /dev/null +++ b/gui/libCommonWidgets/src/PythonHighlighter.cpp @@ -0,0 +1,135 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "common_widgets/PythonHighlighter.h" + +namespace raco::common_widgets { + +PythonHighlighter::PythonHighlighter(QTextDocument *parent, bool consoleMode) : QSyntaxHighlighter(parent), isConsole_(consoleMode) { + HighlightingRule rule; + + if (!isConsole_) { + keywordFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::externalReference)); + + QStringList keywordPatterns; + keywordPatterns << "\\bFalse\\b" + << "\\bNone\\b" + << "\\bTrue\\b" + << "\\band\\b" + << "\\bas\\b" + << "\\bassert\\b" + << "\\bbreak\\b" + << "\\bclass\\b" + << "\\bcontinue\\b" + << "\\bdef\\b" + << "\\bdel\\b" + << "\\belif\\b" + << "\\belse\\b" + << "\\bexcept\\b" + << "\\bfinally\\b" + << "\\bfor\\b" + << "\\bfrom\\b" + << "\\bglobal\\b" + << "\\bif\\b" + << "\\bimport\\b" + << "\\bin\\b" + << "\\bis\\b" + << "\\blambda\\b" + << "\\bnonlocal\\b" + << "\\bnot\\b" + << "\\bor\\b" + << "\\bpass\\b" + << "\\braise\\b" + << "\\breturn\\b" + << "\\btry\\b" + << "\\bwhile\\b" + << "\\bwith\\b" + << "\\byield\\b"; + + for (const QString &pattern : keywordPatterns) { + rule.pattern = QRegularExpression(pattern); + rule.format = keywordFormat_; + highlightingRules_.append(rule); + } + + numberFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightNumbers)); + rule.pattern = QRegularExpression(QStringLiteral("\\b[0-9]+\\b|\\b[0-9]+\\.[0-9]+\\b")); + rule.format = numberFormat_; + highlightingRules_.append(rule); + + singleLineCommentFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightComments)); + rule.pattern = QRegularExpression(QStringLiteral("#[^\n]*")); + rule.format = singleLineCommentFormat_; + highlightingRules_.append(rule); + + quotationFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightComments)); + rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); + rule.format = quotationFormat_; + highlightingRules_.append(rule); + + quotationFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightComments)); + rule.pattern = QRegularExpression(QStringLiteral("'.*'")); + rule.format = quotationFormat_; + highlightingRules_.append(rule); + + operatorsFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::externalReference)); + rule.pattern = QRegularExpression(QStringLiteral("[(){}\\[\\]<>!=+\\-*/%^&|.,;:]+")); + rule.format = operatorsFormat_; + highlightingRules_.append(rule); + + indentationFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightIndentation)); + rule.pattern = QRegularExpression(QString(QChar(0x2219))); + rule.format = indentationFormat_; + highlightingRules_.append(rule); + + multiLineCommentFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightComments)); + commentStartExpression_ = QRegularExpression(QStringLiteral("\"\"\"\\b.*$")); + commentEndExpression_ = QRegularExpression(QStringLiteral("^.*\\b\"\"\"")); + } else { + arrowsFormat_.setForeground(raco::style::Colors::color(raco::style::Colormap::textHighlightArrows)); + rule.pattern = QRegularExpression(QStringLiteral(">>>|\\. \\. \\. ")); + rule.format = arrowsFormat_; + highlightingRules_.append(rule); + } +} + +void PythonHighlighter::highlightBlock(const QString &text) { + for (const HighlightingRule &rule : highlightingRules_) { + QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); + while (matchIterator.hasNext()) { + QRegularExpressionMatch match = matchIterator.next(); + setFormat(match.capturedStart(), match.capturedLength(), rule.format); + } + } + + if (!isConsole_) { + setCurrentBlockState(0); + + int startIndex = 0; + if (previousBlockState() != 1) + startIndex = text.indexOf(commentStartExpression_); + + while (startIndex >= 0) { + QRegularExpressionMatch match = commentEndExpression_.match(text, startIndex); + int endIndex = match.capturedStart(); + int commentLength; + if (endIndex == -1) { + setCurrentBlockState(1); + commentLength = text.length() - startIndex; + } else { + commentLength = endIndex - startIndex + match.capturedLength(); + } + setFormat(startIndex, commentLength, multiLineCommentFormat_); + startIndex = text.indexOf(commentStartExpression_, startIndex + commentLength); + } + } +} + +} // namespace raco::common_widgets \ No newline at end of file diff --git a/gui/libCommonWidgets/src/PythonScriptEditor.cpp b/gui/libCommonWidgets/src/PythonScriptEditor.cpp new file mode 100644 index 00000000..05501ddb --- /dev/null +++ b/gui/libCommonWidgets/src/PythonScriptEditor.cpp @@ -0,0 +1,211 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "common_widgets/PythonScriptEditor.h" + +#include "python_api/PythonAPI.h" + +#include +#include +#include +#include +#include +#include + +namespace raco::common_widgets { + +PythonScriptEditor::PythonScriptEditor(QWidget* parent) : QPlainTextEdit(parent) { + setPlaceholderText("Type your Python script here..."); + + // Set tabs alignment equal to 4 spaces + QTextOption textOption = document()->defaultTextOption(); + textOption.setTabStopDistance(4 * fontMetrics().horizontalAdvance(' ')); + document()->setDefaultTextOption(textOption); + + // Set up the completer_ + QStringListModel* model = new QStringListModel(this); + completer_ = new QCompleter(this); + completer_->setModel(model); + completer_->setWidget(this); + completer_->setCompletionMode(QCompleter::PopupCompletion); + completer_->setCaseSensitivity(Qt::CaseInsensitive); + connect(completer_, QOverload::of(&QCompleter::activated), this, &PythonScriptEditor::insertCompletion); + + // Add shortcut for duplicating the lines (Ctrl+D) + QShortcut* duplicateLineShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_D), this); + connect(duplicateLineShortcut, &QShortcut::activated, this, &PythonScriptEditor::duplicateCurrentLine); +} + +QString PythonScriptEditor::getExpression() const { + return toPlainText().replace(indentationSymbol_, ' '); +} + +void PythonScriptEditor::updateText(QString text) { + clear(); + insertPlainText(text.replace(' ', indentationSymbol_)); +} + +void PythonScriptEditor::insertFromMimeData(const QMimeData* source) { + QString textToInsert = source->text(); + textToInsert.replace(' ', indentationSymbol_); + + QTextCursor cursor = textCursor(); + cursor.insertText(textToInsert); + setTextCursor(cursor); +} + +QMimeData* PythonScriptEditor::createMimeDataFromSelection() const { + QMimeData* mimeData = QPlainTextEdit::createMimeDataFromSelection(); + if (!mimeData) + return nullptr; + + QString originalText = mimeData->text(); + QString modifiedText = originalText.replace(indentationSymbol_, QChar(' ')); + mimeData->setText(modifiedText); + + return mimeData; +} + +void PythonScriptEditor::keyPressEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Space) { + QTextCursor cursor = textCursor(); + cursor.insertText(QString(indentationSymbol_)); + setTextCursor(cursor); + } else { + // Code completion + if (completer_ && completer_->popup()->isVisible()) { + // The following keys are forwarded by the completer_ to the widget + switch (event->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Escape: + case Qt::Key_Tab: + case Qt::Key_Backtab: + event->ignore(); + return; // let the completer_ handle the event + default: + break; + } + } + + if (event->key() == Qt::Key_D && event->modifiers() == Qt::ControlModifier) { + duplicateCurrentLine(); + } else { + switch (event->key()) { + case Qt::Key_Tab: { + addSpaces(4); + break; + } + case Qt::Key_Enter: + case Qt::Key_Return: { + const int spaces = getSpacesAtBeginningOfLine(); + QPlainTextEdit::keyPressEvent(event); + addSpaces(spaces); + break; + } + default: + QPlainTextEdit::keyPressEvent(event); + break; + } + + // Set up the completion box + const QString completionPrefix = getCompletionPrefix(); + if (completionPrefix.isEmpty()) { + completer_->popup()->hide(); + return; + } + if (completionPrefix != completer_->completionPrefix()) { + updateCompleterModel(completionPrefix); + } + + QRect cr = cursorRect(); + cr.setWidth(completer_->popup()->sizeHintForColumn(0) + completer_->popup()->verticalScrollBar()->sizeHint().width()); + completer_->complete(cr); + } + } +} + +QString PythonScriptEditor::getCompletionPrefix() const { + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + QString prefix = cursor.selectedText(); + + // Move the cursor to the start of the word + cursor.movePosition(QTextCursor::StartOfWord); + + // Check if the symbol before is a dot and adjust the position accordingly + if (cursor.position() > 0 && document()->characterAt(cursor.position() - 1) == '.') { + // Move the cursor to include the word before the dot + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); + + prefix = prefix.prepend(cursor.selectedText()); + } + + return prefix; +} + +void PythonScriptEditor::insertCompletion(const QString& completion) { + if (completer_->widget() != this) + return; + + QTextCursor cursor = textCursor(); + const auto trimmedCompletion = completion.mid(completer_->completionPrefix().length()); + cursor.insertText(trimmedCompletion); + setTextCursor(cursor); +} + +void PythonScriptEditor::updateCompleterModel(const QString& prefix) const { + QStringList completions; + for (const auto& match : python_api::getCompletions(prefix.toStdString())) { + completions << QString::fromStdString(match); + } + + static_cast(completer_->model())->setStringList(completions); + completer_->setCompletionPrefix(prefix); + completer_->popup()->setCurrentIndex(completer_->completionModel()->index(0, 0)); +} + +void PythonScriptEditor::duplicateCurrentLine() const { + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::StartOfBlock); + QString currentLine = cursor.block().text(); + + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.insertText("\n" + currentLine); +} + +void PythonScriptEditor::addSpaces(int spaceCount) { + if (spaceCount > 0) { + QString bulletString = QString(spaceCount, indentationSymbol_); + insertPlainText(bulletString); + } +} + +int PythonScriptEditor::getSpacesAtBeginningOfLine() const { + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::StartOfLine); + + QString line = cursor.block().text(); + int spaceCount = 0; + + for (const QChar& character : line) { + if (character == indentationSymbol_) { + spaceCount++; + } else { + // Stop collecting spaces when a non-space character is encountered + break; + } + } + + return spaceCount; +} + +} // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/src/RunScriptDialog.cpp b/gui/libCommonWidgets/src/RunScriptDialog.cpp index 07ebe81a..e76655df 100644 --- a/gui/libCommonWidgets/src/RunScriptDialog.cpp +++ b/gui/libCommonWidgets/src/RunScriptDialog.cpp @@ -10,132 +10,213 @@ #include "common_widgets/RunScriptDialog.h" #include "core/PathManager.h" -#include "style/Colors.h" +#include "python_api/PythonAPI.h" #include "utils/u8path.h" -#include +#include #include #include #include #include #include -#include +#include +#include +#include +#include +#include namespace raco::common_widgets { RunScriptDialog::RunScriptDialog(std::map& scriptEntries, std::map& commandLineParamEntries, QWidget* parent) : QWidget{parent}, - scriptEntries_{scriptEntries}, - commandLineParamEntries_{commandLineParamEntries} -{ - - layout_ = new QGridLayout(this); - - scriptSettingsLayout_ = new QGridLayout(this); - - scriptPathEdit_ = new QComboBox(this); + scriptEntries_{scriptEntries}{ + // Python script path + const auto pathLabel = new QLabel("Python Script Path"); + scriptPathEdit_ = new QComboBox(); scriptPathEdit_->setEditable(true); - scriptPathURIButton_ = new QPushButton("...", this); + scriptPathURIButton_ = new QPushButton("..."); scriptPathURIButton_->setMaximumWidth(30); - scriptSettingsLayout_->addWidget(new QLabel{"Python Script Path", this}, 0, 0); - scriptSettingsLayout_->addWidget(scriptPathEdit_, 0, 1); - scriptSettingsLayout_->addWidget(scriptPathURIButton_, 0, 2); - QObject::connect(scriptPathEdit_, &QComboBox::currentTextChanged, this, &RunScriptDialog::updateButtonStates); QObject::connect(scriptPathURIButton_, &QPushButton::clicked, [this]() { - auto pythonPath = scriptPathEdit_->currentText(); - if (pythonPath.isEmpty()) { - auto cachedScriptPath = core::PathManager::getCachedPath(core::PathManager::FolderTypeKeys::Script, pythonPath.toStdString()); + auto pythonPath = scriptPathEdit_->currentText(); + if (pythonPath.isEmpty()) { + const auto cachedScriptPath = core::PathManager::getCachedPath(core::PathManager::FolderTypeKeys::Script, pythonPath.toStdString()); pythonPath = QString::fromStdString(cachedScriptPath.string()); - } + } - auto pythonScriptPath = QFileDialog::getOpenFileName(this, "Open Python Script", pythonPath, "Python Scripts (*.py);; All files (*.*)"); - if (!pythonScriptPath.isEmpty()) { + const auto pythonScriptPath = QFileDialog::getOpenFileName(this, "Open Python Script", pythonPath, "Python Scripts (*.py);; All files (*.*)"); + if (!pythonScriptPath.isEmpty()) { scriptPathEdit_->setCurrentText(pythonScriptPath); core::PathManager::setCachedPath(core::PathManager::FolderTypeKeys::Script, QFileInfo(pythonScriptPath).absoluteDir().absolutePath().toStdString()); - } + + scriptTextEdit_->updateText(getPythonFileContent(pythonScriptPath)); + } }); - argumentsEdit_ = new QComboBox(this); - argumentsEdit_->setEditable(true); - scriptSettingsLayout_->addWidget(new QLabel{"Command Line Arguments", this}, 1, 0); - scriptSettingsLayout_->addWidget(argumentsEdit_, 1, 1); + // Python script editor + scriptTextEdit_ = new PythonScriptEditor(); + QObject::connect(scriptTextEdit_, &QPlainTextEdit::textChanged, this, &RunScriptDialog::updateButtonStates); + scriptTextEdit_->setFont(QFont("RobotoRegular", 10)); + + scriptButtonBox_ = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help}; + scriptButtonBox_->button(QDialogButtonBox::Ok)->setText("Save"); + scriptButtonBox_->button(QDialogButtonBox::Cancel)->setText("Save As"); + scriptButtonBox_->button(QDialogButtonBox::Help)->setText("Run Script"); + connect(scriptButtonBox_, &QDialogButtonBox::accepted, this, [this]() { + saveScript(scriptPathEdit_->currentText()); + }); + connect(scriptButtonBox_, &QDialogButtonBox::rejected, this, &RunScriptDialog::saveScriptAs); + connect(scriptButtonBox_, &QDialogButtonBox::helpRequested, this, [this]() { + runScript(scriptTextEdit_->getExpression(), ScriptSource::Editor); + }); - buttonBox_ = new QDialogButtonBox{QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this}; - buttonBox_->button(QDialogButtonBox::Ok)->setText("Run Script"); - buttonBox_->button(QDialogButtonBox::Cancel)->setText("Clear Output"); - connect(buttonBox_, &QDialogButtonBox::accepted, this, &RunScriptDialog::runScript); - connect(buttonBox_, &QDialogButtonBox::rejected, [this]() { statusTextBlock_->clear(); }); + // Python console + pythonConsole_ = new PythonConsole(); + QObject::connect(pythonConsole_, &PythonConsole::runPythonScript, this, [this](const QString& script) { + runScript(script, ScriptSource::Console); + }); + pythonConsole_->setFont(QFont("RobotoRegular", 10)); + + clearConsoleButtonBox_ = new QDialogButtonBox{QDialogButtonBox::Ok}; + clearConsoleButtonBox_->button(QDialogButtonBox::Ok)->setText("Clear Console"); + connect(clearConsoleButtonBox_, &QDialogButtonBox::accepted, this, &RunScriptDialog::clearConsole); + + // Layouts + const auto scriptPathLayout = new QHBoxLayout(); + scriptPathLayout->addWidget(pathLabel); + scriptPathLayout->addWidget(scriptPathEdit_); + scriptPathLayout->addWidget(scriptPathURIButton_); + + const auto scriptLayout = new QVBoxLayout(); + scriptLayout->addLayout(scriptPathLayout); + scriptLayout->addWidget(scriptTextEdit_); + scriptLayout->addWidget(scriptButtonBox_); + + const auto consoleLayout = new QVBoxLayout(); + consoleLayout->addWidget(pythonConsole_); + consoleLayout->addWidget(clearConsoleButtonBox_); + + const auto verticalSplitter = new QSplitter(Qt::Vertical); + verticalSplitter->addWidget(new QWidget); + verticalSplitter->addWidget(new QWidget); + + verticalSplitter->widget(0)->setLayout(scriptLayout); + verticalSplitter->widget(1)->setLayout(consoleLayout); + + // This is only needed when the dialog is docked, probably it's a AdvancedDocking issue + QObject::connect(verticalSplitter, &QSplitter::splitterMoved, [this](int pos, int index) { + update(); + }); - statusTextBlock_ = new QPlainTextEdit(this); - statusTextBlock_->setReadOnly(true); - statusTextBlock_->setPlaceholderText("Python Script Outputs..."); + const auto mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(verticalSplitter); - layout_->addLayout(scriptSettingsLayout_, 0, 0); - layout_->addWidget(buttonBox_, 1, 0); - layout_->addWidget(statusTextBlock_, 2, 0); + // Python API connections + connect(this, &RunScriptDialog::runScriptRequested, [this](const QString& pythonScript, const ScriptSource source) { + setScriptIsRunning(true); + repaint(); + const auto currentRunStatus = python_api::runPythonScript(pythonScript.toStdString()); + if (source == ScriptSource::Editor) { + addOutputFromScriptEditor(currentRunStatus.stdOutBuffer, currentRunStatus.stdErrBuffer); + } else { + addOutputFromConsole(currentRunStatus.stdOutBuffer, currentRunStatus.stdErrBuffer); + } + + setScriptIsRunning(false); + }); + + // Code highlighting + scriptEditorHighlighter_ = new PythonHighlighter(scriptTextEdit_->document()); + consoleHighlighter_ = new PythonHighlighter(pythonConsole_->document(), true); + + // Shortcuts (Alt+Enter / Alt+Return) + const auto enterShortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Enter), this); + connect(enterShortcut, &QShortcut::activated, this, [this]() { + runScript(scriptTextEdit_->getExpression(), ScriptSource::Editor); + }); + const auto returnShortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this); + connect(returnShortcut, &QShortcut::activated, this, [this]() { + runScript(scriptTextEdit_->getExpression(), ScriptSource::Editor); + }); + + // Updates setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Run Python Script"); updateComboBoxItems(); updateButtonStates(); } -void RunScriptDialog::addPythonOutput(const std::string& outBuffer, const std::string& errorBuffer) { - auto launchTime = QDateTime::currentDateTime(); - statusTextBlock_->appendHtml(QString("===== SCRIPT RUN AT %2 =====
").arg(style::Colors::color(style::Colormap::externalReference).name()).arg(launchTime.toString("hh:mm:ss.zzz"))); - - auto vbar = statusTextBlock_->verticalScrollBar(); - auto atBottom = vbar->value() == vbar->maximum(); - - QTextCursor tc(statusTextBlock_->document()); - tc.movePosition(QTextCursor::End); - tc.insertText(QString::fromStdString(outBuffer)); - - if (atBottom) { - vbar->setValue(vbar->maximum()); - } +void RunScriptDialog::addOutputFromScriptEditor(const std::string& outBuffer, const std::string& errorBuffer) const { + pythonConsole_->addOutputFromScriptEditor(QString::fromStdString(outBuffer), QString::fromStdString(errorBuffer)); +} - if (!errorBuffer.empty()) { - statusTextBlock_->appendHtml(QString("%2
").arg(style::Colors::color(style::Colormap::errorColorLight).name()).arg(QString::fromStdString(errorBuffer).toHtmlEscaped())); - } - statusTextBlock_->appendHtml(QString("===== SCRIPT RUN AT %2 FINISHED =====
").arg(style::Colors::color(style::Colormap::externalReference).name()).arg(launchTime.toString("hh:mm:ss.zzz"))); +void RunScriptDialog::addOutputFromConsole(const std::string& outBuffer, const std::string& errorBuffer) const { + pythonConsole_->addOutput(QString::fromStdString(outBuffer), QString::fromStdString(errorBuffer)); } -void RunScriptDialog::setScriptIsRunning(bool isRunning) { +void RunScriptDialog::setScriptIsRunning(bool isRunning) const { scriptPathEdit_->setDisabled(isRunning); - argumentsEdit_->setDisabled(isRunning); scriptPathURIButton_->setDisabled(isRunning); - buttonBox_->setDisabled(isRunning); + scriptButtonBox_->setDisabled(isRunning); +} + +void RunScriptDialog::updateButtonStates() const { + scriptTextEdit_->toPlainText().isEmpty() ? scriptButtonBox_->button(QDialogButtonBox::Ok)->setEnabled(false) : scriptButtonBox_->button(QDialogButtonBox::Ok)->setEnabled(true); + scriptTextEdit_->toPlainText().isEmpty() ? scriptButtonBox_->button(QDialogButtonBox::Cancel)->setEnabled(false) : scriptButtonBox_->button(QDialogButtonBox::Cancel)->setEnabled(true); +} + +void RunScriptDialog::saveScript(const QString& filePath) const { + if (!filePath.isEmpty()) { + QFile file(filePath); + + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&file); + out << scriptTextEdit_->getExpression(); + file.close(); + + scriptPathEdit_->setCurrentText(filePath); + } else { + QMessageBox::warning( + nullptr, + "File Save Error", + "Failed to open file for writing:\n" + file.errorString(), + QMessageBox::Ok); + } + } } -Q_SLOT void RunScriptDialog::updateButtonStates() { - auto path = scriptPathEdit_->currentText(); - auto fileInfo = QFileInfo(path); - if (scriptPathEdit_->currentText().isEmpty() || !fileInfo.exists() || !fileInfo.isReadable()) { - buttonBox_->button(QDialogButtonBox::Ok)->setEnabled(false); - return; +void RunScriptDialog::saveScriptAs() const { + auto pythonPath = scriptPathEdit_->currentText(); + if (pythonPath.isEmpty()) { + const auto cachedScriptPath = core::PathManager::getCachedPath(core::PathManager::FolderTypeKeys::Script, pythonPath.toStdString()); + pythonPath = QString::fromStdString(cachedScriptPath.string()); } - buttonBox_->button(QDialogButtonBox::Ok)->setEnabled(true); + const auto filePath = QFileDialog::getSaveFileName( + nullptr, + "Save As...", + pythonPath, + "Python Files (*.py);;All Files (*)"); + + saveScript(filePath); } -void RunScriptDialog::runScript() { - auto scriptPath = scriptPathEdit_->currentText(); - auto commandLineArgumentString = argumentsEdit_->currentText(); - auto commandLineArguments = commandLineArgumentString.split(' ', Qt::SkipEmptyParts); +void RunScriptDialog::clearConsole() const { + pythonConsole_->clearConsole(); +} + +void RunScriptDialog::runScript(const QString& script, const ScriptSource source) { + const auto scriptPath = scriptPathEdit_->currentText(); scriptEntries_[scriptPath] = QDateTime::currentMSecsSinceEpoch(); - if (!commandLineArguments.isEmpty()) { - commandLineParamEntries_[commandLineArgumentString] = QDateTime::currentMSecsSinceEpoch(); - } updateComboBoxItems(); - Q_EMIT pythonScriptRunRequested(scriptPath, commandLineArguments); + Q_EMIT runScriptRequested(script, source); } -void RunScriptDialog::updateComboBoxItems() { +void RunScriptDialog::updateComboBoxItems() const { auto updateItems = [](QComboBox* comboBox, auto& map) { comboBox->clear(); @@ -154,15 +235,19 @@ void RunScriptDialog::updateComboBoxItems() { comboBox->addItem(string); } }; +} - auto resetCommandLineParams = argumentsEdit_->currentText().isEmpty(); - - updateItems(scriptPathEdit_, scriptEntries_); - updateItems(argumentsEdit_, commandLineParamEntries_); +QString RunScriptDialog::getPythonFileContent(const QString& filePath) const { + QFile file(filePath); - if (resetCommandLineParams) { - argumentsEdit_->setCurrentText(""); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return {}; } + + QTextStream textStream(&file); + QString fileContents = textStream.readAll(); + + return fileContents; } } // namespace raco::common_widgets diff --git a/gui/libCommonWidgets/tests/CMakeLists.txt b/gui/libCommonWidgets/tests/CMakeLists.txt index 9e1f6c7e..80d30653 100644 --- a/gui/libCommonWidgets/tests/CMakeLists.txt +++ b/gui/libCommonWidgets/tests/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_LIBRARIES raco::ApplicationLib raco::RamsesBase raco::Testing + raco::PythonAPI ) raco_package_add_gui_test( @@ -24,3 +25,6 @@ raco_package_add_gui_test( "${TEST_LIBRARIES}" ${CMAKE_CURRENT_BINARY_DIR} ) + +deploy_python_dlls(libCommonWidgets_test) +deploy_python_folder(libCommonWidgets_test) diff --git a/gui/libCommonWidgets/tests/ErrorView_test.h b/gui/libCommonWidgets/tests/ErrorView_test.h index 08eb7414..31e525d9 100644 --- a/gui/libCommonWidgets/tests/ErrorView_test.h +++ b/gui/libCommonWidgets/tests/ErrorView_test.h @@ -15,11 +15,9 @@ #include -class ErrorViewTest : public TestEnvironmentCore { +class ErrorViewTest : public TestEnvironmentCoreT<::testing::Test, QApplication> { protected: - int argc{0}; - QApplication fakeApp_{argc, nullptr}; components::SDataChangeDispatcher dataChangeDispatcher_{std::make_shared()}; common_widgets::ErrorView errorView_{&commandInterface, dataChangeDispatcher_, true, nullptr}; }; diff --git a/gui/libGUIPythonAPI/tests/GUIPythonAPI_test.cpp b/gui/libGUIPythonAPI/tests/GUIPythonAPI_test.cpp index cfbeea6a..f476ac67 100644 --- a/gui/libGUIPythonAPI/tests/GUIPythonAPI_test.cpp +++ b/gui/libGUIPythonAPI/tests/GUIPythonAPI_test.cpp @@ -8,12 +8,6 @@ * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#if defined(WIN32) && defined(_DEBUG) && defined(PYTHON_DEBUG_LIBRARY_AVAILABLE) -// Needed to avoid pybind11/embed.h to cause linking to the non-debug DLL if the debug DLL is available. -// See https://github.com/pybind/pybind11/issues/3403#issuecomment-962878324 -#define Py_DEBUG -#endif - #include #include @@ -41,8 +35,9 @@ class GUIPythonTest : public RaCoApplicationTest { python_api::preparePythonEnvironment(QCoreApplication::applicationFilePath().toStdWString(), {}, true); pyGuard = std::make_unique(); - python_api::setup(&application); - raco::gui_python_api::setupObjectTree(objectTreeDockManager); + python_api::setApp(&application); + python_api::importRaCoModule(); + gui_python_api::setupObjectTree(objectTreeDockManager); } object_tree::model::ObjectTreeViewDefaultModel* objectTreeViewModel; @@ -92,7 +87,7 @@ TEST_F(GUIPythonTest, get_selection_single_selection) { createNode("node1"); auto node2Id = createNode("node2"); createNode("node3"); - objectTreeDock->getActiveTreeView()->selectObject(QString::fromStdString(node2Id)); + objectTreeDock->getActiveTreeView()->selectObject(QString::fromStdString(node2Id), false); py::exec(R"( import unittest diff --git a/gui/libObjectTree/CMakeLists.txt b/gui/libObjectTree/CMakeLists.txt index 492df031..f5904694 100644 --- a/gui/libObjectTree/CMakeLists.txt +++ b/gui/libObjectTree/CMakeLists.txt @@ -21,7 +21,9 @@ add_library(libObjectTree include/object_tree_view_model/ObjectTreeViewDefaultModel.h src/object_tree_view_model/ObjectTreeViewDefaultModel.cpp include/object_tree_view_model/ObjectTreeViewExternalProjectModel.h src/object_tree_view_model/ObjectTreeViewExternalProjectModel.cpp include/object_tree_view_model/ObjectTreeViewPrefabModel.h src/object_tree_view_model/ObjectTreeViewPrefabModel.cpp + include/object_tree_view_model/ObjectTreeViewRenderViewModel.h src/object_tree_view_model/ObjectTreeViewRenderViewModel.cpp include/object_tree_view_model/ObjectTreeViewResourceModel.h + include/object_tree_view_model/ObjectTreeViewSceneGraphModel.h src/object_tree_view_model/ObjectTreeViewSceneGraphModel.cpp include/object_tree_view_model/ObjectTreeViewSortProxyModels.h src/object_tree_view_model/ObjectTreeViewSortProxyModels.cpp src/object_tree_view_model/ObjectTreeViewResourceModel.cpp include/object_creator/ObjectCreator.h src/object_creator/ObjectCreator.cpp diff --git a/gui/libObjectTree/include/object_tree_view/ObjectTreeDock.h b/gui/libObjectTree/include/object_tree_view/ObjectTreeDock.h index 201677bc..14f2b918 100644 --- a/gui/libObjectTree/include/object_tree_view/ObjectTreeDock.h +++ b/gui/libObjectTree/include/object_tree_view/ObjectTreeDock.h @@ -36,10 +36,8 @@ public Q_SLOTS: void resetSelection(); Q_SIGNALS: - void externalObjectSelected(ObjectTreeDock *srcDock); - void newObjectTreeItemsSelected(const core::SEditorObjectSet &objects, ObjectTreeDock *srcDock, const QString &property); - void dockClosed(ObjectTreeDock *closedDock); - void dockSelectionFocusRequested(ObjectTreeDock *focusDock); + void newObjectTreeItemsSelected(const core::SEditorObjectSet &objects); + void dockClosed(); private: void filterTreeViewObjects(); diff --git a/gui/libObjectTree/include/object_tree_view/ObjectTreeDockManager.h b/gui/libObjectTree/include/object_tree_view/ObjectTreeDockManager.h index c0ba707e..47ac7618 100644 --- a/gui/libObjectTree/include/object_tree_view/ObjectTreeDockManager.h +++ b/gui/libObjectTree/include/object_tree_view/ObjectTreeDockManager.h @@ -35,19 +35,19 @@ class ObjectTreeDockManager : public QObject { Q_SIGNALS: void treeDockListChanged(); void newObjectTreeItemsSelected(const core::SEditorObjectSet& objects, const QString& property); - void selectionCleared(); public Q_SLOTS: void eraseTreeDock(ObjectTreeDock* dockToErase); void setFocusedDock(ObjectTreeDock* dockToFocus); - void selectObjectAcrossAllTreeDocks(const QString& objectID); - void selectObjectAndPropertyAcrossAllTreeDocks(const QString& objectID, const QString& objectProperty); + void selectObjectAndPropertyAcrossAllTreeDocks(core::SEditorObject object, const QString& propertyPath); private: + bool isExternalProjectDock(ObjectTreeDock* dock) const; + void connectTreeDockSignals(ObjectTreeDock* dock); + std::vector docks_; ObjectTreeDock* focusedDock_{nullptr}; - void connectTreeDockSignals(ObjectTreeDock* dock); }; } // namespace raco::object_tree::view diff --git a/gui/libObjectTree/include/object_tree_view/ObjectTreeView.h b/gui/libObjectTree/include/object_tree_view/ObjectTreeView.h index d4c06c7b..ab883758 100644 --- a/gui/libObjectTree/include/object_tree_view/ObjectTreeView.h +++ b/gui/libObjectTree/include/object_tree_view/ObjectTreeView.h @@ -41,6 +41,7 @@ class ObjectTreeView : public QTreeView { void requestNewNode(const std::string &nodeType, const std::string &nodeName, const QModelIndex &parent); void showContextMenu(const QPoint &p); bool canCopyAtIndices(const QModelIndexList &indices); + bool canCutIndices(const QModelIndexList &indices); bool canPasteIntoIndex(const QModelIndex &index, bool asExtref); bool canProgrammaticallyGoToObject(); bool containsObject(const QString &objectID) const; @@ -53,11 +54,11 @@ class ObjectTreeView : public QTreeView { QModelIndex getSelectedInsertionTargetIndex() const; void collapseRecusively(const QModelIndex &index); + object_tree::model::ObjectTreeViewDefaultModel *treeModel() const; + Q_SIGNALS: - void dockSelectionFocusRequested(ObjectTreeView *focusTree); void newNodeRequested(EditorObject::TypeDescriptor nodeType, const std::string &nodeName, const QModelIndex &parent); - void newObjectTreeItemsSelected(const core::SEditorObjectSet &objects, const QString &property); - void externalObjectSelected(); + void newObjectTreeItemsSelected(const core::SEditorObjectSet &objects); public Q_SLOTS: void resetSelection(); @@ -73,8 +74,7 @@ public Q_SLOTS: void hideNodes(); void showAllNodes(); - void selectObject(const QString &objectID); - void setPropertyToSelect(const QString &property); + void selectObject(const QString &objectID, bool blockSignals = true); void expandAllParentsOfObject(const QString &objectID); void expanded(const QModelIndex &index); void collapsed(const QModelIndex &index); @@ -87,7 +87,6 @@ public Q_SLOTS: QString viewTitle_; std::unordered_set expandedItemIDs_; std::unordered_set selectedItemIDs_; - QString property_; virtual QMenu* createCustomContextMenu(const QPoint &p); @@ -97,9 +96,12 @@ public Q_SLOTS: std::vector indicesToSEditorObjects(const QModelIndexList &index) const; std::string indexToTreeNodeID(const QModelIndex &index) const; QModelIndex indexFromTreeNodeID(const std::string &id) const; + void iterateThroughTree(QAbstractItemModel *model, std::function nodeFunc, QModelIndex currentIndex); protected Q_SLOTS: + void saveItemExpansionStates(); void restoreItemExpansionStates(); + void saveItemSelectionStates(); void restoreItemSelectionStates(); void expandAllParentsOfObject(const QModelIndex &index); }; diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeNode.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeNode.h index bcf474a1..a714bb50 100644 --- a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeNode.h +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeNode.h @@ -11,6 +11,8 @@ #include "core/EditorObject.h" +#include + namespace raco::object_tree::model { enum class ObjectTreeNodeType { @@ -18,7 +20,8 @@ enum class ObjectTreeNodeType { ExternalProject, ExtRefGroup, TypeParent, - Root + Root, + Tag }; enum class VisibilityState { @@ -33,7 +36,8 @@ class ObjectTreeNode { explicit ObjectTreeNode(core::SEditorObject obj, ObjectTreeNode *parent); explicit ObjectTreeNode(ObjectTreeNodeType type, ObjectTreeNode *parent); explicit ObjectTreeNode(const std::string& typeName); - + explicit ObjectTreeNode(ObjectTreeNodeType type, const std::string &typeName, ObjectTreeNode *parent); + ~ObjectTreeNode(); ObjectTreeNode *getParent(); @@ -59,7 +63,14 @@ class ObjectTreeNode { VisibilityState getPreviewVisibility() const; VisibilityState getAbstractViewVisibility() const; - void setBelongsToExternalProject(const std::string &path, const std::string &name); + void setExternalProjectInfo(const std::string &path, const std::string &name); + + std::string getInputBuffers() const; + std::string getOutputBuffers() const; + std::optional getRenderOrder() const; + + void setBuffers(const std::string &inputBuffers, const std::string &outputBuffers); + void setRenderOrder(int order); protected: ObjectTreeNode *parent_; @@ -69,5 +80,8 @@ class ObjectTreeNode { std::string typeName_ = ""; std::vector children_; core::SEditorObject representedObject_; + std::string inputBuffers_; + std::string outputBuffers_; + std::optional renderOrder_; }; } \ No newline at end of file diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewDefaultModel.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewDefaultModel.h index d33c7937..556785c9 100644 --- a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewDefaultModel.h +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewDefaultModel.h @@ -32,6 +32,8 @@ Traversal through the entire tree is guaranteed by the iterateThroughTree() meth #include "core/ExtrefOperations.h" +#include "user_types/RenderLayer.h" + #include #include @@ -52,6 +54,9 @@ class ObjectTreeViewDefaultModel : public QAbstractItemModel { // invisible column used for tag based filtering COLUMNINDEX_USERTAGS, COLUMNINDEX_PROJECT, + COLUMNINDEX_RENDER_ORDER, + COLUMNINDEX_INPUT_BUFFERS, + COLUMNINDEX_OUTPUT_BUFFERS, COLUMNINDEX_COLUMN_COUNT }; @@ -109,12 +114,17 @@ class ObjectTreeViewDefaultModel : public QAbstractItemModel { virtual bool canDeleteUnusedResources() const; virtual bool canProgramaticallyGotoObject() const; + bool canConvertAnimationChannels(const QModelIndexList& indices) const; + virtual bool isObjectAllowedIntoIndex(const QModelIndex& index, const core::SEditorObject& obj) const; virtual std::vector typesAllowedIntoIndex(const QModelIndex& index) const; virtual std::vector creatableTypes(const QModelIndex& index) const; + virtual std::vector hiddenColumns() const; + virtual ColumnIndex defaultSortColumn() const; + Q_SIGNALS: void repaintRequested(); void meshImportFailed(const std::string &filePath, const std::string &error); @@ -131,12 +141,17 @@ public Q_SLOTS: void moveScenegraphChildren(const std::vector& objects, core::SEditorObject parent, int row = -1); void importMeshScenegraph(const QString& filePath, const QModelIndex& selectedIndex); void deleteUnusedResources(); + void convertToAnimationChannelRaco(const QModelIndexList& indices); + void isolateNodes(const QModelIndexList& indices); void hideNodes(const QModelIndexList& indices); void showAllNodes(); protected: + void insertObject(const QModelIndex& parentIndex, core::SEditorObject object); + + components::SDataChangeDispatcher dispatcher_; std::unique_ptr invisibleRootNode_; QModelIndex invisibleRootIndex_; @@ -154,7 +169,7 @@ public Q_SLOTS: components::Subscription lifeCycleSubscription_; components::Subscription afterDispatchSubscription_; components::Subscription extProjectChangedSubscription_; - + bool groupExternalReferences_; bool groupByType_; @@ -189,8 +204,12 @@ public Q_SLOTS: {"Prefab", style::Icons::instance().typePrefabInternal}, {"ExtrefPrefab", style::Icons::instance().typePrefabExternal}, {"PrefabInstance", style::Icons::instance().typePrefabInstance}, + {"RenderLayer", style::Icons::instance().typeRenderLayer}, + {"RenderTarget", style::Icons::instance().typeRenderTarget}, + {"RenderTargetMS", style::Icons::instance().typeRenderTarget}, {"LuaScriptModule", style::Icons::instance().typeLuaScriptModule}, {"AnimationChannel", style::Icons::instance().typeAnimationChannel}, + {"AnimationChannelRaco", style::Icons::instance().typeAnimationChannel}, {"Animation", style::Icons::instance().typeAnimation}, {"Timer", style::Icons::instance().typeTimer}, {"AnchorPoint", style::Icons::instance().typeAnchorPoint}, diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewExternalProjectModel.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewExternalProjectModel.h index 5723d9ed..cf6e0bd7 100644 --- a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewExternalProjectModel.h +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewExternalProjectModel.h @@ -36,6 +36,8 @@ class ObjectTreeViewExternalProjectModel : public ObjectTreeViewDefaultModel { bool isObjectAllowedIntoIndex(const QModelIndex& index, const core::SEditorObject& obj) const override; bool canPasteIntoIndex(const QModelIndex& index, const std::vector& objects, const std::set& sourceProjectTopLevelObjectIds, bool asExtRef = false) const override; + std::vector hiddenColumns() const override; + public Q_SLOTS: size_t deleteObjectsAtIndices(const QModelIndexList& index) override; void copyObjectsAtIndices(const QModelIndexList& indices, bool deepCopy) override; diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewPrefabModel.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewPrefabModel.h index 96a0265c..e2087618 100644 --- a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewPrefabModel.h +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewPrefabModel.h @@ -18,9 +18,11 @@ class ObjectTreeViewPrefabModel : public ObjectTreeViewDefaultModel { Q_OBJECT public: - ObjectTreeViewPrefabModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore, const std::vector& allowedCreatableUserTypes = {}); + ObjectTreeViewPrefabModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore); QVariant data(const QModelIndex& index, int role) const override; + + std::vector hiddenColumns() const override; }; } // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewRenderViewModel.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewRenderViewModel.h new file mode 100644 index 00000000..340468f6 --- /dev/null +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewRenderViewModel.h @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "ObjectTreeViewDefaultModel.h" + +namespace raco::object_tree::model { + +class ObjectTreeViewRenderViewModel : public ObjectTreeViewDefaultModel { + Q_OBJECT + +public: + ObjectTreeViewRenderViewModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore); + + std::vector hiddenColumns() const override; + virtual ColumnIndex defaultSortColumn() const; + +protected: + Qt::ItemFlags flags(const QModelIndex& index) const override; + + std::vector creatableTypes(const QModelIndex& index) const override; + bool canProgramaticallyGotoObject() const override; +private: + void buildObjectTree() override; + + std::vector buildTaggedNodeSubtree(const std::vector& objects, const std::set& tags, bool parentActive, const std::set& materialFilterTags, bool materialFilterExclusive, const std::map& renderBufferRefs, core::SEditorObjectSet& inputBuffers); + + void buildRenderLayerSubtree(ObjectTreeNode* layerNode, core::SEditorObject layer, const std::map& renderBufferRefs, const std::vector& topLevelNodes, const std::vector& renderLayers, core::SEditorObjectSet& inputBuffers); + void buildRenderPassSubtree(ObjectTreeNode* layerNode, core::SEditorObject layer, const std::map& renderBufferRefs, const std::vector& topLevelNodes, const std::vector& renderLayers); + void buildRenderPasses(ObjectTreeNode* rootNode, const std::vector& children); + + void updateSubscriptions(); + + std::vector subscriptions_; +}; + +} // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewResourceModel.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewResourceModel.h index eea8f3c2..bc0264ed 100644 --- a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewResourceModel.h +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewResourceModel.h @@ -20,12 +20,15 @@ class ObjectTreeViewResourceModel : public ObjectTreeViewDefaultModel { public: - ObjectTreeViewResourceModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectStore, const std::vector& allowedCreatableUserTypes = {}); - + ObjectTreeViewResourceModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectStore); + bool pasteObjectAtIndex(const QModelIndex& index, bool pasteAsExtref, std::string* outError, const std::string& serializedObjects = RaCoClipboard::get()) override; std::vector typesAllowedIntoIndex(const QModelIndex& index) const override; bool isObjectAllowedIntoIndex(const QModelIndex& index, const core::SEditorObject& obj) const override; + + std::vector hiddenColumns() const override; + virtual ColumnIndex defaultSortColumn() const; }; } // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewSceneGraphModel.h b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewSceneGraphModel.h new file mode 100644 index 00000000..f1a6115b --- /dev/null +++ b/gui/libObjectTree/include/object_tree_view_model/ObjectTreeViewSceneGraphModel.h @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "ObjectTreeViewDefaultModel.h" + +namespace raco::object_tree::model { + +class ObjectTreeViewSceneGraphModel : public ObjectTreeViewDefaultModel { + Q_OBJECT + +public: + ObjectTreeViewSceneGraphModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore); +}; + +} // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/src/object_tree_view/ObjectTreeDock.cpp b/gui/libObjectTree/src/object_tree_view/ObjectTreeDock.cpp index 2d349f6a..1da7bb50 100644 --- a/gui/libObjectTree/src/object_tree_view/ObjectTreeDock.cpp +++ b/gui/libObjectTree/src/object_tree_view/ObjectTreeDock.cpp @@ -65,7 +65,7 @@ ObjectTreeDock::ObjectTreeDock(const char *dockTitle, QWidget *parent) } ObjectTreeDock::~ObjectTreeDock() { - Q_EMIT dockClosed(this); + Q_EMIT dockClosed(); } void ObjectTreeDock::setTreeView(ObjectTreeView *treeView) { @@ -74,15 +74,7 @@ void ObjectTreeDock::setTreeView(ObjectTreeView *treeView) { filterLineEdit_->setVisible(treeView->hasProxyModel()); filterByComboBox_->setVisible(treeView->hasProxyModel()); - connect(treeView, &ObjectTreeView::newObjectTreeItemsSelected, [this](const auto &objects, const auto &property) { - Q_EMIT newObjectTreeItemsSelected(objects, this, property); - }); - connect(treeView, &ObjectTreeView::externalObjectSelected, [this]() { - Q_EMIT externalObjectSelected(this); - }); - connect(treeView, &ObjectTreeView::dockSelectionFocusRequested, [this]() { - Q_EMIT dockSelectionFocusRequested(this); - }); + connect(treeView, &ObjectTreeView::newObjectTreeItemsSelected, this, &ObjectTreeDock::newObjectTreeItemsSelected); treeViewStack_->removeWidget(treeViewStack_->currentWidget()); treeViewStack_->addWidget(treeView); diff --git a/gui/libObjectTree/src/object_tree_view/ObjectTreeDockManager.cpp b/gui/libObjectTree/src/object_tree_view/ObjectTreeDockManager.cpp index 2fb282dd..5e6a18ac 100644 --- a/gui/libObjectTree/src/object_tree_view/ObjectTreeDockManager.cpp +++ b/gui/libObjectTree/src/object_tree_view/ObjectTreeDockManager.cpp @@ -10,6 +10,8 @@ #include "object_tree_view/ObjectTreeDock.h" #include "object_tree_view/ObjectTreeDockManager.h" +#include "object_tree_view_model/ObjectTreeViewExternalProjectModel.h" + namespace raco::object_tree::view { void ObjectTreeDockManager::addTreeDock(ObjectTreeDock* newDock) { @@ -29,7 +31,7 @@ void ObjectTreeDockManager::eraseTreeDock(ObjectTreeDock* dockToErase) { docks_.erase(dockPosition); if (focusedDock_ == dockToErase) { focusedDock_ = nullptr; - Q_EMIT selectionCleared(); + Q_EMIT newObjectTreeItemsSelected({}, {}); } Q_EMIT treeDockListChanged(); @@ -44,26 +46,21 @@ void ObjectTreeDockManager::setFocusedDock(ObjectTreeDock* dock) { focusedDock_ = dock; } -void ObjectTreeDockManager::selectObjectAcrossAllTreeDocks(const QString& objectID) { - selectObjectAndPropertyAcrossAllTreeDocks(objectID, {}); -} - -void ObjectTreeDockManager::selectObjectAndPropertyAcrossAllTreeDocks(const QString& objectID, const QString& objectProperty) { - // always favor the first created active tree view of any type (e.g. the first "Scene Graph", the first "Resources") - std::set viewTitles; - - for (const auto* dock : getDocks()) { +void ObjectTreeDockManager::selectObjectAndPropertyAcrossAllTreeDocks(core::SEditorObject object, const QString& propertyPath) { + ObjectTreeDock* focusDock = nullptr; + auto objectID = QString::fromStdString(object->objectID()); + for (auto* dock : getDocks()) { if (auto activeTreeView = dock->getActiveTreeView()) { - auto viewTitle = activeTreeView->getViewTitle(); - - if (activeTreeView->canProgrammaticallyGoToObject() && viewTitles.count(viewTitle) == 0) { - activeTreeView->setPropertyToSelect(objectProperty); + if (activeTreeView->canProgrammaticallyGoToObject() && dock->getActiveTreeView()->containsObject(objectID)) { activeTreeView->selectObject(objectID); activeTreeView->expandAllParentsOfObject(objectID); - viewTitles.insert(viewTitle); + focusDock = dock; + break; } } } + setFocusedDock(focusDock); + Q_EMIT newObjectTreeItemsSelected({object}, propertyPath); } size_t ObjectTreeDockManager::getTreeDockAmount() const { @@ -92,9 +89,13 @@ bool ObjectTreeDockManager::docksContainObject(const QString& objID) const { return false; } +bool ObjectTreeDockManager::isExternalProjectDock(ObjectTreeDock* dock) const { + return dynamic_cast(dock->getActiveTreeView()->treeModel()) != nullptr; +} + std::vector ObjectTreeDockManager::getSelection() const { auto activeDockWhichHasSelection = getActiveDockWithSelection(); - if (activeDockWhichHasSelection == nullptr || activeDockWhichHasSelection->windowTitle().toStdString() == "Project Browser") { + if (activeDockWhichHasSelection == nullptr || isExternalProjectDock(activeDockWhichHasSelection)) { return std::vector(); } @@ -102,23 +103,17 @@ std::vector ObjectTreeDockManager::getSelection() const { } void ObjectTreeDockManager::connectTreeDockSignals(ObjectTreeDock* dock) { - QObject::connect(dock, &ObjectTreeDock::externalObjectSelected, [this](auto* selectionSrcDock) { - // Keep the external dock focused while clearing selection to not show external objects in the Property Browser - setFocusedDock(selectionSrcDock); - Q_EMIT selectionCleared(); - }); - - QObject::connect(dock, &ObjectTreeDock::newObjectTreeItemsSelected, [this](auto& objects, auto* selectionSrcDock, auto& property) { - setFocusedDock(selectionSrcDock); - if (objects.empty()) { - Q_EMIT selectionCleared(); + QObject::connect(dock, &ObjectTreeDock::newObjectTreeItemsSelected, [this, dock](const core::SEditorObjectSet& objects) { + setFocusedDock(dock); + if (objects.empty() || isExternalProjectDock(dock)) { + Q_EMIT newObjectTreeItemsSelected({}, {}); } else { - Q_EMIT newObjectTreeItemsSelected(objects, property); + Q_EMIT newObjectTreeItemsSelected(objects, {}); } }); - QObject::connect(dock, &ObjectTreeDock::dockSelectionFocusRequested, this, &ObjectTreeDockManager::setFocusedDock); - - QObject::connect(dock, &ObjectTreeDock::dockClosed, this, &ObjectTreeDockManager::eraseTreeDock); + QObject::connect(dock, &ObjectTreeDock::dockClosed, this, [this, dock]() { + eraseTreeDock(dock); + }); } } // namespace raco::object_tree::view \ No newline at end of file diff --git a/gui/libObjectTree/src/object_tree_view/ObjectTreeView.cpp b/gui/libObjectTree/src/object_tree_view/ObjectTreeView.cpp index a29f475d..2ace5977 100644 --- a/gui/libObjectTree/src/object_tree_view/ObjectTreeView.cpp +++ b/gui/libObjectTree/src/object_tree_view/ObjectTreeView.cpp @@ -16,10 +16,12 @@ #include "core/PathManager.h" #include "core/Project.h" #include "user_types/Node.h" +#include "user_types/AnimationChannel.h" #include "object_tree_view_model/ObjectTreeViewDefaultModel.h" #include "object_tree_view_model/ObjectTreeViewExternalProjectModel.h" #include "object_tree_view_model/ObjectTreeViewPrefabModel.h" +#include "object_tree_view_model/ObjectTreeViewRenderViewModel.h" #include "object_tree_view_model/ObjectTreeViewResourceModel.h" #include "object_tree_view_model/ObjectTreeViewSortProxyModels.h" #include "utils/u8path.h" @@ -51,8 +53,9 @@ ObjectTreeView::ObjectTreeView(const QString &viewTitle, ObjectTreeViewDefaultMo if (proxyModel_) { proxyModel_->setSourceModel(treeModel_); - + setSortingEnabled(proxyModel_->sortingEnabled()); + sortByColumn(treeModel_->defaultSortColumn(), Qt::AscendingOrder); QTreeView::setModel(proxyModel_); } else { QTreeView::setModel(treeModel_); @@ -60,39 +63,31 @@ ObjectTreeView::ObjectTreeView(const QString &viewTitle, ObjectTreeViewDefaultMo setTextElideMode(treeModel_->textElideMode()); - // hidden column for data only used for filtering, enable to reveal object IDs - setColumnHidden(ObjectTreeViewDefaultModel::COLUMNINDEX_ID, true); - setColumnHidden(ObjectTreeViewDefaultModel::COLUMNINDEX_USERTAGS, true); connect(this, &QTreeView::customContextMenuRequested, this, &ObjectTreeView::showContextMenu); connect(this, &QTreeView::expanded, this, &ObjectTreeView::expanded); connect(this, &QTreeView::collapsed, this, &ObjectTreeView::collapsed); connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, [this](const auto &selectedItemList, const auto &deselectedItemList) { - if (auto externalProjectModel = (dynamic_cast(treeModel_))) { - Q_EMIT externalObjectSelected(); - return; - } - - auto selectedObjects = indicesToSEditorObjects(selectedItemList.indexes()); - for (const auto &selObj : selectedObjects) { - selectedItemIDs_.emplace(selObj->objectID()); - } - - auto deselectedObjects = indicesToSEditorObjects(deselectedItemList.indexes()); - for (const auto &deselObj : deselectedObjects) { - selectedItemIDs_.erase(deselObj->objectID()); - } - - Q_EMIT newObjectTreeItemsSelected(getSelectedObjects(), property_); - property_.clear(); + Q_EMIT newObjectTreeItemsSelected(getSelectedObjects()); }); + connect(treeModel_, &ObjectTreeViewDefaultModel::modelAboutToBeReset, this, &ObjectTreeView::saveItemExpansionStates); connect(treeModel_, &ObjectTreeViewDefaultModel::modelReset, this, &ObjectTreeView::restoreItemExpansionStates); + connect(treeModel_, &ObjectTreeViewDefaultModel::modelAboutToBeReset, this, &ObjectTreeView::saveItemSelectionStates); connect(treeModel_, &ObjectTreeViewDefaultModel::modelReset, this, &ObjectTreeView::restoreItemSelectionStates); + resizeColumnToContents(ObjectTreeViewDefaultModel::COLUMNINDEX_PREVIEW_VISIBILITY); + resizeColumnToContents(ObjectTreeViewDefaultModel::COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY); setColumnWidth(ObjectTreeViewDefaultModel::COLUMNINDEX_NAME, width() / 3); + // hidden column for data only used for filtering, enable to reveal object IDs + setColumnHidden(ObjectTreeViewDefaultModel::COLUMNINDEX_ID, true); + setColumnHidden(ObjectTreeViewDefaultModel::COLUMNINDEX_USERTAGS, true); + for (auto column : treeModel_->hiddenColumns()) { + setColumnHidden(column, true); + } + auto copyShortcut = new QShortcut(QKeySequence::Copy, this, nullptr, nullptr, Qt::WidgetShortcut); QObject::connect(copyShortcut, &QShortcut::activated, this, &ObjectTreeView::copyObjects); @@ -207,14 +202,14 @@ void ObjectTreeView::pasteObjects(const QModelIndex &index, bool asExtRef) { void ObjectTreeView::cutObjects() { auto selectedIndices = getSelectedIndices(true); - if (!selectedIndices.isEmpty()) { + if (!selectedIndices.isEmpty() && canCutIndices(selectedIndices)) { treeModel_->cutObjectsAtIndices(selectedIndices, false); } } void ObjectTreeView::deleteObjects() { auto selectedIndices = getSelectedIndices(); - if (!selectedIndices.empty()) { + if (!selectedIndices.empty() && treeModel_->canDeleteAtIndices(selectedIndices)) { auto delObjAmount = treeModel_->deleteObjectsAtIndices(selectedIndices); if (delObjAmount > 0) { @@ -256,22 +251,19 @@ void ObjectTreeView::showAllNodes() { treeModel_->showAllNodes(); } -void ObjectTreeView::selectObject(const QString &objectID) { +void ObjectTreeView::selectObject(const QString &objectID, bool blockSignals) { + selectionModel()->blockSignals(blockSignals); if (objectID.isEmpty()) { resetSelection(); - return; - } - - auto objectIndex = indexFromTreeNodeID(objectID.toStdString()); - if (objectIndex.isValid()) { - resetSelection(); - selectionModel()->select(objectIndex, SELECTION_MODE); - scrollTo(objectIndex); + } else { + auto objectIndex = indexFromTreeNodeID(objectID.toStdString()); + if (objectIndex.isValid()) { + resetSelection(); + selectionModel()->select(objectIndex, SELECTION_MODE); + scrollTo(objectIndex); + } } -} - -void ObjectTreeView::setPropertyToSelect(const QString &property) { - property_ = property; + selectionModel()->blockSignals(false); } void ObjectTreeView::expandAllParentsOfObject(const QString &objectID) { @@ -282,16 +274,12 @@ void ObjectTreeView::expandAllParentsOfObject(const QString &objectID) { } void ObjectTreeView::expanded(const QModelIndex &index) { - expandedItemIDs_.insert(indexToTreeNodeID(index)); - if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier)) { expandRecursively(index); } } void ObjectTreeView::collapsed(const QModelIndex &index) { - expandedItemIDs_.erase(indexToTreeNodeID(index)); - if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier)) { collapseRecusively(index); } @@ -305,27 +293,34 @@ void ObjectTreeView::collapseRecusively(const QModelIndex& index) { } } +object_tree::model::ObjectTreeViewDefaultModel *ObjectTreeView::treeModel() const { + return treeModel_; +} + QString ObjectTreeView::getViewTitle() const { return viewTitle_; } void ObjectTreeView::requestNewNode(const std::string& nodeType, const std::string &nodeName, const QModelIndex &parent) { - Q_EMIT dockSelectionFocusRequested(this); - - selectedItemIDs_.clear(); auto createdObject = treeModel_->createNewObject(nodeType, nodeName, parent); - selectedItemIDs_.insert(createdObject->objectID()); + selectObject(QString::fromStdString(createdObject->objectID()), false); } void ObjectTreeView::showContextMenu(const QPoint &p) { auto *treeViewMenu = createCustomContextMenu(p); - treeViewMenu->exec(viewport()->mapToGlobal(p)); + if (treeViewMenu) { + treeViewMenu->exec(viewport()->mapToGlobal(p)); + } } bool ObjectTreeView::canCopyAtIndices(const QModelIndexList &parentIndices) { return treeModel_->canCopyAtIndices(parentIndices); } +bool ObjectTreeView::canCutIndices(const QModelIndexList &indices) { + return treeModel_->canCopyAtIndices(indices) && treeModel_->canDeleteAtIndices(indices); +} + bool ObjectTreeView::canPasteIntoIndex(const QModelIndex &index, bool asExtref) { if (!RaCoClipboard::hasEditorObject()) { return false; @@ -378,11 +373,14 @@ bool ObjectTreeView::hasProxyModel() const { void ObjectTreeView::resetSelection() { selectionModel()->reset(); - selectedItemIDs_.clear(); viewport()->update(); } QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { + if (dynamic_cast(treeModel_)) { + return nullptr; + } + auto treeViewMenu = new QMenu(this); auto selectedItemIndices = getSelectedIndices(true); @@ -390,6 +388,7 @@ QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { bool canDeleteSelectedIndices = treeModel_->canDeleteAtIndices(selectedItemIndices); bool canCopySelectedIndices = treeModel_->canCopyAtIndices(selectedItemIndices); + bool canCutSelectedIndices = canCutIndices(selectedItemIndices); auto externalProjectModel = (dynamic_cast(treeModel_)); auto prefabModel = (dynamic_cast(treeModel_)); @@ -397,6 +396,7 @@ QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { bool isScenegraphView = !(prefabModel || resourceModel || externalProjectModel); bool canInsertMeshAsset = false; bool haveCreatableTypes = false; + bool canConvAnimChannel = false; for (auto const& typeName : treeModel_->creatableTypes(insertionTargetIndex)) { auto actionCreate = treeViewMenu->addAction(QString::fromStdString("Create " + typeName), [this, typeName, insertionTargetIndex]() { @@ -406,6 +406,9 @@ QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { if (typeName == user_types::Node::typeDescription.typeName) { canInsertMeshAsset = true; } + if (typeName == user_types::AnimationChannel::typeDescription.typeName) { + canConvAnimChannel = true; + } } if (canInsertMeshAsset) { @@ -421,6 +424,15 @@ QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { actionImport->setEnabled(canInsertMeshAsset); } + if (canConvAnimChannel) { + treeViewMenu->addSeparator(); + auto actionConvert = treeViewMenu->addAction( + "Convert AnimationChannel to AnimationChannelRaco", [this, selectedItemIndices] { + treeModel_->convertToAnimationChannelRaco(selectedItemIndices); + }); + actionConvert->setEnabled(treeModel_->canConvertAnimationChannels(selectedItemIndices)); + } + if (!externalProjectModel || haveCreatableTypes) { treeViewMenu->addSeparator(); } @@ -473,7 +485,7 @@ QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { "Cut", [this, selectedItemIndices]() { treeModel_->cutObjectsAtIndices(selectedItemIndices, false); }, QKeySequence::Cut); - actionCut->setEnabled(canDeleteSelectedIndices && canCopySelectedIndices); + actionCut->setEnabled(canCutSelectedIndices); treeViewMenu->addSeparator(); @@ -485,7 +497,7 @@ QMenu* ObjectTreeView::createCustomContextMenu(const QPoint &p) { auto actionCutDeep = treeViewMenu->addAction("Cut (Deep)", [this, selectedItemIndices]() { treeModel_->cutObjectsAtIndices(selectedItemIndices, true); }); - actionCutDeep->setEnabled(canDeleteSelectedIndices && canCopySelectedIndices); + actionCutDeep->setEnabled(canCutSelectedIndices); if (!externalProjectModel) { auto actionDeleteUnrefResources = treeViewMenu->addAction("Delete Unused Resources", [this] { treeModel_->deleteUnusedResources(); }); @@ -580,7 +592,7 @@ void ObjectTreeView::mousePressEvent(QMouseEvent *event) { QTreeView::mousePressEvent(event); if (!indexAt(event->pos()).isValid()) { resetSelection(); - Q_EMIT newObjectTreeItemsSelected({}, {}); + Q_EMIT newObjectTreeItemsSelected({}); } } @@ -656,6 +668,28 @@ QModelIndex ObjectTreeView::getSelectedInsertionTargetIndex() const { } } + +void ObjectTreeView::iterateThroughTree(QAbstractItemModel *model, std::function nodeFunc, QModelIndex currentIndex) { + if (currentIndex.row() != -1) { + nodeFunc(currentIndex); + } + for (int i = 0; i < model->rowCount(currentIndex); ++i) { + auto childIndex = model->index(i, 0, currentIndex); + iterateThroughTree(model, nodeFunc, childIndex); + } +} + +void ObjectTreeView::saveItemExpansionStates() { + expandedItemIDs_.clear(); + iterateThroughTree( + model(), [this](QModelIndex &index) { + if (isExpanded(index)) { + expandedItemIDs_.insert(indexToTreeNodeID(index)); + } + }, + QModelIndex()); +} + void ObjectTreeView::restoreItemExpansionStates() { for (const auto &expandedObjectID : expandedItemIDs_) { auto expandedObjectIndex = indexFromTreeNodeID(expandedObjectID); @@ -667,6 +701,13 @@ void ObjectTreeView::restoreItemExpansionStates() { } } +void ObjectTreeView::saveItemSelectionStates() { + selectedItemIDs_.clear(); + for (auto obj : indicesToSEditorObjects(selectionModel()->selectedIndexes())) { + selectedItemIDs_.insert(obj->objectID()); + } +} + void ObjectTreeView::restoreItemSelectionStates() { // This doesn't emit any signals: selectionModel()->reset(); diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeNode.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeNode.cpp index 9303b2ff..e1dcbfe5 100644 --- a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeNode.cpp +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeNode.cpp @@ -47,6 +47,16 @@ ObjectTreeNode::ObjectTreeNode(const std::string& typeName) typeName_{typeName} { } +ObjectTreeNode::ObjectTreeNode(ObjectTreeNodeType type, const std::string& typeName, ObjectTreeNode* parent) + : parent_(parent), + type_(type), + representedObject_{nullptr}, + typeName_(typeName) { + if (parent_) { + parent_->addChild(this); + } +} + ObjectTreeNode::~ObjectTreeNode() { for (auto child : children_) { delete child; @@ -119,6 +129,8 @@ std::string ObjectTreeNode::getDisplayName() const { } return typeName_ + "s"; + case ObjectTreeNodeType::Tag: + return typeName_; default: return ""; } @@ -170,12 +182,33 @@ VisibilityState ObjectTreeNode::getAbstractViewVisibility() const { return VisibilityState::Missing; } -void ObjectTreeNode::setBelongsToExternalProject(const std::string& path, const std::string& name) { +void ObjectTreeNode::setExternalProjectInfo(const std::string& path, const std::string& name) { assert(type_ == ObjectTreeNodeType::EditorObject || type_ == ObjectTreeNodeType::ExternalProject); externalProjectPath_ = path; externalProjectName_ = name; } +std::string ObjectTreeNode::getInputBuffers() const { + return inputBuffers_; +} + +std::string ObjectTreeNode::getOutputBuffers() const { + return outputBuffers_; +} + +std::optional ObjectTreeNode::getRenderOrder() const { + return renderOrder_; +} + +void ObjectTreeNode::setBuffers(const std::string& inputBuffers, const std::string& outputBuffers) { + inputBuffers_ = inputBuffers; + outputBuffers_ = outputBuffers; +} + +void ObjectTreeNode::setRenderOrder(int order) { + renderOrder_ = order; +} + std::string ObjectTreeNode::getID() const { switch (type_) { case ObjectTreeNodeType::EditorObject: diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewDefaultModel.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewDefaultModel.cpp index 8e2fcff9..a508fc98 100644 --- a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewDefaultModel.cpp +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewDefaultModel.cpp @@ -16,11 +16,17 @@ #include "core/ExternalReferenceAnnotation.h" #include "core/Project.h" #include "core/Queries.h" +#include "core/Queries_Tags.h" #include "object_tree_view_model/ObjectTreeNode.h" #include "components/Naming.h" #include "style/Colors.h" #include "user_types/UserObjectFactory.h" #include "object_creator/ObjectCreator.h" +#include "user_types/AnimationChannel.h" +#include "user_types/BlitPass.h" +#include "user_types/RenderPass.h" +#include "user_types/MeshNode.h" +#include "components/EditorObjectFormatter.h" #include #include @@ -94,6 +100,8 @@ QVariant ObjectTreeViewDefaultModel::getNodeIcon(ObjectTreeNode* treeNode) const std::string typeName; if (treeNode->getType() == ObjectTreeNodeType::TypeParent) { typeName = treeNode->getTypeName(); + } else if (treeNode->getType() == ObjectTreeNodeType::Tag) { + return QVariant(style::Icons::instance().label); } else { auto editorObj = treeNode->getRepresentedObject(); if (editorObj) { @@ -190,7 +198,19 @@ QVariant ObjectTreeViewDefaultModel::data(const QModelIndex& index, int role) co return QVariant(QString()); case COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY: return QVariant(QString()); + case COLUMNINDEX_INPUT_BUFFERS: + return QVariant(QString::fromStdString(treeNode->getInputBuffers())); + break; + case COLUMNINDEX_OUTPUT_BUFFERS: + return QVariant(QString::fromStdString(treeNode->getOutputBuffers())); + break; + case COLUMNINDEX_RENDER_ORDER: + if (treeNode->getRenderOrder().has_value()) { + return QVariant(treeNode->getRenderOrder().value()); + } + break; } + return QVariant(); } case Qt::EditRole: { return QVariant(QString::fromStdString(treeNode->getDisplayName())); @@ -214,6 +234,12 @@ QVariant ObjectTreeViewDefaultModel::headerData(int section, Qt::Orientation ori return QVariant("User Tags"); case COLUMNINDEX_PROJECT: return QVariant("Project Name"); + case COLUMNINDEX_INPUT_BUFFERS: + return QVariant("Input Buffers"); + case COLUMNINDEX_OUTPUT_BUFFERS: + return QVariant("Output Buffers"); + case COLUMNINDEX_RENDER_ORDER: + return QVariant("Render Order"); } } break; case Qt::DecorationRole: @@ -476,7 +502,7 @@ void ObjectTreeViewDefaultModel::buildObjectTree() { void ObjectTreeViewDefaultModel::setNodeExternalProjectInfo(ObjectTreeNode* node) const { if (auto obj = node->getRepresentedObject()) { if (auto extrefAnno = obj->query()) { - node->setBelongsToExternalProject( + node->setExternalProjectInfo( project()->lookupExternalProjectPath(*extrefAnno->projectID_), project()->lookupExternalProjectName(*extrefAnno->projectID_)); } @@ -520,6 +546,7 @@ void ObjectTreeViewDefaultModel::constructTreeUnderNode(ObjectTreeNode* rootNode auto* node = new ObjectTreeNode(obj, parentNode); setNodeExternalProjectInfo(node); + constructTreeUnderNode(node, obj->children_->asVector(), false, false); } } @@ -538,8 +565,27 @@ std::vector ObjectTreeViewDefaultModel::creatableTypes(const QModel return result; } -SEditorObject ObjectTreeViewDefaultModel::createNewObject(const std::string& typeName, const std::string& nodeName, const QModelIndex& parent) { - SEditorObject parentObj = indexToSEditorObject(parent); +std::vector ObjectTreeViewDefaultModel::hiddenColumns() const { + return {COLUMNINDEX_RENDER_ORDER, COLUMNINDEX_INPUT_BUFFERS, COLUMNINDEX_OUTPUT_BUFFERS}; +} + +ObjectTreeViewDefaultModel::ColumnIndex ObjectTreeViewDefaultModel::defaultSortColumn() const { + return COLUMNINDEX_TYPE; +} + +void ObjectTreeViewDefaultModel::insertObject(const QModelIndex& parentIndex, SEditorObject object) { + auto parentNode = indexToTreeNode(parentIndex); + + beginInsertRows(parentIndex, parentNode->childCount(), parentNode->childCount()); + + auto* node = new ObjectTreeNode(object, parentNode); + updateTreeIndexes(); + + endInsertRows(); +} + +SEditorObject ObjectTreeViewDefaultModel::createNewObject(const std::string& typeName, const std::string& nodeName, const QModelIndex& parentIndex) { + SEditorObject parentObj = indexToSEditorObject(parentIndex); std::vector nodes; std::copy_if(project()->instances().begin(), project()->instances().end(), std::back_inserter(nodes), [this, parentObj](const SEditorObject& obj) { @@ -547,7 +593,11 @@ SEditorObject ObjectTreeViewDefaultModel::createNewObject(const std::string& typ }); auto name = project()->findAvailableUniqueName(nodes.begin(), nodes.end(), nullptr, nodeName.empty() ? components::Naming::format(typeName) : nodeName); - auto newObj = commandInterface_->createObject(typeName, name, parent.isValid() ? parentObj : nullptr); + auto newObj = commandInterface_->createObject(typeName, name, parentIndex.isValid() ? parentObj : nullptr); + + // Insert new object into model + // This is necessary so that we can immediately select it after creation. + insertObject(parentIndex, newObj); return newObj; } @@ -715,6 +765,20 @@ void ObjectTreeViewDefaultModel::cutObjectsAtIndices(const QModelIndexList& indi } } +bool ObjectTreeViewDefaultModel::canConvertAnimationChannels(const QModelIndexList& indices) const { + auto objects = indicesToSEditorObjects(indices); + return std::all_of(objects.begin(), objects.end(), + [](auto obj) { + return obj && obj->template isType(); + }); +} + +void ObjectTreeViewDefaultModel::convertToAnimationChannelRaco(const QModelIndexList& indices) { + auto objects = indicesToSEditorObjects(indices); + commandInterface_->convertToAnimationChannelRaco(objects); +} + + void ObjectTreeViewDefaultModel::moveScenegraphChildren(const std::vector& objects, SEditorObject parent, int row) { int insertBeforeIndex = row; if (!parent) { diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewExternalProjectModel.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewExternalProjectModel.cpp index b1a4d687..909f1064 100644 --- a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewExternalProjectModel.cpp +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewExternalProjectModel.cpp @@ -146,7 +146,7 @@ void ObjectTreeViewExternalProjectModel::setNodeExternalProjectInfo(ObjectTreeNo } } } - node->setBelongsToExternalProject(projectPath, projectName); + node->setExternalProjectInfo(projectPath, projectName); } void ObjectTreeViewExternalProjectModel::buildObjectTree() { @@ -156,7 +156,7 @@ void ObjectTreeViewExternalProjectModel::buildObjectTree() { for (const auto& [projectPath, commandInterface] : externalProjectStore_->allExternalProjects()) { auto projectRootNode = new ObjectTreeNode(ObjectTreeNodeType::ExternalProject, invisibleRootNode_.get()); std::string projectName = commandInterface ? commandInterface->project()->projectName() : std::string(); - projectRootNode->setBelongsToExternalProject(projectPath, projectName); + projectRootNode->setExternalProjectInfo(projectPath, projectName); if (commandInterface) { auto filteredExternalProjectObjects = filterForTopLevelObjects(commandInterface->project()->instances()); constructTreeUnderNode(projectRootNode, filteredExternalProjectObjects, groupExternalReferences_, false); @@ -233,6 +233,10 @@ bool ObjectTreeViewExternalProjectModel::canPasteIntoIndex(const QModelIndex& in return false; } +std::vector ObjectTreeViewExternalProjectModel::hiddenColumns() const { + return {COLUMNINDEX_PREVIEW_VISIBILITY, COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY, COLUMNINDEX_RENDER_ORDER, COLUMNINDEX_INPUT_BUFFERS, COLUMNINDEX_OUTPUT_BUFFERS}; +} + bool ObjectTreeViewExternalProjectModel::isObjectAllowedIntoIndex(const QModelIndex& index, const core::SEditorObject& obj) const { return false; } diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewPrefabModel.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewPrefabModel.cpp index 6c81ea15..1eb2af92 100644 --- a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewPrefabModel.cpp +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewPrefabModel.cpp @@ -17,8 +17,13 @@ namespace raco::object_tree::model { -ObjectTreeViewPrefabModel::ObjectTreeViewPrefabModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore, const std::vector& allowedCreatableUserTypes) - : ObjectTreeViewDefaultModel(commandInterface, dispatcher, externalProjectsStore, allowedCreatableUserTypes, true) { +using namespace user_types; + +ObjectTreeViewPrefabModel::ObjectTreeViewPrefabModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore) + : ObjectTreeViewDefaultModel(commandInterface, dispatcher, externalProjectsStore, + std::vector{ + Prefab::typeDescription.typeName}, + true) { } QVariant ObjectTreeViewPrefabModel::data(const QModelIndex& index, int role) const { @@ -34,4 +39,8 @@ QVariant ObjectTreeViewPrefabModel::data(const QModelIndex& index, int role) con return ObjectTreeViewDefaultModel::data(index, role); } +std::vector ObjectTreeViewPrefabModel::hiddenColumns() const { + return {COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY, COLUMNINDEX_RENDER_ORDER, COLUMNINDEX_INPUT_BUFFERS, COLUMNINDEX_OUTPUT_BUFFERS}; +} + } // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewRenderViewModel.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewRenderViewModel.cpp new file mode 100644 index 00000000..9b72c0ee --- /dev/null +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewRenderViewModel.cpp @@ -0,0 +1,306 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "object_tree_view_model/ObjectTreeViewRenderViewModel.h" + +#include "core/Iterators.h" +#include "core/Queries.h" +#include "core/Queries_Tags.h" + +#include "user_types/BlitPass.h" +#include "user_types/Material.h" +#include "user_types/MeshNode.h" +#include "user_types/RenderLayer.h" +#include "user_types/RenderPass.h" + +namespace raco::object_tree::model { + +using namespace raco::core; + +ObjectTreeViewRenderViewModel::ObjectTreeViewRenderViewModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore) + : ObjectTreeViewDefaultModel(commandInterface, dispatcher, externalProjectsStore, + {user_types::BlitPass::typeDescription.typeName, user_types::RenderPass::typeDescription.typeName}, true) { +} + +Qt::ItemFlags ObjectTreeViewRenderViewModel::flags(const QModelIndex& index) const { + return QAbstractItemModel::flags(index); +} + +std::vector ObjectTreeViewRenderViewModel::creatableTypes(const QModelIndex& index) const { + return {}; +} + +bool ObjectTreeViewRenderViewModel::canProgramaticallyGotoObject() const { + return false; +} + +std::vector ObjectTreeViewRenderViewModel::hiddenColumns() const { + return {COLUMNINDEX_PREVIEW_VISIBILITY, COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY, COLUMNINDEX_PROJECT}; +} + +ObjectTreeViewDefaultModel::ColumnIndex ObjectTreeViewRenderViewModel::defaultSortColumn() const { + return COLUMNINDEX_RENDER_ORDER; +} + +void ObjectTreeViewRenderViewModel::updateSubscriptions() { + subscriptions_.clear(); + + auto setDirtyAction = [this](ValueHandle handle) { + dirty_ = true; + }; + + // Subscription needed: + // BlitPass -> buffers, renderOrder + // RenderPass -> target, layers, renderOrder + // RenderLayer -> renderableTags, materialFilterTags, materialFilterMode, sortOrder + // Node -> tags, children + // MeshNode -> private, material + // any texture uniform in a MeshNode or Material + + // BlitPass + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("sourceRenderBuffer", setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("targetRenderBuffer", setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("sourceRenderBufferMS", setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("targetRenderBufferMS", setDirtyAction)); + // RenderPass + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("target", setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("renderOrder", setDirtyAction)); + // RenderLayer + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("materialFilterMode", setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("sortOrder", setDirtyAction)); + // MeshNode + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("private", setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("material", setDirtyAction)); + // Node + subscriptions_.emplace_back(dispatcher_->registerOnPropertyChange("tags", setDirtyAction)); + + for (const auto& obj : project()->instances()) { + if (auto meshnode = obj->as()) { + if (meshnode->materialPrivate(0)) { + for (auto const& prop : ValueTreeIteratorAdaptor(meshnode->getUniformContainerHandle(0))) { + if (prop.type() == PrimitiveType::Ref) { + subscriptions_.emplace_back(dispatcher_->registerOn(prop, [this]() { dirty_ = true; })); + } + } + } else if (auto mat = meshnode->getMaterial(0)) { + for (auto const& prop : ValueTreeIteratorAdaptor(ValueHandle(meshnode->getMaterial(0), &user_types::Material::uniforms_))) { + if (prop.type() == PrimitiveType::Ref) { + subscriptions_.emplace_back(dispatcher_->registerOn(prop, [this]() { dirty_ = true; })); + } + } + } + } + + if (auto rp = obj->as()) { + subscriptions_.emplace_back(dispatcher_->registerOnChildren({rp, &user_types::RenderPass::layers_}, setDirtyAction)); + } + if (auto rl = obj->as()) { + subscriptions_.emplace_back(dispatcher_->registerOnChildren({rl, &user_types::RenderLayer::renderableTags_}, setDirtyAction)); + subscriptions_.emplace_back(dispatcher_->registerOnChildren({rl, &user_types::RenderLayer::materialFilterTags_}, setDirtyAction)); + } + } +} + +void ObjectTreeViewRenderViewModel::buildObjectTree() { + dirty_ = false; + if (!commandInterface_) { + return; + } + + auto filteredEditorObjects = filterForTopLevelObjects(project()->instances()); + + beginResetModel(); + + resetInvisibleRootNode(); + buildRenderPasses(invisibleRootNode_.get(), filteredEditorObjects); + updateTreeIndexes(); + updateSubscriptions(); + + endResetModel(); +} + +std::vector ObjectTreeViewRenderViewModel::buildTaggedNodeSubtree(const std::vector& objects, const std::set& tags, bool parentActive, const std::set& materialFilterTags, bool materialFilterExclusive, const std::map& renderBufferRefs, SEditorObjectSet& inputBuffers) { + std::vector nodes; + + for (const auto obj : objects) { + bool objectTagged = core::Queries::hasObjectAnyTag(obj->as(), tags); + bool active = parentActive || objectTagged; + + auto currentChildNodes = buildTaggedNodeSubtree(obj->children_->asVector(), tags, active, materialFilterTags, materialFilterExclusive, renderBufferRefs, inputBuffers); + + bool addObject = active && obj->isType() && core::Queries::isMeshNodeInMaterialFilter(obj->as(), materialFilterTags, materialFilterExclusive); + + if (addObject || !currentChildNodes.empty()) { + if (addObject) { + auto meshNode = obj->as(); + auto it = renderBufferRefs.find(meshNode->materialPrivate(0) ? obj : meshNode->getMaterial(0)); + if (it != renderBufferRefs.end()) { + for (const auto obj : it->second) { + inputBuffers.insert(obj); + } + } + } + + auto node = new ObjectTreeNode(obj, nullptr); + for (auto childNode : currentChildNodes) { + node->addChild(childNode); + } + nodes.emplace_back(node); + } + } + return nodes; +} + +void ObjectTreeViewRenderViewModel::buildRenderLayerSubtree( + ObjectTreeNode* layerNode, + core::SEditorObject obj, + const std::map& renderBufferRefs, + const std::vector& topLevelNodes, + const std::vector& renderLayers, + core::SEditorObjectSet& inputBuffers) { + auto layer = obj->as(); + + std::set materialFilterTags{layer->materialFilterTags()}; + bool materialFilterExclusive = *layer->materialFilterMode_ == static_cast(user_types::ERenderLayerMaterialFilterMode::Exclusive); + + bool sceneGraphOrder = static_cast(user_types::ERenderLayerOrder::SceneGraph) == *layer->sortOrder_; + + if (sceneGraphOrder) { + for (auto node : buildTaggedNodeSubtree(topLevelNodes, layer->renderableTagSet(), false, materialFilterTags, materialFilterExclusive, renderBufferRefs, inputBuffers)) { + layerNode->addChild(node); + } + } else { + for (auto tag : layer->renderableTags()) { + auto tagNode = new ObjectTreeNode(ObjectTreeNodeType::Tag, tag, layerNode); + tagNode->setRenderOrder(layer->renderableTags_->get(tag)->asInt()); + + for (auto node : buildTaggedNodeSubtree(topLevelNodes, {tag}, false, materialFilterTags, materialFilterExclusive, renderBufferRefs, inputBuffers)) { + tagNode->addChild(node); + } + + for (auto childLayer : renderLayers) { + if (core::Queries::hasObjectTag(childLayer, tag)) { + auto childLayerNode = new ObjectTreeNode(childLayer, tagNode); + buildRenderLayerSubtree(childLayerNode, childLayer, renderBufferRefs, topLevelNodes, renderLayers, inputBuffers); + } + } + } + } +} + +void ObjectTreeViewRenderViewModel::buildRenderPassSubtree(ObjectTreeNode* node, core::SEditorObject obj, const std::map& renderBufferRefs, const std::vector& topLevelNodes, const std::vector& renderLayers) { + core::SEditorObjectSet inputBuffers; + + auto renderPass = obj->as(); + std::vector layers; + for (const auto& layer : renderPass->layers_->asVector()) { + if (layer) { + auto layerNode = new ObjectTreeNode(layer, node); + buildRenderLayerSubtree(layerNode, layer, renderBufferRefs, topLevelNodes, renderLayers, inputBuffers); + } + } + + std::string inputBufferDesc; + for (auto buffer : inputBuffers) { + if (!inputBufferDesc.empty()) { + inputBufferDesc += "\n"; + } + inputBufferDesc += buffer->objectName(); + } + + std::string outputBufferDesc; + auto target = *renderPass->target_; + if (target) { + if (auto targetNormal = target->as()) { + for (auto buffer : targetNormal->buffers_->asVector()) { + if (buffer) { + if (!outputBufferDesc.empty()) { + outputBufferDesc += "\n"; + } + outputBufferDesc += buffer->objectName(); + } + } + } else { + auto targetMS = target->as(); + for (auto buffer : targetMS->buffers_->asVector()) { + if (buffer) { + if (!outputBufferDesc.empty()) { + outputBufferDesc += "\n"; + } + outputBufferDesc += buffer->objectName(); + } + } + } + } else { + outputBufferDesc = ""; + } + node->setBuffers(inputBufferDesc, outputBufferDesc); + +} + +std::map findRenderBufferReferences(const Project& project) { + std::map refs; + + for (auto obj : project.instances()) { + if (obj->isType()) { + for (const auto& weakSrcObj : obj->referencesToThis()) { + auto srcObj = weakSrcObj.lock(); + if (srcObj) { + refs[srcObj].insert(obj); + } + } + } + } + return refs; +} + +void ObjectTreeViewRenderViewModel::buildRenderPasses(ObjectTreeNode* rootNode, const std::vector& children) { + auto renderBufferRefs = findRenderBufferReferences(*project()); + + std::vector topLevelNodes; + std::vector renderLayers; + for (auto const& child : project()->instances()) { + if (!child->getParent() && child->as()) { + topLevelNodes.emplace_back(child); + } + if (auto layer = child->as()) { + renderLayers.emplace_back(layer); + } + } + + for (auto obj : children) { + if (auto rp = obj->as()) { + auto node = new ObjectTreeNode(rp, rootNode); + node->setRenderOrder(*rp->renderOrder_); + buildRenderPassSubtree(node, rp, renderBufferRefs, topLevelNodes, renderLayers); + } + if (auto blitpass = obj->as()) { + auto node = new ObjectTreeNode(blitpass, rootNode); + node->setRenderOrder(*blitpass->renderOrder_); + + std::string inputBuffers; + std::string outputBuffers; + if (*blitpass->sourceRenderBuffer_) { + inputBuffers = (*blitpass->sourceRenderBuffer_)->objectName(); + } else if (*blitpass->sourceRenderBufferMS_) { + inputBuffers = (*blitpass->sourceRenderBufferMS_)->objectName(); + } + + if (*blitpass->targetRenderBuffer_) { + outputBuffers = (*blitpass->targetRenderBuffer_)->objectName(); + } else if (*blitpass->targetRenderBufferMS_) { + outputBuffers = (*blitpass->targetRenderBufferMS_)->objectName(); + } + node->setBuffers(inputBuffers, outputBuffers); + } + } +} + +} // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewResourceModel.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewResourceModel.cpp index 6fc105fd..d2013108 100644 --- a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewResourceModel.cpp +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewResourceModel.cpp @@ -17,11 +17,51 @@ #include "core/Queries.h" #include "core/ExternalReferenceAnnotation.h" +#include "user_types/AnchorPoint.h" +#include "user_types/AnimationChannel.h" +#include "user_types/AnimationChannelRaco.h" +#include "user_types/BlitPass.h" +#include "user_types/CubeMap.h" +#include "user_types/LuaScriptModule.h" +#include "user_types/Material.h" +#include "user_types/Mesh.h" +#include "user_types/RenderBuffer.h" +#include "user_types/RenderBufferMS.h" +#include "user_types/RenderLayer.h" +#include "user_types/RenderPass.h" +#include "user_types/RenderTarget.h" +#include "user_types/Texture.h" +#include "user_types/TextureExternal.h" +#include "user_types/Timer.h" + namespace raco::object_tree::model { -ObjectTreeViewResourceModel::ObjectTreeViewResourceModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectStore, const std::vector& allowedCreatableUserTypes) - : ObjectTreeViewDefaultModel(commandInterface, dispatcher, externalProjectStore, allowedCreatableUserTypes, true, true) {} +using namespace user_types; +ObjectTreeViewResourceModel::ObjectTreeViewResourceModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectStore) + : ObjectTreeViewDefaultModel(commandInterface, dispatcher, externalProjectStore, + std::vector{ + AnchorPoint::typeDescription.typeName, + AnimationChannel::typeDescription.typeName, + AnimationChannelRaco::typeDescription.typeName, + BlitPass::typeDescription.typeName, + CubeMap::typeDescription.typeName, + LuaScriptModule::typeDescription.typeName, + Material::typeDescription.typeName, + Mesh::typeDescription.typeName, + RenderBuffer::typeDescription.typeName, + RenderBufferMS::typeDescription.typeName, + RenderLayer::typeDescription.typeName, + RenderPass::typeDescription.typeName, + RenderTarget::typeDescription.typeName, + RenderTargetMS::typeDescription.typeName, + Texture::typeDescription.typeName, + TextureExternal::typeDescription.typeName, + Timer::typeDescription.typeName}, + true, true) { + setAcceptableFileExtensions(QStringList{"gltf", "glb", "ctm", "png", "vert", "frag", "geom", "def", "glsl", "lua"}); + setAcceptLuaModules(true); +} bool ObjectTreeViewResourceModel::pasteObjectAtIndex(const QModelIndex& index, bool pasteAsExtref, std::string* outError, const std::string& serializedObjects) { // ignore index: resources always get pasted at top level. @@ -39,4 +79,12 @@ std::vector ObjectTreeViewResourceModel::typesAllowedIntoIndex(cons return ObjectTreeViewDefaultModel::typesAllowedIntoIndex(topLevel); } +std::vector ObjectTreeViewResourceModel::hiddenColumns() const { + return {COLUMNINDEX_PREVIEW_VISIBILITY, COLUMNINDEX_ABSTRACT_VIEW_VISIBILITY, COLUMNINDEX_RENDER_ORDER, COLUMNINDEX_INPUT_BUFFERS, COLUMNINDEX_OUTPUT_BUFFERS}; +} + +ObjectTreeViewDefaultModel::ColumnIndex ObjectTreeViewResourceModel::defaultSortColumn() const { + return COLUMNINDEX_NAME; +} + } // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewSceneGraphModel.cpp b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewSceneGraphModel.cpp new file mode 100644 index 00000000..e3399efe --- /dev/null +++ b/gui/libObjectTree/src/object_tree_view_model/ObjectTreeViewSceneGraphModel.cpp @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "object_tree_view_model/ObjectTreeViewSceneGraphModel.h" + +#include "core/ExternalReferenceAnnotation.h" +#include "core/PrefabOperations.h" +#include "core/Queries.h" +#include "style/Icons.h" + +#include "user_types/Animation.h" +#include "user_types/LuaInterface.h" +#include "user_types/LuaScript.h" +#include "user_types/MeshNode.h" +#include "user_types/Node.h" +#include "user_types/OrthographicCamera.h" +#include "user_types/PerspectiveCamera.h" +#include "user_types/PrefabInstance.h" +#include "user_types/Skin.h" + +namespace raco::object_tree::model { + +using namespace user_types; + +ObjectTreeViewSceneGraphModel::ObjectTreeViewSceneGraphModel(core::CommandInterface* commandInterface, components::SDataChangeDispatcher dispatcher, core::ExternalProjectsStoreInterface* externalProjectsStore) + : ObjectTreeViewDefaultModel(commandInterface, dispatcher, externalProjectsStore, + std::vector{ + Animation::typeDescription.typeName, + LuaInterface::typeDescription.typeName, + LuaScript::typeDescription.typeName, + MeshNode::typeDescription.typeName, + Node::typeDescription.typeName, + OrthographicCamera::typeDescription.typeName, + PerspectiveCamera::typeDescription.typeName, + PrefabInstance::typeDescription.typeName, + Skin::typeDescription.typeName}, + true) { + setAcceptableFileExtensions(QStringList{"lua", "gltf", "glb"}); + setAcceptLuaScripts(true); + setAcceptLuaInterfaces(true); + setDropGltfOpensAssetImportDialog(true); +} + +} // namespace raco::object_tree::model \ No newline at end of file diff --git a/gui/libObjectTree/tests/CMakeLists.txt b/gui/libObjectTree/tests/CMakeLists.txt index 28b31f65..aea07bbb 100644 --- a/gui/libObjectTree/tests/CMakeLists.txt +++ b/gui/libObjectTree/tests/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_SOURCES ObjectTreeViewMultipleModels_test.h ObjectTreeViewMultipleModels_test.cpp ObjectTreeViewPrefabModel_test.cpp ObjectTreeViewResourceModel_test.cpp + ObjectTreeViewRenderViewModel_test.cpp ) set(TEST_LIBRARIES @@ -32,6 +33,13 @@ raco_package_add_gui_test( ${CMAKE_CURRENT_BINARY_DIR} ) +raco_package_add_test_resources( + libObjectTree_test "${CMAKE_SOURCE_DIR}/resources" + shaders/simple_texture.frag + shaders/simple_texture.vert + meshes/Duck.glb +) + get_target_property(object_tree_private_includes raco::ObjectTree INCLUDE_DIRECTORIES) get_target_property(object_tree_private_libraries raco::ObjectTree LINK_LIBRARIES) diff --git a/gui/libObjectTree/tests/ObjectTreeDockManager_test.cpp b/gui/libObjectTree/tests/ObjectTreeDockManager_test.cpp index c9505d76..d3974fa1 100644 --- a/gui/libObjectTree/tests/ObjectTreeDockManager_test.cpp +++ b/gui/libObjectTree/tests/ObjectTreeDockManager_test.cpp @@ -38,7 +38,7 @@ TEST_F(ObjectDefaultTreeDockManagerTest, DockRemovalTwoDocksOneRemovedBySimulate auto firstDock = generateDockInManager(); auto secondDock = generateDockInManager(); - firstDock->Q_EMIT dockClosed(firstDock.get()); + firstDock->Q_EMIT dockClosed(); ASSERT_EQ(manager_.getTreeDockAmount(), 1); } @@ -58,7 +58,7 @@ TEST_F(ObjectDefaultTreeDockManagerTest, DockWithUnselectedItemIsNotConsideredSe firstDock->setTreeView(new object_tree::view::ObjectTreeView("TreeView", model)); auto obj = model->createNewObject(user_types::Node::typeDescription.typeName, "name"); dispatcher_->dispatch(recorder); - firstDock->getActiveTreeView()->selectObject(QString::fromStdString(obj->objectID())); + firstDock->getActiveTreeView()->selectObject(QString::fromStdString(obj->objectID()), false); ASSERT_TRUE(manager_.getActiveDockWithSelection() == firstDock.get()); commandInterface.deleteObjects({obj}); diff --git a/gui/libObjectTree/tests/ObjectTreeDockManager_test.h b/gui/libObjectTree/tests/ObjectTreeDockManager_test.h index 22990d69..3a50f552 100644 --- a/gui/libObjectTree/tests/ObjectTreeDockManager_test.h +++ b/gui/libObjectTree/tests/ObjectTreeDockManager_test.h @@ -15,11 +15,9 @@ #include #include -class ObjectDefaultTreeDockManagerTest : public TestEnvironmentCore { +class ObjectDefaultTreeDockManagerTest : public TestEnvironmentCoreT<::testing::Test, QApplication> { protected: object_tree::view::ObjectTreeDockManager manager_; - int argc = 0; - QApplication fakeApp_{argc, nullptr}; components::SDataChangeDispatcher dispatcher_{std::make_shared()}; std::unique_ptr generateDockInManager() { diff --git a/gui/libObjectTree/tests/ObjectTreeFilter_test.h b/gui/libObjectTree/tests/ObjectTreeFilter_test.h index a53fd466..2cc56dae 100644 --- a/gui/libObjectTree/tests/ObjectTreeFilter_test.h +++ b/gui/libObjectTree/tests/ObjectTreeFilter_test.h @@ -75,7 +75,7 @@ class ObjectTreeFilterTestFixture : public RacoBaseTest<::testing::TestWithParam QGuiApplication fakeGuiApp_{argc_, nullptr}; ramses_base::HeadlessEngineBackend backend{}; - raco::application::RaCoApplication application{backend, {{}, false, false, -1, -1, false}}; + application::RaCoApplication application{backend, {{}, false, false, -1, -1, false}}; core::ExternalProjectsStoreInterface* externalProjects() { return application.externalProjects(); diff --git a/gui/libObjectTree/tests/ObjectTreeViewDefaultModel_test.cpp b/gui/libObjectTree/tests/ObjectTreeViewDefaultModel_test.cpp index 1c9f81f7..1c09db2d 100644 --- a/gui/libObjectTree/tests/ObjectTreeViewDefaultModel_test.cpp +++ b/gui/libObjectTree/tests/ObjectTreeViewDefaultModel_test.cpp @@ -86,6 +86,16 @@ void ObjectTreeViewDefaultModelTest::compareValuesInTree(const SEditorObject &ob ASSERT_EQ(treeValue, objValue); } break; + case ObjectTreeViewDefaultModel::COLUMNINDEX_RENDER_ORDER: + ASSERT_FALSE(objTreeNode->getRenderOrder().has_value()); + break; + case ObjectTreeViewDefaultModel::COLUMNINDEX_INPUT_BUFFERS: + ASSERT_EQ(objTreeNode->getInputBuffers(), std::string()); + break; + case ObjectTreeViewDefaultModel::COLUMNINDEX_OUTPUT_BUFFERS: + ASSERT_EQ(objTreeNode->getInputBuffers(), std::string()); + break; + default: { FAIL() << "Need to check value equivalence for new ObjectTreeViewDefaultModel column enum value"; } diff --git a/gui/libObjectTree/tests/ObjectTreeViewExternalProjectModel_test.cpp b/gui/libObjectTree/tests/ObjectTreeViewExternalProjectModel_test.cpp index 42b4c56f..7a1bb70a 100644 --- a/gui/libObjectTree/tests/ObjectTreeViewExternalProjectModel_test.cpp +++ b/gui/libObjectTree/tests/ObjectTreeViewExternalProjectModel_test.cpp @@ -30,7 +30,7 @@ class ExposedObjectTreeViewExternalProjectModel : public model::ObjectTreeViewEx buildObjectTree(); } - ExposedObjectTreeViewExternalProjectModel(raco::application::RaCoApplication &app) + ExposedObjectTreeViewExternalProjectModel(application::RaCoApplication &app) : ObjectTreeViewExternalProjectModel(app.activeRaCoProject().commandInterface(), app.dataChangeDispatcher(), app.externalProjects()) {} model::ObjectTreeNode *getInvisibleRootNode() { @@ -47,11 +47,11 @@ class ObjectTreeViewExternalProjectModelTest : public ObjectTreeViewDefaultModel protected: ramses_base::HeadlessEngineBackend otherBackend; - raco::application::RaCoApplication otherApplication{otherBackend}; + application::RaCoApplication otherApplication{otherBackend}; ExposedObjectTreeViewExternalProjectModel externalProjectModel{application}; void generateExternalProject(const std::vector &instances, std::string projectPath = "projectPath.rca") { - application.externalProjectsStore_.externalProjects_[projectPath] = raco::application::RaCoProject::createNew(&otherApplication, true, static_cast(ramses_base::BaseEngineBackend::maxFeatureLevel)); + application.externalProjectsStore_.externalProjects_[projectPath] = application::RaCoProject::createNew(&otherApplication, true, static_cast(ramses_base::BaseEngineBackend::maxFeatureLevel)); auto project = application.externalProjectsStore_.externalProjects_[projectPath]->project(); for (const auto &instance : instances) { diff --git a/gui/libObjectTree/tests/ObjectTreeViewMultipleModels_test.h b/gui/libObjectTree/tests/ObjectTreeViewMultipleModels_test.h index 7600e4f9..574de7b5 100644 --- a/gui/libObjectTree/tests/ObjectTreeViewMultipleModels_test.h +++ b/gui/libObjectTree/tests/ObjectTreeViewMultipleModels_test.h @@ -22,7 +22,7 @@ class ObjectTreeViewMultipleModelsTest : public ObjectTreeViewDefaultModelTest { core::SEditorObject prefab_; ObjectTreeViewMultipleModelsTest() : ObjectTreeViewDefaultModelTest(), - prefabModel_(&commandInterface(), application.dataChangeDispatcher(), nullptr, {user_types::Prefab::typeDescription.typeName}) { + prefabModel_(&commandInterface(), application.dataChangeDispatcher(), nullptr) { } void SetUp() override { diff --git a/gui/libObjectTree/tests/ObjectTreeViewPrefabModel_test.cpp b/gui/libObjectTree/tests/ObjectTreeViewPrefabModel_test.cpp index a98e8327..f3c5fbc6 100644 --- a/gui/libObjectTree/tests/ObjectTreeViewPrefabModel_test.cpp +++ b/gui/libObjectTree/tests/ObjectTreeViewPrefabModel_test.cpp @@ -21,10 +21,7 @@ using namespace raco::user_types; class ObjectTreeViewPrefabModelTest : public ObjectTreeViewDefaultModelTest { public: ObjectTreeViewPrefabModelTest() : ObjectTreeViewDefaultModelTest() { - viewModel_.reset(new object_tree::model::ObjectTreeViewPrefabModel(&commandInterface(), application.dataChangeDispatcher(), externalProjectStore(), - { - Prefab::typeDescription.typeName - })); + viewModel_.reset(new object_tree::model::ObjectTreeViewPrefabModel(&commandInterface(), application.dataChangeDispatcher(), externalProjectStore())); } }; diff --git a/gui/libObjectTree/tests/ObjectTreeViewRenderViewModel_test.cpp b/gui/libObjectTree/tests/ObjectTreeViewRenderViewModel_test.cpp new file mode 100644 index 00000000..0b02b6ee --- /dev/null +++ b/gui/libObjectTree/tests/ObjectTreeViewRenderViewModel_test.cpp @@ -0,0 +1,470 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * + * This file is part of Ramses Composer + * (see https://github.com/bmwcarit/ramses-composer). + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include "gtest/gtest.h" + +#include "ObjectTreeViewDefaultModel_test.h" + +#include "object_tree_view_model/ObjectTreeViewRenderViewModel.h" + +#include "user_types/BlitPass.h" +#include "user_types/MeshNode.h" +#include "user_types/RenderLayer.h" +#include "user_types/RenderPass.h" +#include "user_types/RenderTarget.h" + +using namespace raco::user_types; +using namespace raco::object_tree::model; + +class ObjectTreeViewRenderViewModelTest : public ObjectTreeViewDefaultModelTest { +public: + ObjectTreeViewRenderViewModelTest() : ObjectTreeViewDefaultModelTest() { + viewModel_.reset(new object_tree::model::ObjectTreeViewRenderViewModel(&commandInterface(), application.dataChangeDispatcher(), nullptr)); + + node = create("root", nullptr, {"render_main"}); + mesh = create_mesh("mesh", "meshes/Duck.glb"); + material = create_material("material", "shaders/simple_texture.vert", "shaders/simple_texture.frag", {}); + material_def = create("material_def", nullptr, {"mat_default"}); + material_alt = create("material_alt", nullptr, {"mat_alt"}); + meshnode = create_meshnode("meshnode", mesh, material, node); + meshnode_def = create_meshnode("meshnode_def", mesh, material_def, node); + meshnode_alt = create_meshnode("meshnode_alt", mesh, material_alt, node); + buffer_1 = create("buffer_1"); + buffer_2 = create("buffer_2"); + target = create_rendertarget("render_target", {buffer_1}); + layer = create_layer("layer", {}, {{"render_main", 7}}); + renderpass = create_renderpass("render_pass", {}, {layer}, 2); + dispatch(true); + } + + void dispatch(bool rebuildTree = false) { + application.dataChangeDispatcher()->dispatch(recorder().release()); + if (rebuildTree) { + viewModel_->buildObjectTree(); + } + } + + void checkTree(QModelIndex index, ObjectTreeNode* node) { + auto modelNode = viewModel_->indexToTreeNode(index); + std::map nodeTypeNames = { + {ObjectTreeNodeType::EditorObject, "EditorObject"}, + {ObjectTreeNodeType::Root, "Root"}, + {ObjectTreeNodeType::Tag, "Tag"}}; + std::string desc = fmt::format("Node type = {}, Object type = {}, Name = {}", + nodeTypeNames.at(node->getType()), node->getDisplayType(), node->getDisplayName()); + + EXPECT_EQ(modelNode->getRepresentedObject(), node->getRepresentedObject()) << desc; + EXPECT_EQ(modelNode->getType(), node->getType()) << desc; + EXPECT_EQ(modelNode->getTypeName(), node->getTypeName()) << desc; + EXPECT_EQ(modelNode->getRenderOrder(), node->getRenderOrder()) << desc; + EXPECT_EQ(modelNode->getInputBuffers(), node->getInputBuffers()) << desc; + EXPECT_EQ(modelNode->getOutputBuffers(), node->getOutputBuffers()) << desc; + EXPECT_EQ(modelNode->childCount(), node->childCount()) << desc; + for (size_t row = 0; row < node->childCount(); row++) { + checkTree(viewModel_->index(row, 0, index), node->getChild(row)); + } + } + + ObjectTreeNode* makeNode(core::SEditorObject obj, const std::vector& children = {}) { + ObjectTreeNode* node = obj ? new ObjectTreeNode(obj, {}) : new ObjectTreeNode(ObjectTreeNodeType::Root, {}); + for (auto child : children) { + node->addChild(child); + } + return node; + } + + ObjectTreeNode* makeRenderPassNode(core::SEditorObject obj, int renderOrder, const std::string& inputBuffers, const std::string& outputBuffers, const std::vector& children = {}) { + ObjectTreeNode* node = new ObjectTreeNode(obj, {}); + node->setRenderOrder(renderOrder); + node->setBuffers(inputBuffers, outputBuffers); + for (auto child : children) { + node->addChild(child); + } + return node; + } + + ObjectTreeNode* makeTagNode(const std::string& tag, int renderOrder, const std::vector& children = {}) { + auto node = new ObjectTreeNode(ObjectTreeNodeType::Tag, tag, {}); + node->setRenderOrder(renderOrder); + for (auto child : children) { + node->addChild(child); + } + return node; + } + + SNode node; + SMesh mesh; + SMaterial material; + SMaterial material_def; + SMaterial material_alt; + SMeshNode meshnode; + SMeshNode meshnode_def; + SMeshNode meshnode_alt; + SRenderBuffer buffer_1; + SRenderBuffer buffer_2; + SRenderTarget target; + SRenderLayer layer; + SRenderPass renderpass; +}; + +TEST_F(ObjectTreeViewRenderViewModelTest, build_top_level) { + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), target); + commandInterface().set(ValueHandle(renderpass, &RenderPass::layers_)[0], SEditorObject()); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(renderpass, 2, {}, "buffer_1"), makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_layer_sortorder_tag) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_layer_sortorder_scenegraph) { + commandInterface().set({layer, &RenderLayer::sortOrder_}, static_cast(ERenderLayerOrder::SceneGraph)); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_material_filter_inclusive) { + commandInterface().setTags({layer, &user_types::RenderLayer::materialFilterTags_}, {"mat_default"}); + commandInterface().set({layer, &user_types::RenderLayer::materialFilterMode_}, static_cast(user_types::ERenderLayerMaterialFilterMode::Inclusive)); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode_def)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_material_filter_exclusive) { + commandInterface().setTags({layer, &user_types::RenderLayer::materialFilterTags_}, {"mat_default"}); + commandInterface().set({layer, &user_types::RenderLayer::materialFilterMode_}, static_cast(user_types::ERenderLayerMaterialFilterMode::Exclusive)); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_input_buffer_shared_material) { + commandInterface().set(ValueHandle(material, &Material::uniforms_).get("u_Tex"), buffer_1); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, "buffer_1", "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_input_buffer_private_material_private_uniform) { + commandInterface().set(meshnode->getMaterialPrivateHandle(0), true); + commandInterface().set(meshnode->getUniformContainerHandle(0).get("u_Tex"), buffer_1); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, "buffer_1", "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, build_input_buffer_private_material_shared_uniform) { + commandInterface().set(meshnode->getMaterialPrivateHandle(0), true); + commandInterface().set(ValueHandle(material, &Material::uniforms_).get("u_Tex"), buffer_1); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_create_blitpass) { + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), target); + commandInterface().set(ValueHandle(renderpass, &RenderPass::layers_)[0], SEditorObject()); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(renderpass, 2, {}, "buffer_1"), makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); + + auto blitpass_2 = create_blitpass("blit_pass_2", 3, buffer_2, buffer_1); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(renderpass, 2, {}, "buffer_1"), + makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2"), + makeRenderPassNode(blitpass_2, 3, "buffer_2", "buffer_1")})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_delete_renderpass) { + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), target); + commandInterface().set(ValueHandle(renderpass, &RenderPass::layers_)[0], SEditorObject()); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(renderpass, 2, {}, "buffer_1"), makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); + + commandInterface().deleteObjects({renderpass}); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_delete_buffer) { + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), target); + commandInterface().set(ValueHandle(renderpass, &RenderPass::layers_)[0], SEditorObject()); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(renderpass, 2, {}, "buffer_1"), makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); + + commandInterface().deleteObjects({buffer_1}); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(renderpass, 2, {}, {}), makeRenderPassNode(blitpass, 1, {}, "buffer_2")})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_create_meshnode_root) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + auto meshnode_new = create_meshnode("meshnode_new", mesh, material, {}, {"render_main"}); + dispatch(false); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)}), makeNode(meshnode_new)})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_delete_meshnode_root) { + auto meshnode_new = create_meshnode("meshnode_new", mesh, material, {}, {"render_main"}); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)}), makeNode(meshnode_new)})})})); + + commandInterface().deleteObjects({meshnode_new}); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_blitpass_change_render_order) { + commandInterface().deleteObjects({renderpass}); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); + + commandInterface().set(ValueHandle(blitpass, &BlitPass::renderOrder_), 5); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 5, "buffer_1", "buffer_2")})); +} + + +TEST_F(ObjectTreeViewRenderViewModelTest, update_blitpass_change_source_buffer) { + commandInterface().deleteObjects({renderpass}); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); + + commandInterface().set(ValueHandle(blitpass, &BlitPass::sourceRenderBuffer_), SEditorObject()); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, {}, "buffer_2")})); + + commandInterface().set(ValueHandle(blitpass, &BlitPass::sourceRenderBuffer_), buffer_1); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_blitpass_change_target_buffer) { + commandInterface().deleteObjects({renderpass}); + auto blitpass = create_blitpass("blit_pass", 1, buffer_1, buffer_2); + dispatch(true); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); + + commandInterface().set(ValueHandle(blitpass, &BlitPass::targetRenderBuffer_), SEditorObject()); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", {})})); + + commandInterface().set(ValueHandle(blitpass, &BlitPass::targetRenderBuffer_), buffer_2); + dispatch(); + + checkTree({}, makeNode({}, {makeRenderPassNode(blitpass, 1, "buffer_1", "buffer_2")})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_renderpass_change_target) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), target); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "buffer_1", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(ValueHandle(renderpass, &RenderPass::target_), SEditorObject()); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_renderpass_change_render_order) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(ValueHandle(renderpass, &RenderPass::renderOrder_), 13); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 13, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_layer_change_sortorder) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set({layer, &RenderLayer::sortOrder_}, static_cast(ERenderLayerOrder::SceneGraph)); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_layer_change_material_filter_mode) { + commandInterface().setTags({layer, &user_types::RenderLayer::materialFilterTags_}, {"mat_default"}); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_alt)})})})})); + + commandInterface().set({layer, &user_types::RenderLayer::materialFilterMode_}, static_cast(user_types::ERenderLayerMaterialFilterMode::Inclusive)); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode_def)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_layer_change_material_filter_tags) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().setTags({layer, &user_types::RenderLayer::materialFilterTags_}, {"mat_default"}); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_layer_change_renderable_tags_replace) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().setRenderableTags({layer, &RenderLayer::renderableTags_}, {{"render_main", 2}}); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 2, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().setRenderableTags({layer, &RenderLayer::renderableTags_}, {{"render_alt", 3}}); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_alt", 3, {})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_layer_change_renderable_tags_priority) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(ValueHandle{layer, &RenderLayer::renderableTags_}.get("render_main"), 2); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 2, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_renderpass_change_layers) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(ValueHandle(renderpass, &user_types::RenderPass::layers_)[0], SEditorObject()); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_meshnode_change_material) { + commandInterface().setTags({layer, &user_types::RenderLayer::materialFilterTags_}, {"mat_default"}); + commandInterface().set({layer, &user_types::RenderLayer::materialFilterMode_}, static_cast(user_types::ERenderLayerMaterialFilterMode::Inclusive)); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode_def)})})})})); + + commandInterface().set(meshnode->getMaterialHandle(0), material_def); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_meshnode_change_private) { + commandInterface().set(ValueHandle(material, &Material::uniforms_).get("u_Tex"), buffer_1); + commandInterface().set(meshnode->getMaterialPrivateHandle(0), true); + commandInterface().set(meshnode->getUniformContainerHandle(0).get("u_Tex"), buffer_2); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, "buffer_2", "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(meshnode->getMaterialPrivateHandle(0), false); + + dispatch(); + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, "buffer_1", "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_input_buffer_shared_material) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(ValueHandle(material, &Material::uniforms_).get("u_Tex"), buffer_1); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, "buffer_1", "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_input_buffer_private_material_private_uniform) { + commandInterface().set(meshnode->getMaterialPrivateHandle(0), true); + dispatch(true); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().set(meshnode->getUniformContainerHandle(0).get("u_Tex"), buffer_1); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, "buffer_1", "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); +} + +TEST_F(ObjectTreeViewRenderViewModelTest, update_node_change_tags) { + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {makeNode(node, {makeNode(meshnode), makeNode(meshnode_def), makeNode(meshnode_alt)})})})})); + + commandInterface().setTags({node, &user_types::Node::tags_}, {"render_alt"}); + dispatch(); + + checkTree(viewModel_->index(0, 0), + makeRenderPassNode(renderpass, 2, {}, "", {makeNode(layer, {makeTagNode("render_main", 7, {})})})); +} + diff --git a/gui/libObjectTree/tests/ObjectTreeViewResourceModel_test.cpp b/gui/libObjectTree/tests/ObjectTreeViewResourceModel_test.cpp index 3732c2e3..a836eecf 100644 --- a/gui/libObjectTree/tests/ObjectTreeViewResourceModel_test.cpp +++ b/gui/libObjectTree/tests/ObjectTreeViewResourceModel_test.cpp @@ -15,6 +15,7 @@ #include "object_tree_view_model/ObjectTreeViewResourceModel.h" #include "user_types/AnchorPoint.h" #include "user_types/AnimationChannel.h" +#include "user_types/AnimationChannelRaco.h" #include "user_types/BlitPass.h" #include "user_types/LuaScriptModule.h" #include "user_types/MeshNode.h" @@ -31,24 +32,7 @@ using namespace raco::user_types; class ObjectTreeViewResourceModelTest : public ObjectTreeViewDefaultModelTest { public: ObjectTreeViewResourceModelTest() : ObjectTreeViewDefaultModelTest() { - viewModel_.reset(new object_tree::model::ObjectTreeViewResourceModel(&commandInterface(), application.dataChangeDispatcher(), nullptr, - { - AnchorPoint::typeDescription.typeName, - AnimationChannel::typeDescription.typeName, - BlitPass::typeDescription.typeName, - CubeMap::typeDescription.typeName, - Material::typeDescription.typeName, - Mesh::typeDescription.typeName, - LuaScriptModule::typeDescription.typeName, - Texture::typeDescription.typeName, - TextureExternal::typeDescription.typeName, - Timer::typeDescription.typeName, - RenderBuffer::typeDescription.typeName, - RenderBufferMS::typeDescription.typeName, - RenderTarget::typeDescription.typeName, - RenderTargetMS::typeDescription.typeName, - RenderLayer::typeDescription.typeName, - RenderPass::typeDescription.typeName})); + viewModel_.reset(new object_tree::model::ObjectTreeViewResourceModel(&commandInterface(), application.dataChangeDispatcher(), nullptr)); } }; @@ -57,6 +41,7 @@ TEST_F(ObjectTreeViewResourceModelTest, TypesAllowedIntoIndexEmptyIndex) { std::vector allowedTypesAssert { AnchorPoint::typeDescription.typeName, AnimationChannel::typeDescription.typeName, + AnimationChannelRaco::typeDescription.typeName, BlitPass::typeDescription.typeName, CubeMap::typeDescription.typeName, LuaScriptModule::typeDescription.typeName, diff --git a/gui/libPropertyBrowser/include/property_browser/PropertyBrowserWidget.h b/gui/libPropertyBrowser/include/property_browser/PropertyBrowserWidget.h index 7ddf4c40..610144d6 100644 --- a/gui/libPropertyBrowser/include/property_browser/PropertyBrowserWidget.h +++ b/gui/libPropertyBrowser/include/property_browser/PropertyBrowserWidget.h @@ -41,13 +41,13 @@ public Q_SLOTS: void setObjectFromObjectId(const QString& objectID, const QString& objectProperty); void setObjects(const core::SEditorObjectSet& objects, const QString& property); void highlightProperty(const QString& property); - void clear(); void setLockable(bool lockable) const; private Q_SLOTS: void showRefToThis(); private: + void clear(); void showScrollBar(bool isAlwaysOn); void setLocked(bool locked); void setObjectsImpl(const core::SEditorObjectSet& objects, bool forceExpandStateUpdate); diff --git a/gui/libPropertyBrowser/src/PropertyBrowserWidget.cpp b/gui/libPropertyBrowser/src/PropertyBrowserWidget.cpp index b69b899c..c485a9c4 100644 --- a/gui/libPropertyBrowser/src/PropertyBrowserWidget.cpp +++ b/gui/libPropertyBrowser/src/PropertyBrowserWidget.cpp @@ -228,10 +228,14 @@ void PropertyBrowserWidget::setObjectsImpl(const core::SEditorObjectSet& objects } void PropertyBrowserWidget::setObjects(const core::SEditorObjectSet& objects, const QString& property) { - setObjectsImpl(objects, false); + if (objects.size() == 0) { + clear(); + } else { + setObjectsImpl(objects, false); - if ((locked_ && currentObjects_ == objects) || !locked_) { - highlightProperty(property); + if ((locked_ && currentObjects_ == objects) || !locked_) { + highlightProperty(property); + } } } diff --git a/gui/libPropertyBrowser/src/editors/TagContainerEditor.cpp b/gui/libPropertyBrowser/src/editors/TagContainerEditor.cpp index e0f7bebe..524f1b3a 100644 --- a/gui/libPropertyBrowser/src/editors/TagContainerEditor.cpp +++ b/gui/libPropertyBrowser/src/editors/TagContainerEditor.cpp @@ -82,6 +82,7 @@ TagContainerEditor::TagContainerEditor(PropertyBrowserItem* item, QWidget* paren renderedBy_ = new QLabel{this}; renderedBy_->setForegroundRole(QPalette::BrightText); + renderedBy_->setWordWrap(true); layout->addWidget(renderedBy_, 1, 1, Qt::AlignTop); } diff --git a/gui/libPropertyBrowser/tests/CMakeLists.txt b/gui/libPropertyBrowser/tests/CMakeLists.txt index 74de9257..8fa8b5fe 100644 --- a/gui/libPropertyBrowser/tests/CMakeLists.txt +++ b/gui/libPropertyBrowser/tests/CMakeLists.txt @@ -48,3 +48,6 @@ raco_package_add_test_resources( scripts/types-scalar.lua scripts/interface-scalar-types.lua ) + +deploy_python_dlls(libPropertyBrowser_test) +deploy_python_folder(libPropertyBrowser_test) diff --git a/gui/libPropertyBrowser/tests/EditorTestFixture.h b/gui/libPropertyBrowser/tests/EditorTestFixture.h index 472e63ba..7c1ab514 100644 --- a/gui/libPropertyBrowser/tests/EditorTestFixture.h +++ b/gui/libPropertyBrowser/tests/EditorTestFixture.h @@ -17,20 +17,18 @@ #include template -class EditorTestFixtureT : public TestEnvironmentCoreT { +class EditorTestFixtureT : public TestEnvironmentCoreT { public: using DataChangeDispatcher = components::DataChangeDispatcher; - int argc{0}; - QApplication application{argc, nullptr}; std::shared_ptr dataChangeDispatcher; property_browser::PropertyBrowserModel model; - EditorTestFixtureT() : TestEnvironmentCoreT{}, dataChangeDispatcher{std::make_shared()} {} - EditorTestFixtureT(core::UserObjectFactoryInterface* objectFactory) : TestEnvironmentCoreT{objectFactory}, dataChangeDispatcher{std::make_shared()} {} + EditorTestFixtureT() : TestEnvironmentCoreT{}, dataChangeDispatcher{std::make_shared()} {} + EditorTestFixtureT(core::UserObjectFactoryInterface* objectFactory) : TestEnvironmentCoreT{objectFactory}, dataChangeDispatcher{std::make_shared()} {} void dispatch() { dataChangeDispatcher->dispatch(this->recorder.release()); - application.processEvents(); + this->application.processEvents(); } static void pasteProperty(property_browser::PropertyBrowserItem* item, data_storage::ValueBase* value) { diff --git a/gui/libRamsesWidgets/include/ramses_widgets/AbstractViewMainWindow.h b/gui/libRamsesWidgets/include/ramses_widgets/AbstractViewMainWindow.h index 0821460f..645b82bf 100644 --- a/gui/libRamsesWidgets/include/ramses_widgets/AbstractViewMainWindow.h +++ b/gui/libRamsesWidgets/include/ramses_widgets/AbstractViewMainWindow.h @@ -45,7 +45,6 @@ class AbstractViewMainWindow final : public QMainWindow { public Q_SLOTS: void onSelectionChanged(const core::SEditorObjectSet& objects); - void onSelectionCleared(); private: enum class HighlightMode { diff --git a/gui/libRamsesWidgets/include/ramses_widgets/PreviewContentWidget.h b/gui/libRamsesWidgets/include/ramses_widgets/PreviewContentWidget.h index 71a2571d..7d80d12d 100644 --- a/gui/libRamsesWidgets/include/ramses_widgets/PreviewContentWidget.h +++ b/gui/libRamsesWidgets/include/ramses_widgets/PreviewContentWidget.h @@ -51,6 +51,8 @@ public Q_SLOTS: Q_SIGNALS: void newMousePosition(const QPoint globalPosition); + void newPreviewState(bool previewStatus); + protected: void paintEvent(QPaintEvent* event) override; bool event(QEvent* event) override; diff --git a/gui/libRamsesWidgets/include/ramses_widgets/PreviewMainWindow.h b/gui/libRamsesWidgets/include/ramses_widgets/PreviewMainWindow.h index 1541e71e..c65c0fa8 100644 --- a/gui/libRamsesWidgets/include/ramses_widgets/PreviewMainWindow.h +++ b/gui/libRamsesWidgets/include/ramses_widgets/PreviewMainWindow.h @@ -71,6 +71,7 @@ public Q_SLOTS: PreviewContentWidget* previewWidget_; PreviewScrollAreaWidget* scrollAreaWidget_; QLabel* sceneIdLabel_; + QLabel* errorLabel_; }; } // namespace raco::ramses_widgets \ No newline at end of file diff --git a/gui/libRamsesWidgets/include/ramses_widgets/RamsesAbstractViewWindow.h b/gui/libRamsesWidgets/include/ramses_widgets/RamsesAbstractViewWindow.h index cc45d9ac..f882e91a 100644 --- a/gui/libRamsesWidgets/include/ramses_widgets/RamsesAbstractViewWindow.h +++ b/gui/libRamsesWidgets/include/ramses_widgets/RamsesAbstractViewWindow.h @@ -39,6 +39,8 @@ class RamsesAbstractViewWindow final { void* windowHandle_; RendererBackend& rendererBackend_; + bool errorState_ = false; + ramses::displayId_t displayId_; State current_{}; diff --git a/gui/libRamsesWidgets/include/ramses_widgets/RamsesPreviewWindow.h b/gui/libRamsesWidgets/include/ramses_widgets/RamsesPreviewWindow.h index 4de389a2..8111f873 100644 --- a/gui/libRamsesWidgets/include/ramses_widgets/RamsesPreviewWindow.h +++ b/gui/libRamsesWidgets/include/ramses_widgets/RamsesPreviewWindow.h @@ -60,14 +60,18 @@ class RamsesPreviewWindow final { const State& currentState(); State& nextState(); - void commit(bool forceUpdate = false); + bool commit(bool forceUpdate = false); bool saveScreenshot(const std::string& fullPath); + bool errorState(); + private: void* windowHandle_; RendererBackend& rendererBackend_; + bool errorState_ = false; + ramses::displayId_t displayId_; ramses::displayBufferId_t offscreenBufferId_; std::unique_ptr framebufferScene_; diff --git a/gui/libRamsesWidgets/include/ramses_widgets/SceneStateEventHandler.h b/gui/libRamsesWidgets/include/ramses_widgets/SceneStateEventHandler.h index 0d5ca42c..b22b2818 100644 --- a/gui/libRamsesWidgets/include/ramses_widgets/SceneStateEventHandler.h +++ b/gui/libRamsesWidgets/include/ramses_widgets/SceneStateEventHandler.h @@ -41,18 +41,18 @@ class SceneStateEventHandler final : public QObject, public ramses::RendererEven GreaterEqual }; - void waitForSceneState(ramses::sceneId_t sceneId, ramses::RendererSceneState state, ECompareFunc compFunc = ECompareFunc::Equal); + [[nodiscard]] bool waitForSceneState(ramses::sceneId_t sceneId, ramses::RendererSceneState state, ECompareFunc compFunc = ECompareFunc::Equal); void objectsPicked(ramses::sceneId_t sceneId, const ramses::pickableObjectId_t* pickedObjects, size_t pickedObjectsCount) override; - bool waitForFlush(ramses::sceneId_t sceneId, ramses::sceneVersionTag_t sceneVersion); - bool waitForDisplayCreation(ramses::displayId_t displayId); - bool waitForDisplayDestruction(ramses::displayId_t displayId); - bool waitForOffscreenBufferCreation(ramses::displayBufferId_t displayBufferId); - bool waitForOffscreenBufferDestruction(ramses::displayBufferId_t displayBufferId); - bool waitForOffscreenBufferLinked(ramses::displayBufferId_t displayBufferId); - bool waitUntilOrTimeout(const std::function& conditionFunction); - bool waitForScreenshot(); + [[nodiscard]] bool waitForFlush(ramses::sceneId_t sceneId, ramses::sceneVersionTag_t sceneVersion); + [[nodiscard]] bool waitForDisplayCreation(ramses::displayId_t displayId); + [[nodiscard]] bool waitForDisplayDestruction(ramses::displayId_t displayId); + [[nodiscard]] bool waitForOffscreenBufferCreation(ramses::displayBufferId_t displayBufferId); + [[nodiscard]] bool waitForOffscreenBufferDestruction(ramses::displayBufferId_t displayBufferId); + [[nodiscard]] bool waitForOffscreenBufferLinked(ramses::displayBufferId_t displayBufferId); + [[nodiscard]] bool waitUntilOrTimeout(const std::function& conditionFunction, const std::string& actionDescription); + [[nodiscard]] bool waitForScreenshot(); ramses::RendererSceneState sceneState(ramses::sceneId_t sceneId); diff --git a/gui/libRamsesWidgets/src/AbstractViewMainWindow.cpp b/gui/libRamsesWidgets/src/AbstractViewMainWindow.cpp index 05d05c49..a87346ba 100644 --- a/gui/libRamsesWidgets/src/AbstractViewMainWindow.cpp +++ b/gui/libRamsesWidgets/src/AbstractViewMainWindow.cpp @@ -150,11 +150,6 @@ void AbstractViewMainWindow::onSelectionChanged(const core::SEditorObjectSet& ob abstractScene_->attachGizmo(treeDockManager_->getSelection()); } -void AbstractViewMainWindow::onSelectionCleared() { - updateHighlighted(); - abstractScene_->attachGizmo({}); -} - void AbstractViewMainWindow::updateHighlighted() { switch (highlightMode_) { case HighlightMode::None: diff --git a/gui/libRamsesWidgets/src/PreviewContentWidget.cpp b/gui/libRamsesWidgets/src/PreviewContentWidget.cpp index ab43c40b..5a8b2666 100644 --- a/gui/libRamsesWidgets/src/PreviewContentWidget.cpp +++ b/gui/libRamsesWidgets/src/PreviewContentWidget.cpp @@ -12,7 +12,9 @@ #include "ramses_widgets/BuildOptions.h" #include "ramses_widgets/RamsesPreviewWindow.h" #include "components/QtFormatter.h" +#include "style/Icons.h" #include +#include #include #include @@ -108,8 +110,20 @@ void PreviewContentWidget::paintEvent(QPaintEvent* e) { // time scene id changes to paint event instead of our mainWindow timer // because the mainWindow timer interval is actually too high for RaCo // to register all scene id changes in the UI (?) - if (ramsesPreview_->currentState().sceneId != ramsesPreview_->nextState().sceneId) { - ramsesPreview_->commit(); + if (!ramsesPreview_->errorState()) { + setAttribute(Qt::WA_PaintOnScreen, true); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + if (ramsesPreview_->currentState().sceneId != ramsesPreview_->nextState().sceneId) { + auto status = ramsesPreview_->commit(); + Q_EMIT newPreviewState(status); + } + } else { + setAttribute(Qt::WA_PaintOnScreen, false); + setAttribute(Qt::WA_OpaquePaintEvent, false); + setAttribute(Qt::WA_NoSystemBackground, false); + QPainter painter{this}; + painter.drawTiledPixmap(rect(), style::Icons::instance().warning.pixmap(24)); } } @@ -117,7 +131,8 @@ void PreviewContentWidget::commit(bool forceUpdate) { const auto& currentState = ramsesPreview_->currentState(); auto& nextState = ramsesPreview_->nextState(); if (forceUpdate || nextState != currentState && nextState.sceneId == currentState.sceneId) { - ramsesPreview_->commit(forceUpdate); + auto status = ramsesPreview_->commit(forceUpdate); + Q_EMIT newPreviewState(status); } } diff --git a/gui/libRamsesWidgets/src/PreviewFramebufferScene.cpp b/gui/libRamsesWidgets/src/PreviewFramebufferScene.cpp index 0a8d8ed2..9cb1543e 100644 --- a/gui/libRamsesWidgets/src/PreviewFramebufferScene.cpp +++ b/gui/libRamsesWidgets/src/PreviewFramebufferScene.cpp @@ -190,8 +190,14 @@ ramses::dataConsumerId_t PreviewFramebufferScene::setupFramebufferTexture(Render sampler_.reset(); renderbufferMS_ = ramsesRenderBuffer(scene_.get(), size.width(), size.height(), ramses::ERenderBufferFormat::RGBA8, ramses::ERenderBufferAccessMode::ReadWrite, sampleRate, {}, {0, 0}); + if (!renderbufferMS_) { + return ramses::dataConsumerId_t::Invalid(); + } samplerMS_ = ramsesTextureSamplerMS(scene_.get(), renderbufferMS_, {}, {0, 0}); + if (!samplerMS_) { + return ramses::dataConsumerId_t::Invalid(); + } ramses::UniformInput texUniformInput = (*appearanceMS_)->getEffect().findUniformInput("uTex0").value(); (*appearanceMS_)->setInputTexture(texUniformInput, *samplerMS_.get()); @@ -213,8 +219,14 @@ ramses::dataConsumerId_t PreviewFramebufferScene::setupFramebufferTexture(Render const ramses::TextureSwizzle textureSwizzle{}; framebufferTexture_ = ramsesTexture2D(scene_.get(), ramses::ETextureFormat::RGBA8, size.width(), size.height(), mipDatas, false, textureSwizzle, "framebuffer texture", {0, 0}); + if (!framebufferTexture_) { + return ramses::dataConsumerId_t::Invalid(); + } sampler_ = ramsesTextureSampler(scene_.get(), ramses::ETextureAddressMode::Clamp, ramses::ETextureAddressMode::Clamp, samplingMethod, samplingMethod, framebufferTexture_.get(), 1, "framebuffer sampler", {0, 0}); + if (!sampler_) { + return ramses::dataConsumerId_t::Invalid(); + } ramses::UniformInput texUniformInput = (*appearance_)->getEffect().findUniformInput("uTex0").value(); (*appearance_)->setInputTexture(texUniformInput, *sampler_.get()); @@ -227,10 +239,15 @@ ramses::dataConsumerId_t PreviewFramebufferScene::setupFramebufferTexture(Render scene_->flush(); framebufferSampleId_ = backend.internalDataConsumerId(); + bool status; if (sampleRate > 0) { - scene_->createTextureConsumer(*samplerMS_.get(), framebufferSampleId_); + status = scene_->createTextureConsumer(*samplerMS_.get(), framebufferSampleId_); } else { - scene_->createTextureConsumer(*sampler_.get(), framebufferSampleId_); + status = scene_->createTextureConsumer(*sampler_.get(), framebufferSampleId_); + } + if (!status) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "Creating texture consumer failed: {}", scene_->getRamsesClient().getRamsesFramework().getLastError().value().message); + return ramses::dataConsumerId_t::Invalid(); } static const ramses::sceneVersionTag_t SCENE_VERSION_TAG_DATA_CONSUMER_CREATED{42}; @@ -239,10 +256,13 @@ ramses::dataConsumerId_t PreviewFramebufferScene::setupFramebufferTexture(Render auto& eventHandler = backend.eventHandler(); // Toggle version tag for scene so that we are sure that data consumer is create scene_->flush(SCENE_VERSION_TAG_DATA_CONSUMER_CREATED); - eventHandler.waitForFlush(scene_->getSceneId(), SCENE_VERSION_TAG_DATA_CONSUMER_CREATED); + if (!eventHandler.waitForFlush(scene_->getSceneId(), SCENE_VERSION_TAG_DATA_CONSUMER_CREATED)) { + return ramses::dataConsumerId_t::Invalid(); + } scene_->flush(SCENE_VERSION_TAG_RESET); - eventHandler.waitForFlush(scene_->getSceneId(), SCENE_VERSION_TAG_RESET); - + if (!eventHandler.waitForFlush(scene_->getSceneId(), SCENE_VERSION_TAG_RESET)) { + return ramses::dataConsumerId_t::Invalid(); + } return framebufferSampleId_; } diff --git a/gui/libRamsesWidgets/src/PreviewMainWindow.cpp b/gui/libRamsesWidgets/src/PreviewMainWindow.cpp index e46c1546..69eec3b4 100644 --- a/gui/libRamsesWidgets/src/PreviewMainWindow.cpp +++ b/gui/libRamsesWidgets/src/PreviewMainWindow.cpp @@ -36,9 +36,11 @@ PreviewMainWindow::PreviewMainWindow(RendererBackend& rendererBackend, ramses_ad ui_->setupUi(this); sceneIdLabel_ = new QLabel{"scene id: -", ui_->statusbar}; + errorLabel_ = new QLabel{"Status", ui_->statusbar}; auto* pixelLabel = new QLabel{"x: - y: -", ui_->statusbar}; auto* scaleLabel = new QLabel{"scale: 1.0", ui_->statusbar}; ui_->statusbar->addWidget(sceneIdLabel_); + ui_->statusbar->addWidget(errorLabel_); ui_->statusbar->addPermanentWidget(pixelLabel); ui_->statusbar->addPermanentWidget(scaleLabel); @@ -68,6 +70,10 @@ PreviewMainWindow::PreviewMainWindow(RendererBackend& rendererBackend, ramses_ad } }); + connect(previewWidget_, &PreviewContentWidget::newPreviewState, [this](bool status) { + errorLabel_->setText(QString("Status: ") + QString(status ? "OK" : "ERROR")); + }); + // Size mode tool button { auto* sizeMenu = new QMenu{ui_->toolBar}; diff --git a/gui/libRamsesWidgets/src/PreviewScrollAreaWidget.cpp b/gui/libRamsesWidgets/src/PreviewScrollAreaWidget.cpp index a465a19e..6131a18c 100644 --- a/gui/libRamsesWidgets/src/PreviewScrollAreaWidget.cpp +++ b/gui/libRamsesWidgets/src/PreviewScrollAreaWidget.cpp @@ -185,10 +185,9 @@ QSize PreviewScrollAreaWidget::scaledSize() const noexcept { return sceneSize_ * scaleValue_; } -void PreviewScrollAreaWidget::setViewport(const QSize& sceneSize) { - QSize size = sceneSize.boundedTo({4096, 4096}).expandedTo({1, 1}); - if (sceneSize_ != size) { - sceneSize_ = size; +void PreviewScrollAreaWidget::setViewport(const QSize& newSize) { + if (sceneSize_ != newSize) { + sceneSize_ = newSize; updateViewport(); } } diff --git a/gui/libRamsesWidgets/src/RamsesAbstractViewWindow.cpp b/gui/libRamsesWidgets/src/RamsesAbstractViewWindow.cpp index f5f78171..40c21e2b 100644 --- a/gui/libRamsesWidgets/src/RamsesAbstractViewWindow.cpp +++ b/gui/libRamsesWidgets/src/RamsesAbstractViewWindow.cpp @@ -20,7 +20,7 @@ namespace { using namespace raco::ramses_widgets; -void setAndWaitSceneState( +[[nodiscard]] bool setAndWaitSceneState( RendererBackend& backend, const ramses::RendererSceneState state, const ramses::sceneId_t sceneId) { @@ -29,15 +29,16 @@ void setAndWaitSceneState( if (sceneId.isValid()) { auto status = sceneControlAPI.setSceneState(sceneId, state); if (sceneControlAPI.flush()) { - backend.eventHandler().waitForSceneState(sceneId, state); + return backend.eventHandler().waitForSceneState(sceneId, state); } } + return true; } /** * Sets and await's current scene state for frambuffer and conditionally for scene. The scene state is only set if the current scene state is greater than the request scene state. */ -void reduceAndWaitSceneState( +[[nodiscard]] bool reduceAndWaitSceneState( RendererBackend& backend, const ramses::RendererSceneState state, const ramses::sceneId_t sceneId) { @@ -54,9 +55,10 @@ void reduceAndWaitSceneState( // leads to the scene state comparison above being true which triggers a setSceneState which then has no effect since the // real state is already lower than the set state which leads to no callback being invoked which leads to waiting forever // of using an exact scene state comparison. - backend.eventHandler().waitForSceneState(sceneId, state, SceneStateEventHandler::ECompareFunc::LessEqual); + return backend.eventHandler().waitForSceneState(sceneId, state, SceneStateEventHandler::ECompareFunc::LessEqual); } } + return true; } } // namespace @@ -72,11 +74,11 @@ RamsesAbstractViewWindow::~RamsesAbstractViewWindow() { } void RamsesAbstractViewWindow::reset() { - reduceAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Available, current_.sceneId); + auto status = reduceAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Available, current_.sceneId); if (displayId_.isValid()) { rendererBackend_.renderer().destroyDisplay(displayId_); rendererBackend_.renderer().flush(); - rendererBackend_.eventHandler().waitForDisplayDestruction(displayId_); + auto status = rendererBackend_.eventHandler().waitForDisplayDestruction(displayId_); displayId_ = ramses::displayId_t::Invalid(); current_ = State{}; } @@ -91,6 +93,10 @@ RamsesAbstractViewWindow::State& RamsesAbstractViewWindow::nextState() { } void RamsesAbstractViewWindow::commit(bool forceUpdate) { + if (errorState_ && !forceUpdate) { + return; + } + if (forceUpdate || !displayId_.isValid() || next_ != current_) { // Unload current scenes reset(); @@ -112,13 +118,19 @@ void RamsesAbstractViewWindow::commit(bool forceUpdate) { } displayId_ = rendererBackend_.renderer().createDisplay(displayConfig); rendererBackend_.renderer().flush(); - rendererBackend_.eventHandler().waitForDisplayCreation(displayId_); + if (!rendererBackend_.eventHandler().waitForDisplayCreation(displayId_)) { + errorState_ = true; + return; + } if (next_.sceneId.isValid()) { /// @todo maybe we need to reset old scene mapping? sceneControlAPI.setSceneMapping(next_.sceneId, displayId_); sceneControlAPI.flush(); - setAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Rendered, next_.sceneId); + if (!setAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Rendered, next_.sceneId)) { + errorState_ = true; + return; + } } current_ = next_; diff --git a/gui/libRamsesWidgets/src/RamsesPreviewWindow.cpp b/gui/libRamsesWidgets/src/RamsesPreviewWindow.cpp index 3898e5aa..6a7331df 100644 --- a/gui/libRamsesWidgets/src/RamsesPreviewWindow.cpp +++ b/gui/libRamsesWidgets/src/RamsesPreviewWindow.cpp @@ -23,7 +23,7 @@ namespace { using namespace raco::ramses_widgets; -void setAndWaitSceneState( +[[nodiscard]] bool setAndWaitSceneState( RendererBackend& backend, const ramses::RendererSceneState state, const std::unique_ptr& framebufferScene, @@ -47,19 +47,21 @@ void setAndWaitSceneState( } sceneControlAPI.flush(); - + + auto status = true; if (fb_success) { - backend.eventHandler().waitForSceneState(framebufferScene->getSceneId(), state); + status = backend.eventHandler().waitForSceneState(framebufferScene->getSceneId(), state) || status; } if (scene_success) { - backend.eventHandler().waitForSceneState(sceneId, state); + status = backend.eventHandler().waitForSceneState(sceneId, state) || status; } + return status; } /** * Sets and await's current scene state for frambuffer and conditionally for scene. The scene state is only set if the current scene state is greater than the request scene state. */ -void reduceAndWaitSceneState( +[[nodiscard]] bool reduceAndWaitSceneState( RendererBackend& backend, const ramses::RendererSceneState state, const std::unique_ptr& framebufferScene, @@ -89,12 +91,15 @@ void reduceAndWaitSceneState( // leads to the scene state comparison above being true which triggers a setSceneState which then has no effect since the // real state is already lower than the set state which leads to no callback being invoked which leads to waiting forever // of using an exact scene state comparison. + bool status = true; if (fb_success) { - backend.eventHandler().waitForSceneState(framebufferScene->getSceneId(), state, SceneStateEventHandler::ECompareFunc::LessEqual); + status = backend.eventHandler().waitForSceneState(framebufferScene->getSceneId(), state, SceneStateEventHandler::ECompareFunc::LessEqual) || status; + } if (scene_success) { - backend.eventHandler().waitForSceneState(sceneId, state, SceneStateEventHandler::ECompareFunc::LessEqual); + status = backend.eventHandler().waitForSceneState(sceneId, state, SceneStateEventHandler::ECompareFunc::LessEqual) || status; } + return status; } } // namespace @@ -108,16 +113,16 @@ RamsesPreviewWindow::RamsesPreviewWindow( } RamsesPreviewWindow::~RamsesPreviewWindow() { - reduceAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Available, framebufferScene_, current_.sceneId); + auto status = reduceAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Available, framebufferScene_, current_.sceneId); if (offscreenBufferId_.isValid()) { rendererBackend_.renderer().destroyOffscreenBuffer(displayId_, offscreenBufferId_); rendererBackend_.renderer().flush(); - rendererBackend_.eventHandler().waitForOffscreenBufferDestruction(offscreenBufferId_); + auto status = rendererBackend_.eventHandler().waitForOffscreenBufferDestruction(offscreenBufferId_); } if (displayId_.isValid()) { rendererBackend_.renderer().destroyDisplay(displayId_); rendererBackend_.renderer().flush(); - rendererBackend_.eventHandler().waitForDisplayDestruction(displayId_); + auto status = rendererBackend_.eventHandler().waitForDisplayDestruction(displayId_); } } @@ -142,22 +147,27 @@ RamsesPreviewWindow::State& RamsesPreviewWindow::nextState() { return next_; } -void RamsesPreviewWindow::commit(bool forceUpdate) { - if (forceUpdate || !displayId_.isValid() || next_.viewportSize != current_.viewportSize || next_.sceneId != current_.sceneId || next_.targetSize != current_.targetSize || next_.sampleRate != current_.sampleRate || next_.filteringMode != current_.filteringMode) { +bool RamsesPreviewWindow::errorState() { + return errorState_; +} + +bool RamsesPreviewWindow::commit(bool forceUpdate) { + if (errorState_ && !forceUpdate) { + return false; + } + + if (forceUpdate || !displayId_.isValid() || next_.sceneId != current_.sceneId || next_.targetSize != current_.targetSize || next_.sampleRate != current_.sampleRate || next_.filteringMode != current_.filteringMode) { // Unload current scenes - reduceAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Available, framebufferScene_, current_.sceneId); + if (!reduceAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Available, framebufferScene_, current_.sceneId)) { + errorState_ = true; + return false; + } if (next_.viewportSize.width() > 0 && next_.viewportSize.height() > 0 || next_.sampleRate != current_.sampleRate || next_.filteringMode != current_.filteringMode) { auto& sceneControlAPI = *rendererBackend_.renderer().getSceneControlAPI(); if (!displayId_.isValid()) { ramses::DisplayConfig displayConfig = {}; - /// @todo maybe this setWindowRectangle is not needed? - constexpr auto displayX = 100; - constexpr auto displayY = 100; - displayConfig.setWindowRectangle(displayX, displayY, next_.viewportSize.width(), next_.viewportSize.height()); - glm::vec4 clearColor{0.25, 0.25, 0.25, 1.0}; - displayConfig.setClearColor(clearColor); displayConfig.setWindowIviVisible(); if constexpr (!BuildOptions::nativeRamsesDisplayWindow) { #if (defined(__WIN32) || defined(_WIN32)) @@ -167,9 +177,21 @@ void RamsesPreviewWindow::commit(bool forceUpdate) { #endif } displayId_ = rendererBackend_.renderer().createDisplay(displayConfig); + if (displayId_ == ramses::displayId_t::Invalid()) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "Ramses display creation failed."); + errorState_ = true; + return false; + } rendererBackend_.renderer().flush(); - rendererBackend_.eventHandler().waitForDisplayCreation(displayId_); - sceneControlAPI.setSceneMapping(framebufferScene_->getSceneId(), displayId_); + if (!rendererBackend_.eventHandler().waitForDisplayCreation(displayId_)) { + errorState_ = true; + return false; + } + if (!sceneControlAPI.setSceneMapping(framebufferScene_->getSceneId(), displayId_)) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "Framebuffer scene setSceneMapping failed with '{}'.", rendererBackend_.framework().getLastError().value().message); + errorState_ = true; + return false; + } } current_.viewportSize = next_.viewportSize; current_.sampleRate = next_.sampleRate; @@ -177,9 +199,16 @@ void RamsesPreviewWindow::commit(bool forceUpdate) { if (next_.sceneId.isValid()) { /// @todo maybe we need to reset old scene mapping? - sceneControlAPI.setSceneMapping(next_.sceneId, displayId_); + if (!sceneControlAPI.setSceneMapping(next_.sceneId, displayId_)) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "User scene setSceneMapping failed with '{}'.", rendererBackend_.framework().getLastError().value().message); + errorState_ = true; + return false; + } + } + if (!setAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Ready, framebufferScene_, next_.sceneId)) { + errorState_ = true; + return false; } - setAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Ready, framebufferScene_, next_.sceneId); // Set up the render buffer we use as a default framebuffer. // This is not a normal Ramses render target / render buffer created with Scene::createRenderBuffer / Scene::createRenderTarget @@ -187,23 +216,51 @@ void RamsesPreviewWindow::commit(bool forceUpdate) { // offscreen render buffer in the scene we eventually export (and in fact for Ramses this offscreen render buffer is // the framebuffer - that we use it later on to blit it into our preview makes for the Ramses scene no difference). const ramses::dataConsumerId_t dataConsumerId = framebufferScene_->setupFramebufferTexture(rendererBackend_, next_.targetSize, next_.filteringMode, next_.sampleRate); + if (dataConsumerId == ramses::dataConsumerId_t::Invalid()) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "Creating framebuffer texture failed."); + errorState_ = true; + return false; + } + offscreenBufferId_ = rendererBackend_.renderer().createOffscreenBuffer(displayId_, next_.targetSize.width(), next_.targetSize.height(), next_.sampleRate); + if (offscreenBufferId_ == ramses::displayBufferId_t::Invalid()) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "Creating offscreen buffer failed."); + errorState_ = true; + return false; + } rendererBackend_.renderer().setDisplayBufferClearColor(displayId_, offscreenBufferId_, {next_.backgroundColor.redF(), next_.backgroundColor.greenF(), next_.backgroundColor.blueF(), next_.backgroundColor.alphaF()}); rendererBackend_.renderer().flush(); - rendererBackend_.eventHandler().waitForOffscreenBufferCreation(offscreenBufferId_); + if (!rendererBackend_.eventHandler().waitForOffscreenBufferCreation(offscreenBufferId_)) { + errorState_ = true; + return false; + } current_.targetSize = next_.targetSize; current_.backgroundColor = next_.backgroundColor; if (next_.sceneId.isValid()) { - sceneControlAPI.setSceneDisplayBufferAssignment(next_.sceneId, offscreenBufferId_); + if (!sceneControlAPI.setSceneDisplayBufferAssignment(next_.sceneId, offscreenBufferId_)) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "setSceneDisplayBufferAssignment failed with '{}'.", rendererBackend_.framework().getLastError().value().message); + errorState_ = true; + return false; + } } sceneControlAPI.flush(); - sceneControlAPI.linkOffscreenBuffer(offscreenBufferId_, framebufferScene_->getSceneId(), dataConsumerId); + if (!sceneControlAPI.linkOffscreenBuffer(offscreenBufferId_, framebufferScene_->getSceneId(), dataConsumerId)) { + LOG_ERROR(log_system::PREVIEW_WIDGET, "linkOffscreenBuffer failed with '{}'.", rendererBackend_.framework().getLastError().value().message); + errorState_ = true; + return false; + } sceneControlAPI.flush(); - rendererBackend_.eventHandler().waitForOffscreenBufferLinked(offscreenBufferId_); + if (!rendererBackend_.eventHandler().waitForOffscreenBufferLinked(offscreenBufferId_)) { + errorState_ = true; + return false; + } - setAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Rendered, framebufferScene_, next_.sceneId); + if (!setAndWaitSceneState(rendererBackend_, ramses::RendererSceneState::Rendered, framebufferScene_, next_.sceneId)) { + errorState_ = true; + return false; + } current_.sceneId = next_.sceneId; LOG_DEBUG(PREVIEW_WIDGET, "commit() sceneId {}", current_.sceneId); } @@ -215,12 +272,16 @@ void RamsesPreviewWindow::commit(bool forceUpdate) { current_.backgroundColor = next_.backgroundColor; } + current_.viewportSize = next_.viewportSize; current_.viewportOffset = next_.viewportOffset; current_.virtualSize = next_.virtualSize; if (current_.viewportSize.width() > 0 && current_.viewportSize.height() > 0) { framebufferScene_->setViewport(current_.viewportOffset, current_.viewportSize, current_.virtualSize); } + + errorState_ = false; + return true; } } // namespace raco::ramses_widgets diff --git a/gui/libRamsesWidgets/src/SceneStateEventHandler.cpp b/gui/libRamsesWidgets/src/SceneStateEventHandler.cpp index 0fe0d7d7..614b229b 100644 --- a/gui/libRamsesWidgets/src/SceneStateEventHandler.cpp +++ b/gui/libRamsesWidgets/src/SceneStateEventHandler.cpp @@ -76,8 +76,8 @@ void SceneStateEventHandler::sceneFlushed(ramses::sceneId_t sceneId, ramses::sce scenes_[sceneId].version = sceneVersion; } -void SceneStateEventHandler::waitForSceneState(ramses::sceneId_t sceneId, ramses::RendererSceneState state, ECompareFunc compFunc) { - waitUntilOrTimeout([this, sceneId, state, compFunc] { +bool SceneStateEventHandler::waitForSceneState(ramses::sceneId_t sceneId, ramses::RendererSceneState state, ECompareFunc compFunc) { + return waitUntilOrTimeout([this, sceneId, state, compFunc] { switch (compFunc) { case ECompareFunc::LessEqual: return scenes_[sceneId].state <= state; @@ -88,7 +88,8 @@ void SceneStateEventHandler::waitForSceneState(ramses::sceneId_t sceneId, ramses default: return false; } - }); + }, + fmt::format("waitForSceneState '{}' of scene '{}' with comparison '{}'", state, sceneId, compFunc)); } void SceneStateEventHandler::objectsPicked(ramses::sceneId_t sceneId, const ramses::pickableObjectId_t* pickedObjects, size_t pickedObjectsCount) { @@ -104,46 +105,56 @@ void SceneStateEventHandler::objectsPicked(ramses::sceneId_t sceneId, const rams } bool SceneStateEventHandler::waitForFlush(ramses::sceneId_t sceneId, ramses::sceneVersionTag_t sceneVersion) { - return waitUntilOrTimeout([&] { return scenes_[sceneId].version == sceneVersion; }); + return waitUntilOrTimeout([&] { return scenes_[sceneId].version == sceneVersion; }, + fmt::format("waitForFlush: sceneId = {}", sceneId)); } bool SceneStateEventHandler::waitForDisplayCreation(ramses::displayId_t displayId) { - return waitUntilOrTimeout([&] { return displays_.find(displayId) != displays_.end(); }); + return waitUntilOrTimeout([&] { return displays_.find(displayId) != displays_.end(); }, + fmt::format("waitForDisplayCreation: displayId = {}", displayId)); } bool SceneStateEventHandler::waitForDisplayDestruction(ramses::displayId_t displayId) { - return waitUntilOrTimeout([&] { return displays_.find(displayId) == displays_.end(); }); + return waitUntilOrTimeout([&] { return displays_.find(displayId) == displays_.end(); }, + fmt::format("waitForDisplayDestruction: displayId = {}", displayId)); } bool SceneStateEventHandler::waitForOffscreenBufferCreation(ramses::displayBufferId_t displayBufferId) { - return waitUntilOrTimeout([&] { return offscreenBuffers_.find(displayBufferId) != offscreenBuffers_.end(); }); + return waitUntilOrTimeout([&] { return offscreenBuffers_.find(displayBufferId) != offscreenBuffers_.end(); }, + fmt::format("waitForOffscreenBufferCreation: bufferId = {}", displayBufferId)); } bool SceneStateEventHandler::waitForOffscreenBufferDestruction(ramses::displayBufferId_t displayBufferId) { - return waitUntilOrTimeout([&] { return offscreenBuffers_.find(displayBufferId) == offscreenBuffers_.end(); }); + return waitUntilOrTimeout([&] { return offscreenBuffers_.find(displayBufferId) == offscreenBuffers_.end(); }, + fmt::format("waitForOffscreenBufferDestruction: bufferId = {}", displayBufferId)); } bool SceneStateEventHandler::waitForOffscreenBufferLinked(ramses::displayBufferId_t displayBufferId) { - return waitUntilOrTimeout([&] { return linkedOffscreenBuffers_.find(displayBufferId) == linkedOffscreenBuffers_.end(); }); + return waitUntilOrTimeout([&] { return linkedOffscreenBuffers_.find(displayBufferId) == linkedOffscreenBuffers_.end(); }, + fmt::format("waitForOffscreenBufferLinked: bufferId = {}", displayBufferId)); } -bool SceneStateEventHandler::waitUntilOrTimeout(const std::function& conditionFunction) { - const std::chrono::steady_clock::time_point timeoutTS = std::chrono::steady_clock::now() + std::chrono::seconds{5}; +bool SceneStateEventHandler::waitUntilOrTimeout(const std::function& conditionFunction, const std::string& actionDescription) { + const std::chrono::steady_clock::time_point timeoutTS = std::chrono::steady_clock::now() + std::chrono::seconds{30}; while (!conditionFunction()) { if (std::chrono::steady_clock::now() > timeoutTS) { - throw std::runtime_error{"Something went wrong"}; + LOG_ERROR(log_system::PREVIEW_WIDGET, "Timeout waiting for: {}", actionDescription); + return false; } std::this_thread::sleep_for(std::chrono::milliseconds{5}); renderer_.doOneLoop(); renderer_.dispatchEvents(*this); renderer_.getSceneControlAPI()->dispatchEvents(*this); } + LOG_TRACE(RAMSES_BACKEND, "Completed wait for {}", actionDescription); return conditionFunction(); } bool SceneStateEventHandler::waitForScreenshot() { - waitUntilOrTimeout([&] { return screenshot_.empty(); }); - return screenshotSaved_; + if (waitUntilOrTimeout([&] { return screenshot_.empty(); }, "waitForScreenshot")) { + return screenshotSaved_; + } + return false; } ramses::RendererSceneState SceneStateEventHandler::sceneState(ramses::sceneId_t sceneId) { diff --git a/gui/libStyle/include/style/Colors.h b/gui/libStyle/include/style/Colors.h index 7564d6ef..05afa9c2 100644 --- a/gui/libStyle/include/style/Colors.h +++ b/gui/libStyle/include/style/Colors.h @@ -25,6 +25,12 @@ enum class Colormap { grayEditDisabled, textDisabled, + // additional colors for text editors + textHighlightIndentation, + textHighlightComments, + textHighlightNumbers, + textHighlightArrows, + // additional colors for custom widgets and custom roles/states updatedInBackground, errorColor, diff --git a/gui/libStyle/include/style/Icons.h b/gui/libStyle/include/style/Icons.h index 71d0176e..203e7ce3 100644 --- a/gui/libStyle/include/style/Icons.h +++ b/gui/libStyle/include/style/Icons.h @@ -57,6 +57,8 @@ class Icons { const QIcon typeAnimationChannel{":typeAnimationChannelIcon"}; const QIcon typeAnimation{":typeAnimationIcon"}; const QIcon typeTimer{":typeTimerIcon"}; + const QIcon typeRenderLayer{":typeRenderLayerIcon"}; + const QIcon typeRenderTarget{":typeRenderTargetIcon"}; const QIcon browse{":browseIcon"}; const QIcon info{":infoIcon"}; const QIcon refresh{":refreshIcon"}; @@ -67,6 +69,9 @@ class Icons { const QIcon playActive{":playActiveIcon"}; const QIcon pauseInactive{":pauseInactiveIcon"}; const QIcon pauseActive{":pauseActiveIcon"}; + const QIcon recordInactive{":recordInactiveIcon"}; + const QIcon recordActive{":recordActiveIcon"}; + const QIcon stop{":stopIcon"}; const QIcon stopInactive{":stopInactiveIcon"}; const QIcon stopActive{":stopActiveIcon"}; const QIcon skipNext{":skipNextIcon"}; @@ -81,6 +86,7 @@ class Icons { const QIcon visibilityOff{makeDisabled(":visibilityOffIcon")}; const QIcon abstractSceneView{":abstractSceneViewIcon"}; const QIcon prefabLookup{":prefabLookupIcon"}; + const QIcon label{":labelIcon"}; static const Icons &instance(); static QIcon makeDisabled(const QString &name); diff --git a/gui/libStyle/src/Colors.cpp b/gui/libStyle/src/Colors.cpp index 26517272..ac1b7abd 100644 --- a/gui/libStyle/src/Colors.cpp +++ b/gui/libStyle/src/Colors.cpp @@ -21,6 +21,12 @@ Colors::Colors() noexcept { {Colormap::grayEditDisabled, QColor(30, 30, 30)}, {Colormap::textDisabled, QColor(200, 200, 200)}, + //additional colors for text editors + {Colormap::textHighlightIndentation, QColor(127, 127, 127)}, + {Colormap::textHighlightComments, QColor(63, 200, 63)}, + {Colormap::textHighlightNumbers, QColor(255, 127, 63)}, + {Colormap::textHighlightArrows, QColor(63, 210, 255)}, + // additional colors for custom widgets and custom roles/states {Colormap::updatedInBackground, QColor(45, 100, 150)}, {Colormap::warningColor, QColor(170, 100, 30)}, diff --git a/resources/export-raco-error-ramses-ok.rca b/resources/export-raco-error-ramses-ok.rca new file mode 100644 index 00000000..5ee43193 --- /dev/null +++ b/resources/export-raco-error-ramses-ok.rca @@ -0,0 +1,1291 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2003, + "instances": [ + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "95cab398-a32d-4a12-997f-19e93a827ec1", + "objectName": "export-raco-warning-ramses-ok", + "pythonOnSaveScript": "", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "children": [ + "f9d19011-d177-428a-90c2-11c49fb54f55" + ], + "enabled": true, + "objectID": "5fc6eae8-74dd-475c-9e0c-3853fbb3cd68", + "objectName": "Node", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "tags": { + "properties": [ + { + "typeName": "String", + "value": "render_main" + } + ] + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "Node" + }, + { + "properties": { + "enabled": true, + "frustum": { + "order": [ + "nearPlane", + "farPlane", + "fieldOfView", + "aspectRatio" + ], + "properties": { + "aspectRatio": { + "annotations": [ + { + "properties": { + "name": "aspectRatio" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 4, + "min": 0.5 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 2 + }, + "farPlane": { + "annotations": [ + { + "properties": { + "name": "farPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 10000, + "min": 100 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 1000 + }, + "fieldOfView": { + "annotations": [ + { + "properties": { + "name": "fieldOfView" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 120, + "min": 10 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 35 + }, + "nearPlane": { + "annotations": [ + { + "properties": { + "name": "nearPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 1, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 0.1 + } + } + }, + "frustumType": 0, + "objectID": "c439665e-bfc5-4984-a290-c643fec05fd3", + "objectName": "PerspectiveCamera", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 10 + } + }, + "viewport": { + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + }, + "offsetX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "offsetY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + } + }, + "visibility": true + }, + "typeName": "PerspectiveCamera" + }, + { + "properties": { + "camera": "c439665e-bfc5-4984-a290-c643fec05fd3", + "clearColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "enableClearColor": true, + "enableClearDepth": true, + "enableClearStencil": true, + "enabled": true, + "layers": [ + "e4aea168-73d5-4368-b6b9-915f8cd278ec" + ], + "objectID": "23d00c7c-88f1-4290-a5a3-e46b48f087d6", + "objectName": "MainRenderPass", + "renderOnce": false, + "renderOrder": 1, + "target": null + }, + "typeName": "RenderPass" + }, + { + "properties": { + "anisotropy": { + "annotations": [ + { + "properties": { + "max": 32000, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "flipTexture": false, + "generateMipmaps": false, + "level2uri": "", + "level3uri": "", + "level4uri": "", + "magSamplingMethod": 0, + "minSamplingMethod": 0, + "mipmapLevel": { + "annotations": [ + { + "properties": { + "max": 4, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "objectID": "d8665539-2da5-4b2c-b6bc-25b7d7f375aa", + "objectName": "Texture", + "textureFormat": 5, + "uri": "nosuchfile", + "wrapUMode": 0, + "wrapVMode": 0 + }, + "typeName": "Texture" + }, + { + "properties": { + "materialFilterMode": 1, + "objectID": "e4aea168-73d5-4368-b6b9-915f8cd278ec", + "objectName": "MainRenderLayer", + "renderableTags": { + "order": [ + "render_main" + ], + "properties": { + "render_main": { + "annotations": [ + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int::LinkEndAnnotation", + "value": 0 + } + } + }, + "sortOrder": 0 + }, + "typeName": "RenderLayer" + }, + { + "properties": { + "enabled": true, + "instanceCount": { + "annotations": [ + { + "properties": { + "max": 20, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": -1 + }, + "mesh": null, + "objectID": "f9d19011-d177-428a-90c2-11c49fb54f55", + "objectName": "MeshNode", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "MeshNode" + } + ], + "links": [ + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/resources/export-raco-ok-ramses-error.rca b/resources/export-raco-ok-ramses-error.rca new file mode 100644 index 00000000..bbbb0194 --- /dev/null +++ b/resources/export-raco-ok-ramses-error.rca @@ -0,0 +1,2251 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2003, + "instances": [ + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "36be3c73-97ea-4dd6-88a2-2ce96d68423c", + "objectName": "export-raco-ok-ramses-error", + "pythonOnSaveScript": "", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "children": [ + "b11009a9-56d7-48d5-9515-7d8a9d697f14" + ], + "enabled": true, + "objectID": "b774854d-67f6-409e-9878-527f2fa3f4c3", + "objectName": "Node", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "tags": { + "properties": [ + { + "typeName": "String", + "value": "render_main" + } + ] + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "Node" + }, + { + "properties": { + "enabled": true, + "frustum": { + "order": [ + "nearPlane", + "farPlane", + "fieldOfView", + "aspectRatio" + ], + "properties": { + "aspectRatio": { + "annotations": [ + { + "properties": { + "name": "aspectRatio" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 4, + "min": 0.5 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 2 + }, + "farPlane": { + "annotations": [ + { + "properties": { + "name": "farPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 10000, + "min": 100 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 1000 + }, + "fieldOfView": { + "annotations": [ + { + "properties": { + "name": "fieldOfView" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 120, + "min": 10 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 35 + }, + "nearPlane": { + "annotations": [ + { + "properties": { + "name": "nearPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 1, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 0.1 + } + } + }, + "frustumType": 0, + "objectID": "a506fb5c-b410-4137-b035-0a0ef25d50bb", + "objectName": "PerspectiveCamera", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 10 + } + }, + "viewport": { + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + }, + "offsetX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "offsetY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + } + }, + "visibility": true + }, + "typeName": "PerspectiveCamera" + }, + { + "properties": { + "inputs": { + "order": [ + "bool", + "float", + "integer", + "integer64", + "string", + "vector2f", + "vector2i", + "vector3f", + "vector3i", + "vector4f", + "vector4i" + ], + "properties": { + "bool": { + "annotations": [ + { + "properties": { + "engineType": 1 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Bool::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": false + }, + "float": { + "annotations": [ + { + "properties": { + "engineType": 5 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": 0 + }, + "integer": { + "annotations": [ + { + "properties": { + "engineType": 2 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": 0 + }, + "integer64": { + "annotations": [ + { + "properties": { + "engineType": 18 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int64::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": "0" + }, + "string": { + "annotations": [ + { + "properties": { + "engineType": 6 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "String::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": "" + }, + "vector2f": { + "annotations": [ + { + "properties": { + "engineType": 7 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Vec2f::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector2i": { + "annotations": [ + { + "properties": { + "engineType": 10 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "i1": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + } + }, + "typeName": "Vec2i::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector3f": { + "annotations": [ + { + "properties": { + "engineType": 8 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Vec3f::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector3i": { + "annotations": [ + { + "properties": { + "engineType": 11 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "i1": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i3": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + } + }, + "typeName": "Vec3i::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector4f": { + "annotations": [ + { + "properties": { + "engineType": 9 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Vec4f::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector4i": { + "annotations": [ + { + "properties": { + "engineType": 12 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "i1": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i3": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i4": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + } + }, + "typeName": "Vec4i::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + } + } + }, + "objectID": "ec568812-21d8-4d65-8a36-aaf646634fd4", + "objectName": "LuaInterface", + "stdModules": { + "base": true, + "debug": true, + "math": true, + "string": true, + "table": true + }, + "uri": "scripts/interface-scalar-types.lua" + }, + "typeName": "LuaInterface" + }, + { + "properties": { + "inputs": { + "order": [ + "bool", + "float", + "integer", + "integer64", + "string", + "vector2f", + "vector2i", + "vector3f", + "vector3i", + "vector4f", + "vector4i" + ], + "properties": { + "bool": { + "annotations": [ + { + "properties": { + "engineType": 1 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Bool::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": false + }, + "float": { + "annotations": [ + { + "properties": { + "engineType": 5 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": 0 + }, + "integer": { + "annotations": [ + { + "properties": { + "engineType": 2 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": 0 + }, + "integer64": { + "annotations": [ + { + "properties": { + "engineType": 18 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int64::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": "0" + }, + "string": { + "annotations": [ + { + "properties": { + "engineType": 6 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "String::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "value": "" + }, + "vector2f": { + "annotations": [ + { + "properties": { + "engineType": 7 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Vec2f::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector2i": { + "annotations": [ + { + "properties": { + "engineType": 10 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "i1": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + } + }, + "typeName": "Vec2i::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector3f": { + "annotations": [ + { + "properties": { + "engineType": 8 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Vec3f::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector3i": { + "annotations": [ + { + "properties": { + "engineType": 11 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "i1": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i3": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + } + }, + "typeName": "Vec3i::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector4f": { + "annotations": [ + { + "properties": { + "engineType": 9 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "typeName": "Vec4f::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + }, + "vector4i": { + "annotations": [ + { + "properties": { + "engineType": 12 + }, + "typeName": "EngineTypeAnnotation" + }, + { + "typeName": "LinkStartAnnotation" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "properties": { + "i1": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i3": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "i4": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + } + }, + "typeName": "Vec4i::EngineTypeAnnotation::LinkStartAnnotation::LinkEndAnnotation" + } + } + }, + "objectID": "0d8174a4-80f3-4d8b-a880-c78fce57e7ad", + "objectName": "LuaInterface", + "stdModules": { + "base": true, + "debug": true, + "math": true, + "string": true, + "table": true + }, + "uri": "scripts/interface-scalar-types.lua" + }, + "typeName": "LuaInterface" + }, + { + "properties": { + "camera": "a506fb5c-b410-4137-b035-0a0ef25d50bb", + "clearColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "enableClearColor": true, + "enableClearDepth": true, + "enableClearStencil": true, + "enabled": true, + "layers": [ + "e31d975f-e94d-4610-9958-44aad9d6f933" + ], + "objectID": "434c3eaa-2d1a-4ae3-9a30-6cba77d04240", + "objectName": "MainRenderPass", + "renderOnce": false, + "renderOrder": 1, + "target": null + }, + "typeName": "RenderPass" + }, + { + "properties": { + "enabled": true, + "instanceCount": { + "annotations": [ + { + "properties": { + "max": 20, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": -1 + }, + "mesh": null, + "objectID": "b11009a9-56d7-48d5-9515-7d8a9d697f14", + "objectName": "MeshNode", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "MeshNode" + }, + { + "properties": { + "materialFilterMode": 1, + "objectID": "e31d975f-e94d-4610-9958-44aad9d6f933", + "objectName": "MainRenderLayer", + "renderableTags": { + "order": [ + "render_main" + ], + "properties": { + "render_main": { + "annotations": [ + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int::LinkEndAnnotation", + "value": 0 + } + } + }, + "sortOrder": 0 + }, + "typeName": "RenderLayer" + } + ], + "links": [ + { + "properties": { + "endObject": "b774854d-67f6-409e-9878-527f2fa3f4c3", + "endProp": [ + "rotation" + ], + "isValid": true, + "isWeak": false, + "startObject": "0d8174a4-80f3-4d8b-a880-c78fce57e7ad", + "startProp": [ + "inputs", + "vector3f" + ] + }, + "typeName": "Link" + }, + { + "properties": { + "endObject": "b774854d-67f6-409e-9878-527f2fa3f4c3", + "endProp": [ + "translation" + ], + "isValid": true, + "isWeak": false, + "startObject": "ec568812-21d8-4d65-8a36-aaf646634fd4", + "startProp": [ + "inputs", + "vector3f" + ] + }, + "typeName": "Link" + } + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/resources/export-raco-ok-ramses-warning.rca b/resources/export-raco-ok-ramses-warning.rca new file mode 100644 index 00000000..6856f0ec --- /dev/null +++ b/resources/export-raco-ok-ramses-warning.rca @@ -0,0 +1,1249 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2003, + "instances": [ + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "9d96e356-5adf-4372-96e8-c1a343e6b881", + "objectName": "export-raco-ok-ramses-warning", + "pythonOnSaveScript": "", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "children": [ + "173e0e9e-d1c2-4b84-b112-9da495b12554" + ], + "enabled": true, + "objectID": "7ba65daf-75de-4d38-92bc-1c4e6dd78ae5", + "objectName": "Node", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "tags": { + "properties": [ + { + "typeName": "String", + "value": "render_main" + } + ] + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "Node" + }, + { + "properties": { + "enabled": true, + "frustum": { + "order": [ + "nearPlane", + "farPlane", + "fieldOfView", + "aspectRatio" + ], + "properties": { + "aspectRatio": { + "annotations": [ + { + "properties": { + "name": "aspectRatio" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 4, + "min": 0.5 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 2 + }, + "farPlane": { + "annotations": [ + { + "properties": { + "name": "farPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 10000, + "min": 100 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 1000 + }, + "fieldOfView": { + "annotations": [ + { + "properties": { + "name": "fieldOfView" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 120, + "min": 10 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 35 + }, + "nearPlane": { + "annotations": [ + { + "properties": { + "name": "nearPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 1, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 0.1 + } + } + }, + "frustumType": 0, + "objectID": "cf444201-b7ae-4aaf-aa98-78e3222dae48", + "objectName": "PerspectiveCamera", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 10 + } + }, + "viewport": { + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + }, + "offsetX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "offsetY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + } + }, + "visibility": true + }, + "typeName": "PerspectiveCamera" + }, + { + "properties": { + "materialFilterMode": 1, + "objectID": "167c344a-5156-4ab5-ad1a-376c97ff844e", + "objectName": "MainRenderLayer", + "renderableTags": { + "order": [ + "render_main" + ], + "properties": { + "render_main": { + "annotations": [ + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int::LinkEndAnnotation", + "value": 0 + } + } + }, + "sortOrder": 0 + }, + "typeName": "RenderLayer" + }, + { + "properties": { + "enabled": true, + "instanceCount": { + "annotations": [ + { + "properties": { + "max": 20, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": -1 + }, + "mesh": null, + "objectID": "173e0e9e-d1c2-4b84-b112-9da495b12554", + "objectName": "MeshNode", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "MeshNode" + }, + { + "properties": { + "camera": "cf444201-b7ae-4aaf-aa98-78e3222dae48", + "clearColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "enableClearColor": true, + "enableClearDepth": true, + "enableClearStencil": true, + "enabled": true, + "layers": [ + null + ], + "objectID": "ca2a3f33-da27-400f-b920-586e60914c54", + "objectName": "MainRenderPass", + "renderOnce": false, + "renderOrder": 1, + "target": null + }, + "typeName": "RenderPass" + } + ], + "links": [ + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/resources/export-raco-warning-ramses-ok.rca b/resources/export-raco-warning-ramses-ok.rca new file mode 100644 index 00000000..dcb5e97c --- /dev/null +++ b/resources/export-raco-warning-ramses-ok.rca @@ -0,0 +1,1291 @@ +{ + "externalProjects": { + }, + "featureLevel": 1, + "fileVersion": 2003, + "instances": [ + { + "properties": { + "backgroundColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "defaultResourceFolders": { + "imageSubdirectory": "images", + "interfaceSubdirectory": "interfaces", + "meshSubdirectory": "meshes", + "scriptSubdirectory": "scripts", + "shaderSubdirectory": "shaders" + }, + "featureLevel": 1, + "objectID": "95cab398-a32d-4a12-997f-19e93a827ec1", + "objectName": "export-raco-warning-ramses-ok", + "pythonOnSaveScript": "", + "saveAsZip": false, + "sceneId": { + "annotations": [ + { + "properties": { + "max": 1024, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 123 + }, + "viewport": { + "i1": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + }, + "i2": { + "annotations": [ + { + "properties": { + "max": 4096, + "min": 0 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + } + } + }, + "typeName": "ProjectSettings" + }, + { + "properties": { + "children": [ + "f9d19011-d177-428a-90c2-11c49fb54f55" + ], + "enabled": true, + "objectID": "5fc6eae8-74dd-475c-9e0c-3853fbb3cd68", + "objectName": "Node", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "tags": { + "properties": [ + { + "typeName": "String", + "value": "render_main" + } + ] + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "Node" + }, + { + "properties": { + "enabled": true, + "frustum": { + "order": [ + "nearPlane", + "farPlane", + "fieldOfView", + "aspectRatio" + ], + "properties": { + "aspectRatio": { + "annotations": [ + { + "properties": { + "name": "aspectRatio" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 4, + "min": 0.5 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 2 + }, + "farPlane": { + "annotations": [ + { + "properties": { + "name": "farPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 10000, + "min": 100 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 1000 + }, + "fieldOfView": { + "annotations": [ + { + "properties": { + "name": "fieldOfView" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 120, + "min": 10 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 35 + }, + "nearPlane": { + "annotations": [ + { + "properties": { + "name": "nearPlane" + }, + "typeName": "DisplayNameAnnotation" + }, + { + "properties": { + "max": 1, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + }, + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "value": 0.1 + } + } + }, + "frustumType": 0, + "objectID": "c439665e-bfc5-4984-a290-c643fec05fd3", + "objectName": "PerspectiveCamera", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 1 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 10 + } + }, + "viewport": { + "height": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 720 + }, + "offsetX": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "offsetY": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": -7680 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 0 + }, + "width": { + "annotations": [ + { + "properties": { + "max": 7680, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1440 + } + }, + "visibility": true + }, + "typeName": "PerspectiveCamera" + }, + { + "properties": { + "camera": "c439665e-bfc5-4984-a290-c643fec05fd3", + "clearColor": { + "w": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "x": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 1, + "min": 0 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "enableClearColor": true, + "enableClearDepth": true, + "enableClearStencil": true, + "enabled": true, + "layers": [ + "e4aea168-73d5-4368-b6b9-915f8cd278ec" + ], + "objectID": "23d00c7c-88f1-4290-a5a3-e46b48f087d6", + "objectName": "MainRenderPass", + "renderOnce": false, + "renderOrder": 1, + "target": null + }, + "typeName": "RenderPass" + }, + { + "properties": { + "anisotropy": { + "annotations": [ + { + "properties": { + "max": 32000, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "flipTexture": false, + "generateMipmaps": false, + "level2uri": "", + "level3uri": "", + "level4uri": "", + "magSamplingMethod": 0, + "minSamplingMethod": 0, + "mipmapLevel": { + "annotations": [ + { + "properties": { + "max": 4, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": 1 + }, + "objectID": "d8665539-2da5-4b2c-b6bc-25b7d7f375aa", + "objectName": "Texture", + "textureFormat": 5, + "uri": "", + "wrapUMode": 0, + "wrapVMode": 0 + }, + "typeName": "Texture" + }, + { + "properties": { + "materialFilterMode": 1, + "objectID": "e4aea168-73d5-4368-b6b9-915f8cd278ec", + "objectName": "MainRenderLayer", + "renderableTags": { + "order": [ + "render_main" + ], + "properties": { + "render_main": { + "annotations": [ + { + "properties": { + "featureLevel": 1 + }, + "typeName": "LinkEndAnnotation" + } + ], + "typeName": "Int::LinkEndAnnotation", + "value": 0 + } + } + }, + "sortOrder": 0 + }, + "typeName": "RenderLayer" + }, + { + "properties": { + "enabled": true, + "instanceCount": { + "annotations": [ + { + "properties": { + "max": 20, + "min": 1 + }, + "typeName": "RangeAnnotationInt" + } + ], + "value": -1 + }, + "mesh": null, + "objectID": "f9d19011-d177-428a-90c2-11c49fb54f55", + "objectName": "MeshNode", + "rotation": { + "x": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 360, + "min": -360 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "scaling": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": 0.1 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 2 + } + }, + "translation": { + "x": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "y": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + }, + "z": { + "annotations": [ + { + "properties": { + "max": 100, + "min": -100 + }, + "typeName": "RangeAnnotationDouble" + } + ], + "value": 0 + } + }, + "visibility": true + }, + "typeName": "MeshNode" + } + ], + "links": [ + ], + "racoVersion": [ + 2, + 0, + 0 + ], + "ramsesVersion": [ + 28, + 0, + 0 + ], + "structPropMap": { + "AnchorPointOutputs": { + "depth": "Double::DisplayNameAnnotation::LinkStartAnnotation", + "viewportCoords": "Vec2f::DisplayNameAnnotation::LinkStartAnnotation" + }, + "BlendOptions": { + "blendColor": "Vec4f::DisplayNameAnnotation", + "blendFactorDestAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorDestColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendFactorSrcColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationAlpha": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "blendOperationColor": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "colorWriteMask": "ColorWriteMask::DisplayNameAnnotation", + "cullmode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthFunction": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "depthwrite": "Bool::DisplayNameAnnotation", + "scissorOptions": "ScissorOptions::DisplayNameAnnotation", + "stencilOptions": "StencilOptions::DisplayNameAnnotation" + }, + "CameraViewport": { + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetX": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "offsetY": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ColorWriteMask": { + "alpha": "Bool::DisplayNameAnnotation", + "blue": "Bool::DisplayNameAnnotation", + "green": "Bool::DisplayNameAnnotation", + "red": "Bool::DisplayNameAnnotation" + }, + "DefaultResourceDirectories": { + "imageSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "interfaceSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "meshSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "scriptSubdirectory": "String::DisplayNameAnnotation::URIAnnotation", + "shaderSubdirectory": "String::DisplayNameAnnotation::URIAnnotation" + }, + "LuaStandardModuleSelection": { + "base": "Bool::DisplayNameAnnotation", + "debug": "Bool::DisplayNameAnnotation", + "math": "Bool::DisplayNameAnnotation", + "string": "Bool::DisplayNameAnnotation", + "table": "Bool::DisplayNameAnnotation" + }, + "OrthographicFrustum": { + "bottomPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "farPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "leftPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "nearPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "rightPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "topPlane": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation" + }, + "ScissorOptions": { + "scissorEnable": "Bool::DisplayNameAnnotation", + "scissorRegion": "CameraViewport::DisplayNameAnnotation" + }, + "StencilOptions": { + "stencilFunc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilMask": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "stencilOpDepthFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpDepthSucc": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilOpStencilFail": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "stencilRef": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "TimerInput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkEndAnnotation" + }, + "TimerOutput": { + "ticker_us": "Int64::DisplayNameAnnotation::LinkStartAnnotation" + }, + "Vec2f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec2i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec3f": { + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec3i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt" + }, + "Vec4f": { + "w": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "x": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "y": "Double::DisplayNameAnnotation::RangeAnnotationDouble", + "z": "Double::DisplayNameAnnotation::RangeAnnotationDouble" + }, + "Vec4i": { + "i1": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i2": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i3": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "i4": "Int::DisplayNameAnnotation::RangeAnnotationInt" + } + }, + "userTypePropMap": { + "AnchorPoint": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "node": "Node::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "AnchorPointOutputs::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Animation": { + "animationChannels": "Array[AnimationChannelBase]::DisplayNameAnnotation::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "progress": "Double::DisplayNameAnnotation::RangeAnnotationDouble::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannel": { + "animationIndex": "Int::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "samplerIndex": "Int::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "AnimationChannelRaco": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "componentArraySize": "Int::DisplayNameAnnotation", + "componentType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "data": "Table::HiddenProperty", + "interpolationType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "BlitPass": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "destinationX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "destinationY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOrder": "Int::DisplayNameAnnotation", + "sourceRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "sourceX": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "sourceY": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "targetRenderBuffer": "RenderBuffer::DisplayNameAnnotation::EmptyReferenceAllowable", + "targetRenderBufferMS": "RenderBufferMS::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "CubeMap": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level2uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level3uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "level4uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uriBack": "String::URIAnnotation::DisplayNameAnnotation", + "uriBottom": "String::URIAnnotation::DisplayNameAnnotation", + "uriFront": "String::URIAnnotation::DisplayNameAnnotation", + "uriLeft": "String::URIAnnotation::DisplayNameAnnotation", + "uriRight": "String::URIAnnotation::DisplayNameAnnotation", + "uriTop": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "LuaInterface": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkStartAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScript": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "luaModules": "Table::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "Table::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "LuaScriptModule": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "stdModules": "LuaStandardModuleSelection::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Material": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "options": "BlendOptions::DisplayNameAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "uniforms": "Table::DisplayNameAnnotation", + "uriDefines": "String::URIAnnotation::DisplayNameAnnotation", + "uriFragment": "String::URIAnnotation::DisplayNameAnnotation", + "uriGeometry": "String::URIAnnotation::DisplayNameAnnotation", + "uriVertex": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Mesh": { + "bakeMeshes": "Bool::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialNames": "Table::ArraySemanticAnnotation::HiddenProperty", + "meshIndex": "Int::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "MeshNode": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "instanceCount": "Int::RangeAnnotationInt::DisplayNameAnnotation::LinkEndAnnotation", + "materials": "Table::DisplayNameAnnotation", + "mesh": "Mesh::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Node": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "OrthographicCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "OrthographicFrustum::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "PerspectiveCamera": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "frustum": "Table::DisplayNameAnnotation::LinkEndAnnotation", + "frustumType": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "viewport": "CameraViewport::DisplayNameAnnotation::LinkEndAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "Prefab": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "PrefabInstance": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "rotation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "scaling": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "template": "Prefab::DisplayNameAnnotation", + "translation": "Vec3f::DisplayNameAnnotation::LinkEndAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "visibility": "Bool::DisplayNameAnnotation::LinkEndAnnotation" + }, + "ProjectSettings": { + "backgroundColor": "Vec4f::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "defaultResourceFolders": "DefaultResourceDirectories::DisplayNameAnnotation", + "featureLevel": "Int::DisplayNameAnnotation::ReadOnlyAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "pythonOnSaveScript": "String::DisplayNameAnnotation::URIAnnotation", + "saveAsZip": "Bool::DisplayNameAnnotation", + "sceneId": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "viewport": "Vec2i::DisplayNameAnnotation" + }, + "RenderBuffer": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "RenderBufferMS": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "format": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "height": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "sampleCount": "Int::RangeAnnotationInt::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "width": "Int::RangeAnnotationInt::DisplayNameAnnotation" + }, + "RenderLayer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "materialFilterMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "materialFilterTags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderableTags": "Table::RenderableTagContainerAnnotation::DisplayNameAnnotation", + "sortOrder": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "tags": "Table::ArraySemanticAnnotation::HiddenProperty::TagContainerAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderPass": { + "camera": "BaseCamera::DisplayNameAnnotation", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "clearColor": "Vec4f::DisplayNameAnnotation::LinkEndAnnotation", + "enableClearColor": "Bool::DisplayNameAnnotation", + "enableClearDepth": "Bool::DisplayNameAnnotation", + "enableClearStencil": "Bool::DisplayNameAnnotation", + "enabled": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "layers": "Array[RenderLayer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "renderOnce": "Bool::DisplayNameAnnotation::LinkEndAnnotation", + "renderOrder": "Int::DisplayNameAnnotation::LinkEndAnnotation", + "target": "RenderTargetBase::DisplayNameAnnotation::EmptyReferenceAllowable", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTarget": { + "buffers": "Array[RenderBuffer]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "RenderTargetMS": { + "buffers": "Array[RenderBufferMS]::DisplayNameAnnotation::EmptyReferenceAllowable::ResizableArray", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Skin": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "joints": "Array[Node]::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "skinIndex": "Int::DisplayNameAnnotation", + "targets": "Array[MeshNode]::DisplayNameAnnotation::ResizableArray", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Texture": { + "anisotropy": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "flipTexture": "Bool::DisplayNameAnnotation", + "generateMipmaps": "Bool::DisplayNameAnnotation", + "level2uri": "String::URIAnnotation::DisplayNameAnnotation", + "level3uri": "String::URIAnnotation::DisplayNameAnnotation", + "level4uri": "String::URIAnnotation::DisplayNameAnnotation", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "mipmapLevel": "Int::DisplayNameAnnotation::RangeAnnotationInt", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "textureFormat": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "uri": "String::URIAnnotation::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation", + "wrapUMode": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "wrapVMode": "Int::DisplayNameAnnotation::EnumerationAnnotation" + }, + "TextureExternal": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "magSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "minSamplingMethod": "Int::DisplayNameAnnotation::EnumerationAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + }, + "Timer": { + "children": "Array[Ref]::ArraySemanticAnnotation::HiddenProperty", + "inputs": "TimerInput::DisplayNameAnnotation", + "metaData": "Table::DisplayNameAnnotation", + "objectID": "String::HiddenProperty", + "objectName": "String::DisplayNameAnnotation", + "outputs": "TimerOutput::DisplayNameAnnotation", + "userTags": "Table::ArraySemanticAnnotation::HiddenProperty::UserTagContainerAnnotation::DisplayNameAnnotation" + } + } +} diff --git a/resources/meshes/SimpleSkin/SimpleSkin-multi-target.gltf b/resources/meshes/SimpleSkin/SimpleSkin-multi-target.gltf new file mode 100644 index 00000000..f6d958f4 --- /dev/null +++ b/resources/meshes/SimpleSkin/SimpleSkin-multi-target.gltf @@ -0,0 +1,135 @@ +{ + "scene" : 0, + "scenes" : [ { + "nodes" : [ 0, 1 ] + } ], + + "nodes" : [ { + "skin" : 0, + "mesh" : 0 + }, { + "children" : [ 2 ], + "translation" : [ 0.0, 1.0, 0.0 ] + }, { + "rotation" : [ 0.0, 0.0, 0.0, 1.0 ] + }, { + "skin" : 0, + "mesh" : 0, + "translation" : [1.0, 0.0, 0.0] + } ], + + "meshes" : [ { + "primitives" : [ { + "attributes" : { + "POSITION" : 1, + "JOINTS_0" : 2, + "WEIGHTS_0" : 3 + }, + "indices" : 0 + } ] + } ], + + "skins" : [ { + "inverseBindMatrices" : 4, + "joints" : [ 1, 2 ] + } ], + + "animations" : [ { + "channels" : [ { + "sampler" : 0, + "target" : { + "node" : 2, + "path" : "rotation" + } + } ], + "samplers" : [ { + "input" : 5, + "interpolation" : "LINEAR", + "output" : 6 + } ] + } ], + + "buffers" : [ { + "uri" : "data:application/gltf-buffer;base64,AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAvwAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAvwAAAD8AAAAAAAAAPwAAAD8AAAAAAAAAvwAAgD8AAAAAAAAAPwAAgD8AAAAAAAAAvwAAwD8AAAAAAAAAPwAAwD8AAAAAAAAAvwAAAEAAAAAAAAAAPwAAAEAAAAAA", + "byteLength" : 168 + }, { + "uri" : "data:application/gltf-buffer;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=", + "byteLength" : 320 + }, { + "uri" : "data:application/gltf-buffer;base64,AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8=", + "byteLength" : 128 + }, { + "uri" : "data:application/gltf-buffer;base64,AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/", + "byteLength" : 240 + } ], + + "bufferViews" : [ { + "buffer" : 0, + "byteLength" : 48, + "target" : 34963 + }, { + "buffer" : 0, + "byteOffset" : 48, + "byteLength" : 120, + "target" : 34962 + }, { + "buffer" : 1, + "byteLength" : 320, + "byteStride" : 16 + }, { + "buffer" : 2, + "byteLength" : 128 + }, { + "buffer" : 3, + "byteLength" : 240 + } ], + + "accessors" : [ { + "bufferView" : 0, + "componentType" : 5123, + "count" : 24, + "type" : "SCALAR" + }, { + "bufferView" : 1, + "componentType" : 5126, + "count" : 10, + "type" : "VEC3", + "max" : [ 0.5, 2.0, 0.0 ], + "min" : [ -0.5, 0.0, 0.0 ] + }, { + "bufferView" : 2, + "componentType" : 5123, + "count" : 10, + "type" : "VEC4" + }, { + "bufferView" : 2, + "byteOffset" : 160, + "componentType" : 5126, + "count" : 10, + "type" : "VEC4" + }, { + "bufferView" : 3, + "componentType" : 5126, + "count" : 2, + "type" : "MAT4" + }, { + "bufferView" : 4, + "componentType" : 5126, + "count" : 12, + "type" : "SCALAR", + "max" : [ 5.5 ], + "min" : [ 0.0 ] + }, { + "bufferView" : 4, + "byteOffset" : 48, + "componentType" : 5126, + "count" : 12, + "type" : "VEC4", + "max" : [ 0.0, 0.0, 0.707, 1.0 ], + "min" : [ 0.0, 0.0, -0.707, 0.707 ] + } ], + + "asset" : { + "version" : "2.0" + } +} \ No newline at end of file diff --git a/resources/meshes/cube_color_attr_no_underscore_vec3.gltf b/resources/meshes/cube_color_attr_no_underscore_vec3.gltf new file mode 100644 index 00000000..369273a4 --- /dev/null +++ b/resources/meshes/cube_color_attr_no_underscore_vec3.gltf @@ -0,0 +1,144 @@ +{ + "asset":{ + "generator":"Khronos glTF Blender I/O v4.1.62", + "version":"2.0" + }, + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 0 + ] + } + ], + "nodes":[ + { + "mesh":0, + "name":"Cube" + } + ], + "materials":[ + { + "doubleSided":true, + "name":"Material", + "pbrMetallicRoughness":{ + "metallicFactor":0, + "roughnessFactor":0.5 + } + } + ], + "meshes":[ + { + "extras":{ + "originalName":"Cube" + }, + "name":"Cube_MeshData", + "primitives":[ + { + "attributes":{ + "POSITION":0, + "NORMAL":1, + "TEXCOORD_0":2, + "TANGENT":3, + "COLOR_0":4 + }, + "indices":5, + "material":0 + } + ] + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5126, + "count":24, + "max":[ + 1, + 1, + 1 + ], + "min":[ + -1, + -1, + -1 + ], + "type":"VEC3" + }, + { + "bufferView":1, + "componentType":5126, + "count":24, + "type":"VEC3" + }, + { + "bufferView":2, + "componentType":5126, + "count":24, + "type":"VEC2" + }, + { + "bufferView":3, + "componentType":5126, + "count":24, + "type":"VEC4" + }, + { + "bufferView":4, + "componentType":5126, + "count":24, + "type":"VEC3" + }, + { + "bufferView":5, + "componentType":5123, + "count":36, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":288, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":288, + "byteOffset":288, + "target":34962 + }, + { + "buffer":0, + "byteLength":192, + "byteOffset":576, + "target":34962 + }, + { + "buffer":0, + "byteLength":384, + "byteOffset":768, + "target":34962 + }, + { + "buffer":0, + "byteLength":288, + "byteOffset":1152, + "target":34962 + }, + { + "buffer":0, + "byteLength":72, + "byteOffset":1440, + "target":34963 + } + ], + "buffers":[ + { + "byteLength":1512, + "uri":"data:application/octet-stream;base64,AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAADAPgAAAAAAAAA+AACAPgAAwD4AAIA/AAAgPwAAAAAAAGA/AACAPgAAID8AAIA/AADAPgAAQD8AAAA+AAAAPwAAwD4AAEA/AAAgPwAAQD8AAGA/AAAAPwAAID8AAEA/AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AgAFAAsAAgALAAgABgAJABUABgAVABIAFAAXABEAFAARAA4ADAAPAAMADAADAAAABwATAA0ABwANAAEAFgAKAAQAFgAEABAA" + } + ] +} diff --git a/resources/meshes/cube_color_attr_with_underscore_vec4.gltf b/resources/meshes/cube_color_attr_with_underscore_vec4.gltf new file mode 100644 index 00000000..0cafca0a --- /dev/null +++ b/resources/meshes/cube_color_attr_with_underscore_vec4.gltf @@ -0,0 +1,150 @@ +{ + "asset":{ + "generator":"Khronos glTF Blender I/O v4.1.62", + "version":"2.0" + }, + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 0 + ] + } + ], + "nodes":[ + { + "mesh":0, + "name":"Cube" + } + ], + "materials":[ + { + "doubleSided":true, + "name":"Material", + "pbrMetallicRoughness":{ + "baseColorFactor":[ + 0.800000011920929, + 0.800000011920929, + 0.800000011920929, + 1 + ], + "metallicFactor":0, + "roughnessFactor":0.5 + } + } + ], + "meshes":[ + { + "extras":{ + "originalName":"Cube" + }, + "name":"Cube_MeshData", + "primitives":[ + { + "attributes":{ + "_COLOR_0":0, + "POSITION":1, + "NORMAL":2, + "TEXCOORD_0":3, + "TANGENT":4 + }, + "indices":5, + "material":0 + } + ] + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5126, + "count":24, + "type":"VEC4" + }, + { + "bufferView":1, + "componentType":5126, + "count":24, + "max":[ + 1, + 1, + 1 + ], + "min":[ + -1, + -1, + -1 + ], + "type":"VEC3" + }, + { + "bufferView":2, + "componentType":5126, + "count":24, + "type":"VEC3" + }, + { + "bufferView":3, + "componentType":5126, + "count":24, + "type":"VEC2" + }, + { + "bufferView":4, + "componentType":5126, + "count":24, + "type":"VEC4" + }, + { + "bufferView":5, + "componentType":5123, + "count":36, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":384, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":288, + "byteOffset":384, + "target":34962 + }, + { + "buffer":0, + "byteLength":288, + "byteOffset":672, + "target":34962 + }, + { + "buffer":0, + "byteLength":192, + "byteOffset":960, + "target":34962 + }, + { + "buffer":0, + "byteLength":384, + "byteOffset":1152, + "target":34962 + }, + { + "buffer":0, + "byteLength":72, + "byteOffset":1536, + "target":34963 + } + ], + "buffers":[ + { + "byteLength":1608, + "uri":"data:application/octet-stream;base64,AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAADAPgAAAAAAAAA+AACAPgAAwD4AAIA/AAAgPwAAAAAAAGA/AACAPgAAID8AAIA/AADAPgAAQD8AAAA+AAAAPwAAwD4AAEA/AAAgPwAAQD8AAGA/AAAAPwAAID8AAEA/AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgL8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AgAFAAsAAgALAAgABgAJABUABgAVABIAFAAXABEAFAARAA4ADAAPAAMADAADAAAABwATAA0ABwANAAEAFgAKAAQAFgAEABAA" + } + ] +} diff --git a/resources/python/anim-channel-demo.py b/resources/python/anim-channel-demo.py new file mode 100644 index 00000000..5702dd77 --- /dev/null +++ b/resources/python/anim-channel-demo.py @@ -0,0 +1,142 @@ +import sys +import raco +import os + +def print_data(obj): + print(obj.objectName.value()) + print(" timeStamps: ", obj.getAnimationTimeStamps()) + data = obj.getAnimationOutputData() + print(" keyframes: ", data[0]) + print(" tangentIn: ", data[1]) + print(" tangentOut: ", data[2]) + print() + +# Float Linear +channel = raco.create("AnimationChannelRaco", "channel_float_linear") +channel.componentType = raco.EAnimationComponentType.Float +channel.interpolationType = raco.EAnimationInterpolationType.Linear +channel.setAnimationData([0,0.5,1], [4, 5, 6]) +print_data(channel) + +# Float Cubic +channel_f_c = raco.create("AnimationChannelRaco", "channel_float_cubic") +channel_f_c.componentType = raco.EAnimationComponentType.Float +channel_f_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_f_c.setAnimationData([0,0.5,1], [4, 5,6], [0,0,0], [1,1,1]) +print_data(channel_f_c) + +# Vec2f linear +channel_v2f = raco.create("AnimationChannelRaco", "channel_vec2f_linear") +channel_v2f.componentType = raco.EAnimationComponentType.Vec2f +channel_v2f.interpolationType = raco.EAnimationInterpolationType.Linear +channel_v2f.setAnimationData([0,0.5,1], [[4, 5], [5,6], [6,7]]) +print_data(channel_v2f) + +# Vec2f cubic +channel_v2f_c = raco.create("AnimationChannelRaco", "channel_vec2f_cubic") +channel_v2f_c.componentType = raco.EAnimationComponentType.Vec2f +channel_v2f_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_v2f_c.setAnimationData([0,0.5,1], [[4.0,5], [5,6], [6,7]], [[0,0], [0,0], [0,0]], [[1,1], [1,1], [1,1]]) +print_data(channel_v2f_c) + +# Vec3f linear +channel_v3f = raco.create("AnimationChannelRaco", "channel_vec3f_linear") +channel_v3f.componentType = raco.EAnimationComponentType.Vec3f +channel_v3f.interpolationType = raco.EAnimationInterpolationType.Linear +channel_v3f.setAnimationData([0,0.5,1], [[4, 5, 6], [5,6,7], [6,7,8]]) +print_data(channel_v3f) + +# Vec3f cubic +channel_v3f_c = raco.create("AnimationChannelRaco", "channel_vec3f_cubic") +channel_v3f_c.componentType = raco.EAnimationComponentType.Vec3f +channel_v3f_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_v3f_c.setAnimationData([0,0.5,1], [[4.0,5,6], [5,6,7], [6,7,8]], [[0,0,0], [0,0,0], [0,0,0]], [[1,1,1], [1,1,1], [1,1,1]]) +print_data(channel_v3f_c) + +# Vec4f linear +channel_v4f = raco.create("AnimationChannelRaco", "channel_vec4f_linear") +channel_v4f.componentType = raco.EAnimationComponentType.Vec4f +channel_v4f.interpolationType = raco.EAnimationInterpolationType.Linear +channel_v4f.setAnimationData([0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]]) +print_data(channel_v4f) + +# Vec4f cubic +channel_v4f_c = raco.create("AnimationChannelRaco", "channel_vec4f_cubic") +channel_v4f_c.componentType = raco.EAnimationComponentType.Vec4f +channel_v4f_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_v4f_c.setAnimationData([0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]], [[0,0,0,0], [0,0,0,0], [0,0,0,0]], [[1,1,1,1], [1,1,1,1], [1,1,1,1]]) +print_data(channel_v4f_c) + + +# Array(float) linear +channel_a = raco.create("AnimationChannelRaco", "channel_array_linear") +channel_a.componentType = raco.EAnimationComponentType.Array +channel_a.interpolationType = raco.EAnimationInterpolationType.Linear +channel_a.componentArraySize = 5 +channel_a.setAnimationData([0,0.5,1], [[4.0,5,6,7,8], [5,6,7,8,9], [6,7,8,9,10]]) +print_data(channel_a) + +# Array(float) cubic +channel_a_c = raco.create("AnimationChannelRaco", "channel_array_cubic") +channel_a_c.componentType = raco.EAnimationComponentType.Array +channel_a_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_a_c.componentArraySize = 5 +channel_a_c.setAnimationData([0,0.5,1], [[4.0,5,6,7,8], [5,6,7,8,9], [6,7,8,9,10]], [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]], [[1,1,1,1,1], [1,1,1,1,1], [1,1,1,1,1]]) +print_data(channel_a_c) + + +# Int Linear +channel_i = raco.create("AnimationChannelRaco", "channel_int_linear") +channel_i.componentType = raco.EAnimationComponentType.Int +channel_i.interpolationType = raco.EAnimationInterpolationType.Linear +channel_i.setAnimationData([0,0.5,1], [4, 5, 6]) +print_data(channel_i) + +# Int Cubic +channel_f_c = raco.create("AnimationChannelRaco", "channel_int_cubic") +channel_f_c.componentType = raco.EAnimationComponentType.Int +channel_f_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_f_c.setAnimationData([0,0.5,1], [4, 5,6], [0,0,0], [1,1,1]) +print_data(channel_f_c) + +# Vec2i linear +channel_v2i = raco.create("AnimationChannelRaco", "channel_vec2i_linear") +channel_v2i.componentType = raco.EAnimationComponentType.Vec2i +channel_v2i.interpolationType = raco.EAnimationInterpolationType.Linear +channel_v2i.setAnimationData([0,0.5,1], [[4, 5], [5,6], [6,7]]) +print_data(channel_v2i) + +# Vec2i cubic +channel_v2i_c = raco.create("AnimationChannelRaco", "channel_vec2i_cubic") +channel_v2i_c.componentType = raco.EAnimationComponentType.Vec2i +channel_v2i_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_v2i_c.setAnimationData([0,0.5,1], [[4,5], [5,6], [6,7]], [[0,0], [0,0], [0,0]], [[1,1], [1,1], [1,1]]) +print_data(channel_v2i_c) + +# Vec3i linear +channel_v3i = raco.create("AnimationChannelRaco", "channel_vec3i_linear") +channel_v3i.componentType = raco.EAnimationComponentType.Vec3i +channel_v3i.interpolationType = raco.EAnimationInterpolationType.Linear +channel_v3i.setAnimationData([0,0.5,1], [[4, 5, 6], [5,6,7], [6,7,8]]) +print_data(channel_v3i) + +# Vec3i cubic +channel_v3i_c = raco.create("AnimationChannelRaco", "channel_vec3i_cubic") +channel_v3i_c.componentType = raco.EAnimationComponentType.Vec3i +channel_v3i_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_v3i_c.setAnimationData([0,0.5,1], [[4,5,6], [5,6,7], [6,7,8]], [[0,0,0], [0,0,0], [0,0,0]], [[1,1,1], [1,1,1], [1,1,1]]) +print_data(channel_v3i_c) + +# Vec4i linear +channel_v4i = raco.create("AnimationChannelRaco", "channel_vec4i_linear") +channel_v4i.componentType = raco.EAnimationComponentType.Vec4i +channel_v4i.interpolationType = raco.EAnimationInterpolationType.Linear +channel_v4i.setAnimationData([0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]]) +print_data(channel_v4i) + +# Vec4i cubic +channel_v4i_c = raco.create("AnimationChannelRaco", "channel_vec4i_cubic") +channel_v4i_c.componentType = raco.EAnimationComponentType.Vec4i +channel_v4i_c.interpolationType = raco.EAnimationInterpolationType.CubicSpline +channel_v4i_c.setAnimationData([0,0.5,1], [[4, 5, 6, 7], [5,6,7,8], [6,7,8,9]], [[0,0,0,0], [0,0,0,0], [0,0,0,0]], [[1,1,1,1], [1,1,1,1], [1,1,1,1]]) +print_data(channel_v4i_c) diff --git a/styles/_Default/icons/label_white_24dp.svg b/styles/_Default/icons/label_white_24dp.svg new file mode 100644 index 00000000..409b19d8 --- /dev/null +++ b/styles/_Default/icons/label_white_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/_Default/icons/recordActive.svg b/styles/_Default/icons/recordActive.svg new file mode 100644 index 00000000..6d918362 --- /dev/null +++ b/styles/_Default/icons/recordActive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/_Default/icons/recordInactive.svg b/styles/_Default/icons/recordInactive.svg new file mode 100644 index 00000000..4b0dfed8 --- /dev/null +++ b/styles/_Default/icons/recordInactive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/_Default/icons/stop.svg b/styles/_Default/icons/stop.svg new file mode 100644 index 00000000..1c826874 --- /dev/null +++ b/styles/_Default/icons/stop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/_Default/icons/typeRenderLayer.svg b/styles/_Default/icons/typeRenderLayer.svg new file mode 100644 index 00000000..c4d0a1bf --- /dev/null +++ b/styles/_Default/icons/typeRenderLayer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/_Default/icons/typeRenderTarget.svg b/styles/_Default/icons/typeRenderTarget.svg new file mode 100644 index 00000000..00bddd9f --- /dev/null +++ b/styles/_Default/icons/typeRenderTarget.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/icons.qrc b/styles/icons.qrc index bcb22efa..c7f042ab 100644 --- a/styles/icons.qrc +++ b/styles/icons.qrc @@ -44,6 +44,8 @@ _Default/icons/typeLuaScriptModule.svg _Default/icons/typeLuaInterface.svg _Default/icons/typeTimer.svg + _Default/icons/typeRenderLayer.svg + _Default/icons/typeRenderTarget.svg _Default/icons/browse.svg _Default/icons/refresh.svg _Default/icons/refreshNeeded.svg @@ -52,6 +54,7 @@ _Default/icons/playerPlayActive.svg _Default/icons/playerPauseInactive.svg _Default/icons/playerPauseActive.svg + _Default/icons/stop.svg _Default/icons/playerStopInctive.svg _Default/icons/playerStopActive.svg _Default/icons/playerSkipNext.svg @@ -68,5 +71,9 @@ _Default/icons/visibility_disabled_white_24dp.svg _Default/icons/abstract_scene_view.svg _Default/icons/prefabLookup.svg + _Default/icons/label_white_24dp.svg + _Default/icons/recordInactive.svg + _Default/icons/recordActive.svg + _Default/icons/stop.svg diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 58f47673..6cf7b20c 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -58,8 +58,10 @@ set_target_properties(raco_pybind11 PROPERTIES add_library(raco::pybind11 ALIAS raco_pybind11) ## zip +set(CMAKE_DISABLE_TESTING ON CACHE BOOL "" FORCE) + add_subdirectory(zip/) -set_target_properties(zip uninstall test_append.out test_entry.out test_extract.out test_permissions.out test_read.out test_write.out PROPERTIES +set_target_properties(zip uninstall PROPERTIES FOLDER third_party/zip ) @@ -90,19 +92,18 @@ add_library(raco::ramses-lib-client-only ALIAS ramses-shared-lib-headless) if (CMAKE_SYSTEM_NAME STREQUAL Linux) find_program(LINUXDEPLOYQT linuxdeployqt) - if(EXISTS "${LINUXDEPLOYQT}") - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/ramses-viewer + if(EXISTS "${LINUXDEPLOYQT}") + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/ramses-viewer COMMAND ${CMAKE_COMMAND} -E rm -f "$/ramses-viewer.sh" COMMAND ${CMAKE_COMMAND} -D TARGET_FILE=$/ramses-viewer -D ROOT_DIR=${CMAKE_SOURCE_DIR} -P "${CMAKE_SOURCE_DIR}/ubuntustartscript.cmake" COMMAND chmod +x "$/ramses-viewer.sh" DEPENDS ramses-viewer RaCoEditor - ) + ) - add_custom_target(generate_ramses_viewer_launch_script ALL + add_custom_target(generate_ramses_viewer_launch_script ALL DEPENDS ${CMAKE_BINARY_DIR}/ramses-viewer - - ) - endif() + ) + endif() endif() if(WIN32) diff --git a/third_party/python-linux/CMakeLists.txt b/third_party/python-linux/CMakeLists.txt index a4a2ce3b..4295166f 100644 --- a/third_party/python-linux/CMakeLists.txt +++ b/third_party/python-linux/CMakeLists.txt @@ -27,7 +27,8 @@ function(register_python_target targetname deploymentfolder) COMMAND ${CMAKE_COMMAND} -E rm -rf "${deploymentfolder}" COMMAND ${CMAKE_COMMAND} -E make_directory "${deploymentfolder}" COMMAND ${CMAKE_COMMAND} -E copy_directory "/usr/lib/python3.8" "${deploymentfolder}/python3.8" - COMMAND ${CMAKE_COMMAND} -E env PIP_PREFIX="${deploymentfolder}/python3.8" python3.8 "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/get-pip.py" --ignore-installed + # TODO: this does not work in CC ci (no Internet access) + # COMMAND ${CMAKE_COMMAND} -E env PIP_PREFIX="${deploymentfolder}/python3.8" python3.8 "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/get-pip.py" --ignore-installed COMMAND ${CMAKE_COMMAND} -E touch "${deploymentfolder}/python_setup_completed.txt") add_library(${targetname} INTERFACE "${deploymentfolder}/python_setup_completed.txt") set_target_properties (${targetname} PROPERTIES FOLDER Packaging)