Skip to content

Commit 3098749

Browse files
committed
Release v1.10.0
1 parent 3b7e693 commit 3098749

File tree

217 files changed

+10684
-1662
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

217 files changed

+10684
-1662
lines changed

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,42 @@ If a copy of the MPL was not distributed with this file, You can obtain one at h
2424
2525
-->
2626

27+
## [1.10.0] Multiedit, Shader Includes, Drag-and-drop Support, Misc Usability Improvements and Bugfixes
28+
29+
### Added
30+
* Added support for the multiple edit functionality in the property browser.
31+
* Added support for `#include` directives in shader files. Include directives can be nested. The path of the included files must be relative and will be interpreted relative to the path of the shader file containing the include.
32+
* Added support for opening `.rca` files using drag-and-drop.
33+
* Added drag-and-drop support for resource files (`.gltf`, `.glb`, `.ctm`, `.png`, `.vert`, `.frag`, `.geom`, `.def`, `.glsl`). Dropping a resource file on a URI property will fill the property. Dropping a resource file in the treeviews will create a new resource object.
34+
* Added application preference to optionally enable the case-sensitive URI validation. The default is off.
35+
* Added functionality to save screenshots of the preview using the GUI application and exposed via the Python API.
36+
* Added `resolveUriPropertyToAbsolutePath` function to the Python API to obtain the absolute path from a uri property.
37+
* Added a feature level update python script and updated the python migration scripts in the `python` subdirectory.
38+
* Use the `migrate_recursive_v1.0.1.py` script to update projects from RaCo version <=1.0.1 to the current version. Keeps feature level.
39+
* Use the `migrate_recursive.py` script to update projects from RaCo version >=1.1.0 to the current version. Keeps feature level.
40+
* Use the `upgrade_fl_recursive.py` script to perform a feature level upgrade to a specified feature level. Also updates the projects to the current RaCo version.
41+
* All scripts will update the main project and all external projects used by it.
42+
* Detailed usage information is contained in the scripts and can be obtained by running the script with the Python interpreter directly.
43+
* Added section on feature levels to the `Basics/Introduction` chapter of the documentation.
44+
45+
### Changes
46+
* Top-level objects in the scenegraph are now moveable.
47+
* The folding state of non-locked property browsers is preserved and saved in a cache per session for all expandable properties.
48+
* Added a new confirmation dialog to prevent accidental file version upgrade on Save. The appearance of this dialog is controlled via a new option in the preferences dialog.
49+
* Adjust the behaviour of the `-f` commandline option in the GUI application to ensure that projects specified on the commandline will load regardless of the feature level set in the preferences dialog. The behaviour is now as follows:
50+
* default feature level for new projects
51+
* set via the preferences dialog in the GUI application
52+
* set via the `-f` commdandline option in the headless application
53+
* initial project load feature level
54+
* set via the `-f` commdandline option in both gui and headless applications.
55+
* if specified the initial project given using the `-p` option will be upgraded to the given feature level.
56+
* if no initial project is specified the initial default project will be created with the given feature level.
57+
* if no `-f` option is used the initial project given the `-p` option will be loaded at the feature level of the project itself.
58+
59+
### Fixes
60+
* Don't optimize away `LuaInterfaces` with invalid links ending on them when exporting a scene. Note that invalid links ending on non-existing properties will not have associated error items indicating an invalid link.
61+
62+
2763
## [1.9.1] Bugfix Release
2864

2965
### Fixes

CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ cmake_minimum_required(VERSION 3.19)
1111

1212
SET(CMAKE_CONFIGURATION_TYPES "Debug;RelWithDebInfo")
1313

14-
project(RaCoOS VERSION 1.9.1)
14+
project(RaCoOS VERSION 1.10.0)
1515

1616
SET(RACO_RELEASE_DIRECTORY ${CMAKE_BINARY_DIR}/release)
1717

@@ -250,7 +250,7 @@ if(PACKAGE_TESTS)
250250
# Define a macro to easily setup tests
251251
macro(raco_package_add_test TESTNAME FILES LIBRARIES TEST_WORKING_DIRECTORY)
252252
add_executable(${TESTNAME} ${FILES})
253-
target_link_libraries(${TESTNAME} gtest gmock gtest_main ${LIBRARIES} raco::ramses-logic-lib-client-only)
253+
target_link_libraries(${TESTNAME} gtest gmock gtest_main ${LIBRARIES})
254254
gtest_discover_tests(${TESTNAME}
255255
WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}"
256256
PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}"
@@ -277,13 +277,15 @@ if(PACKAGE_TESTS)
277277
endmacro()
278278
macro(raco_package_add_headless_test TESTNAME FILES LIBRARIES TEST_WORKING_DIRECTORY)
279279
raco_package_add_qt_test(${TESTNAME} "${FILES}" "${LIBRARIES}" "${TEST_WORKING_DIRECTORY}")
280+
target_link_libraries(${TESTNAME} raco::ramses-logic-lib-client-only)
280281
deploy_headless_shared_dlls(${TESTNAME})
281282
deploy_ramses_client_only_shared_dlls(${TESTNAME} "$<TARGET_FILE_DIR:${TESTNAME}>")
282283
endmacro()
283284
macro(raco_package_add_gui_test TESTNAME FILES LIBRARIES TEST_WORKING_DIRECTORY)
284285
raco_package_add_qt_test(${TESTNAME} "${FILES}" "${LIBRARIES}" "${TEST_WORKING_DIRECTORY}")
286+
target_link_libraries(${TESTNAME} raco::ramses-lib raco::ramses-logic-lib)
285287
deploy_gui_shared_dlls(${TESTNAME})
286-
deploy_ramses_client_only_shared_dlls(${TESTNAME} "$<TARGET_FILE_DIR:${TESTNAME}>")
288+
deploy_ramses_with_renderer_shared_dlls(${TESTNAME} "$<TARGET_FILE_DIR:${TESTNAME}>")
287289
endmacro()
288290
function(raco_package_test_resources_process TESTNAME SOURCE_DIRECTORY)
289291
foreach(fname ${ARGN})

EditorApp/main.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,16 @@ int main(int argc, char* argv[]) {
168168
projectFile = QFileInfo(positionalArgs.at(0)).absoluteFilePath();
169169
}
170170

171+
int initialLoadFeatureLevel = -1;
171172
raco::components::RaCoPreferences::init();
172-
int featureLevel = std::min<int>(raco::components::RaCoPreferences::instance().featureLevel, static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel));
173+
int newFileFeatureLevel = std::min<int>(raco::components::RaCoPreferences::instance().featureLevel, static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel));
173174

174175
if (parser.isSet(ramsesLogicFeatureLevel)) {
175-
featureLevel = parser.value(ramsesLogicFeatureLevel).toInt();
176-
if (!(featureLevel == -1 ||
177-
featureLevel >= static_cast<int>(raco::ramses_base::BaseEngineBackend::minFeatureLevel) &&
178-
featureLevel <= static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel))) {
179-
LOG_ERROR(raco::log_system::COMMON, fmt::format("RamsesLogic feature level {} outside valid range (-1, {} ... {})", featureLevel, static_cast<int>(raco::ramses_base::BaseEngineBackend::minFeatureLevel), static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel)));
176+
initialLoadFeatureLevel = parser.value(ramsesLogicFeatureLevel).toInt();
177+
if (!(initialLoadFeatureLevel == -1 ||
178+
initialLoadFeatureLevel >= static_cast<int>(raco::ramses_base::BaseEngineBackend::minFeatureLevel) &&
179+
initialLoadFeatureLevel <= static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel))) {
180+
LOG_ERROR(raco::log_system::COMMON, fmt::format("RamsesLogic feature level {} outside valid range (-1, {} ... {})", initialLoadFeatureLevel, static_cast<int>(raco::ramses_base::BaseEngineBackend::minFeatureLevel), static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel)));
180181
exit(1);
181182
}
182183
}
@@ -204,13 +205,13 @@ int main(int argc, char* argv[]) {
204205
raco::style::RaCoStyle::installFont();
205206

206207
auto ramsesCommandLineArgs = parser.value(forwardCommandLineArgs).toStdString();
207-
int initialFeatureLevel = featureLevel == -1 ? static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel) : featureLevel;
208+
int initialFeatureLevel = initialLoadFeatureLevel == -1 ? static_cast<int>(raco::ramses_base::BaseEngineBackend::maxFeatureLevel) : initialLoadFeatureLevel;
208209
raco::ramses_widgets::RendererBackend rendererBackend{static_cast<rlogic::EFeatureLevel>(initialFeatureLevel), parser.isSet(forwardCommandLineArgs) ? ramsesCommandLineArgs : ""};
209210

210211
std::unique_ptr<raco::application::RaCoApplication> app;
211212

212213
try {
213-
app = std::make_unique<raco::application::RaCoApplication>(rendererBackend, raco::application::RaCoApplicationLaunchSettings(projectFile, true, parser.isSet(ramsesTraceLogMessageAction), featureLevel, true));
214+
app = std::make_unique<raco::application::RaCoApplication>(rendererBackend, raco::application::RaCoApplicationLaunchSettings(projectFile, true, parser.isSet(ramsesTraceLogMessageAction), newFileFeatureLevel, initialLoadFeatureLevel, true));
214215
} catch (const raco::application::FutureFileVersion& error) {
215216
LOG_ERROR(raco::log_system::COMMON, "File load error: project file was created with newer file version {} but current file version is {}.", error.fileVersion_, raco::serialization::RAMSES_PROJECT_FILE_VERSION);
216217
app.reset();

EditorApp/mainwindow.cpp

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@
7777

7878
#include "DockAreaWidget.h"
7979
#include "ads_globals.h"
80+
#include "components/RaCoNameConstants.h"
8081
#include "python_api/PythonAPI.h"
82+
#include "utils/ZipUtils.h"
8183

8284
#include <DockWidget.h>
8385
#include <IconProvider.h>
@@ -139,25 +141,28 @@ ads::CDockAreaWidget* createAndAddPreview(MainWindow* mainWindow, const char* do
139141
previewWidget->displayScene(application->sceneBackendImpl()->currentSceneId(), backgroundColor);
140142
previewWidget->setWindowFlags(Qt::Widget);
141143

144+
raco::gui_python_api::setupPreviewWindow(previewWidget);
145+
142146
auto* dock = createDockWidget(MainWindow::DockWidgetTypes::RAMSES_PREVIEW, mainWindow);
143147
dock->setObjectName(dockObjName);
144148
dock->setWidget(previewWidget);
145149
QObject::connect(dock, &ads::CDockWidget::closed, [mainWindow]() {
146150
mainWindow->setNewPreviewMenuEntryEnabled(true);
151+
raco::gui_python_api::setupPreviewWindow(nullptr);
147152
});
148153
mainWindow->setNewPreviewMenuEntryEnabled(false);
149154
return dockManager->addDockWidget(ads::CenterDockWidgetArea, dock);
150155
}
151156

152157
void connectPropertyBrowserAndTreeDockManager(raco::property_browser::PropertyBrowserWidget* propertyBrowser, raco::object_tree::view::ObjectTreeDockManager& treeDockManager) {
153-
QObject::connect(&treeDockManager, &raco::object_tree::view::ObjectTreeDockManager::newObjectTreeItemsSelected, propertyBrowser, &raco::property_browser::PropertyBrowserWidget::setValueHandles);
158+
QObject::connect(&treeDockManager, &raco::object_tree::view::ObjectTreeDockManager::newObjectTreeItemsSelected, propertyBrowser, &raco::property_browser::PropertyBrowserWidget::setObjects);
154159
QObject::connect(&treeDockManager, &raco::object_tree::view::ObjectTreeDockManager::selectionCleared, propertyBrowser, &raco::property_browser::PropertyBrowserWidget::clear);
155160
}
156161

157162
ads::CDockAreaWidget* createAndAddPropertyBrowser(MainWindow* mainWindow, const char* dockObjName, RaCoDockManager* dockManager, raco::object_tree::view::ObjectTreeDockManager& treeDockManager, raco::application::RaCoApplication* application) {
158-
auto propertyBrowser = new raco::property_browser::PropertyBrowserWidget(application->dataChangeDispatcher(), application->activeRaCoProject().commandInterface(), application->sceneBackendImpl(), mainWindow);
163+
auto propertyBrowser = new raco::property_browser::PropertyBrowserWidget(application->dataChangeDispatcher(), application->activeRaCoProject().commandInterface(), application->sceneBackendImpl(), &treeDockManager, mainWindow);
159164
QObject::connect(propertyBrowser->model(), &raco::property_browser::PropertyBrowserModel::objectSelectionRequested, mainWindow, &MainWindow::focusToObject);
160-
QObject::connect(mainWindow, &MainWindow::objectFocusRequestedForPropertyBrowser, propertyBrowser, &raco::property_browser::PropertyBrowserWidget::setValueHandleFromObjectId);
165+
QObject::connect(mainWindow, &MainWindow::objectFocusRequestedForPropertyBrowser, propertyBrowser, &raco::property_browser::PropertyBrowserWidget::setObjectFromObjectId);
161166
connectPropertyBrowserAndTreeDockManager(propertyBrowser, treeDockManager);
162167
auto* dockWidget = createDockWidget(MainWindow::DockWidgetTypes::PROPERTY_BROWSER, mainWindow);
163168
dockWidget->setWidget(propertyBrowser);
@@ -168,8 +173,8 @@ ads::CDockAreaWidget* createAndAddPropertyBrowser(MainWindow* mainWindow, const
168173
void createAndAddProjectSettings(MainWindow* mainWindow, const char* dockObjName, RaCoDockManager* dockManager, raco::application::RaCoProject* project, SDataChangeDispatcher dataChangeDispatcher, CommandInterface* commandInterface, SceneBackend* sceneBackend) {
169174
auto* dock = createDockWidget(MainWindow::DockWidgetTypes::PROJECT_SETTINGS, mainWindow);
170175
dock->setObjectName(dockObjName);
171-
auto propertyBrowser = new raco::property_browser::PropertyBrowserWidget(dataChangeDispatcher, commandInterface, sceneBackend, mainWindow);
172-
propertyBrowser->setValueHandle({project->project()->settings()});
176+
auto propertyBrowser = new raco::property_browser::PropertyBrowserWidget(dataChangeDispatcher, commandInterface, sceneBackend, nullptr, mainWindow);
177+
propertyBrowser->setObjects({project->project()->settings()});
173178
propertyBrowser->setLockable(false);
174179
dock->setWidget(propertyBrowser);
175180
dockManager->addDockWidget(ads::RightDockWidgetArea, dock);
@@ -229,6 +234,8 @@ ads::CDockAreaWidget* createAndAddResourceTree(MainWindow* mainWindow, const cha
229234
RenderPass::typeDescription.typeName};
230235

231236
auto* model = new raco::object_tree::model::ObjectTreeViewResourceModel(racoApplication->activeRaCoProject().commandInterface(), racoApplication->dataChangeDispatcher(), racoApplication->externalProjects(), allowedCreateableUserTypes);
237+
model->setAcceptableFileExtensions(QStringList{"gltf", "glb", "ctm", "png", "vert", "frag", "geom", "def", "glsl", "lua"});
238+
model->setAcceptLuaModules(true);
232239
return createAndAddObjectTree(
233240
MainWindow::DockWidgetTypes::RESOURCES, dockObjName, model, new raco::object_tree::model::ObjectTreeViewResourceSortFilterProxyModel(mainWindow),
234241
ads::BottomDockWidgetArea, mainWindow, dockManager, treeDockManager, dockArea);
@@ -238,16 +245,7 @@ ads::CDockAreaWidget* createAndAddPrefabTree(MainWindow* mainWindow, const char*
238245
using namespace raco::user_types;
239246

240247
static const std::vector<std::string> allowedCreateableUserTypes{
241-
Node::typeDescription.typeName,
242-
MeshNode::typeDescription.typeName,
243-
Prefab::typeDescription.typeName,
244-
PrefabInstance::typeDescription.typeName,
245-
OrthographicCamera::typeDescription.typeName,
246-
PerspectiveCamera::typeDescription.typeName,
247-
Animation::typeDescription.typeName,
248-
LuaScript::typeDescription.typeName,
249-
LuaInterface::typeDescription.typeName,
250-
Skin::typeDescription.typeName};
248+
Prefab::typeDescription.typeName};
251249

252250
auto* model = new raco::object_tree::model::ObjectTreeViewPrefabModel(racoApplication->activeRaCoProject().commandInterface(), racoApplication->dataChangeDispatcher(), racoApplication->externalProjects(), allowedCreateableUserTypes);
253251

@@ -271,6 +269,9 @@ ads::CDockAreaWidget* createAndAddSceneGraphTree(MainWindow* mainWindow, const c
271269
Skin::typeDescription.typeName};
272270

273271
auto* model = new raco::object_tree::model::ObjectTreeViewDefaultModel(racoApplication->activeRaCoProject().commandInterface(), racoApplication->dataChangeDispatcher(), racoApplication->externalProjects(), allowedCreateableUserTypes);
272+
model->setAcceptableFileExtensions(QStringList{"lua"});
273+
model->setAcceptLuaScripts(true);
274+
model->setAcceptLuaInterfaces(true);
274275
return createAndAddObjectTree(MainWindow::DockWidgetTypes::SCENE_GRAPH, dockObjName, model, new raco::object_tree::model::ObjectTreeViewDefaultSortFilterProxyModel(mainWindow, false),
275276
ads::LeftDockWidgetArea, mainWindow, dockManager, treeDockManager, nullptr);
276277
}
@@ -446,6 +447,7 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, raco
446447
dialog->resize(500, 500);
447448
dialog->exec();
448449
racoApplication_->setApplicationFeatureLevel(raco::components::RaCoPreferences::instance().featureLevel);
450+
racoApplication_->activeRaCoProject().applyPreferences();
449451
});
450452

451453
// View actions
@@ -500,6 +502,8 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, raco
500502

501503
QObject::connect(this, &MainWindow::objectFocusRequestedForTreeDock, &treeDockManager_, &raco::object_tree::view::ObjectTreeDockManager::selectObjectAcrossAllTreeDocks);
502504

505+
setAcceptDrops(true);
506+
503507
updateProjectSavedConnection();
504508

505509
restoreSettings();
@@ -508,7 +512,8 @@ MainWindow::MainWindow(raco::application::RaCoApplication* racoApplication, raco
508512
// Setup
509513
updateApplicationTitle();
510514
updateSavedLayoutMenu();
511-
raco::gui_python_api::setup(&treeDockManager_);
515+
516+
raco::gui_python_api::setupObjectTree(&treeDockManager_);
512517

513518
// Will we support Mac?
514519
setUnifiedTitleAndToolBarOnMac(true);
@@ -567,6 +572,35 @@ void MainWindow::closeEvent(QCloseEvent* event) {
567572
}
568573
}
569574

575+
void MainWindow::dragEnterEvent(QDragEnterEvent* event) {
576+
const QFileInfo fileInfo = getDragAndDropFileInfo(event);
577+
if (fileInfo.suffix().toLower() == "rca") {
578+
event->acceptProposedAction();
579+
}
580+
}
581+
582+
void MainWindow::dropEvent(QDropEvent* event) {
583+
const QFileInfo fileInfo = getDragAndDropFileInfo(event);
584+
if (fileInfo.suffix().toLower() == "rca") {
585+
openProject(fileInfo.absoluteFilePath());
586+
}
587+
}
588+
589+
QFileInfo MainWindow::getDragAndDropFileInfo(const QDropEvent* event) {
590+
const QList<QUrl> urls = event->mimeData()->urls();
591+
if (urls.empty()) {
592+
return {};
593+
}
594+
595+
const QString filePath = urls.first().toLocalFile();
596+
if (filePath.isEmpty()) {
597+
return {};
598+
}
599+
600+
const QFile file(filePath);
601+
return QFileInfo{file};
602+
}
603+
570604
void MainWindow::restoreSettings() {
571605
if (PathManager::layoutFilePath().existsFile()) {
572606
auto settings = raco::core::PathManager::layoutSettings();
@@ -715,6 +749,10 @@ bool MainWindow::saveActiveProject() {
715749
if (racoApplication_->activeProjectPath().empty()) {
716750
return saveAsActiveProject();
717751
} else {
752+
if (isUpgradePrevented()) {
753+
return false;
754+
}
755+
718756
std::string errorMsg;
719757
if (racoApplication_->activeRaCoProject().save(errorMsg)) {
720758
updateUpgradeMenu();
@@ -731,6 +769,26 @@ bool MainWindow::saveActiveProject() {
731769
return false;
732770
}
733771

772+
bool MainWindow::isUpgradePrevented() {
773+
if (raco::components::RaCoPreferences::instance().preventAccidentalUpgrade) {
774+
const auto filename = QString::fromStdString(racoApplication_->activeProjectPath());
775+
constexpr auto currentFileVersion = raco::serialization::RAMSES_PROJECT_FILE_VERSION;
776+
777+
try {
778+
auto previousFileVersion = raco::serialization::deserializeFileVersion(raco::application::RaCoProject::loadFileDocument(filename));
779+
if (currentFileVersion > previousFileVersion) {
780+
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);
781+
if (answer == QMessageBox::Cancel) {
782+
return true;
783+
}
784+
}
785+
} catch (const std::exception& e) {
786+
QMessageBox::warning(this, "Document Load Error", fmt::format("Document could not be loaded.\n\nReported error: {}\n\nCheck whether the file has been broken or corrupted.", e.what()).c_str(), QMessageBox::Close);
787+
}
788+
}
789+
return false;
790+
}
791+
734792
bool MainWindow::saveAsActiveProject(bool newID) {
735793
if (racoApplication_->canSaveActiveProject()) {
736794
const bool setProjectName = racoApplication_->activeProjectPath().empty();

EditorApp/mainwindow.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public Q_SLOTS:
7373
protected:
7474
void timerEvent(QTimerEvent* event) override;
7575
void closeEvent(QCloseEvent* event) override;
76+
void dragEnterEvent(QDragEnterEvent* event) override;
77+
void dropEvent(QDropEvent* event) override;
7678
void restoreSettings();
7779
/** @returns if user canceled the dirty resolution */
7880
bool resolveDirtiness();
@@ -81,6 +83,7 @@ public Q_SLOTS:
8183
void restoreCustomLayout(const QString& layoutName);
8284
void regenerateLayoutDocks(const RaCoDockManager::LayoutDocks& docks);
8385
void saveDockManagerCustomLayouts();
86+
bool isUpgradePrevented();
8487

8588
protected Q_SLOTS:
8689
void openProject(const QString& file = {}, int featureLevel = -1, bool generateNewObjectIDs = false);
@@ -115,4 +118,6 @@ protected Q_SLOTS:
115118
std::map<QString, qint64> pythonScriptArgumentCache_;
116119

117120
int renderTimerId_ = 0;
121+
122+
QFileInfo getDragAndDropFileInfo(const QDropEvent* event);
118123
};

0 commit comments

Comments
 (0)