From 5eeaa9a33e5d6b945248215f170bf204434b2091 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 8 Feb 2016 16:23:54 -0800 Subject: [PATCH 1/6] Move graphics settings to dedicated dialog --- .../hifi/dialogs/GeneralPreferencesDialog.qml | 2 +- .../dialogs/GraphicsPreferencesDialog.qml | 19 +++++++++++++++++++ interface/src/Menu.cpp | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index c876ac6abb..81e4924204 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -7,7 +7,7 @@ PreferencesDialog { id: root objectName: "GeneralPreferencesDialog" title: "General Preferences" - showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Graphics"] + showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml new file mode 100644 index 0000000000..dca3a8694c --- /dev/null +++ b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml @@ -0,0 +1,19 @@ +import QtQuick 2.5 +import Qt.labs.settings 1.0 + +import "../../dialogs" + +PreferencesDialog { + id: root + objectName: "GraphicsPreferencesDialog" + title: "Graphics Preferences" + showCategories: ["Graphics"] + property var settings: Settings { + category: root.objectName + property alias x: root.x + property alias y: root.y + property alias width: root.width + property alias height: root.height + } +} + diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e5f6de3ae1..964e660dd0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -312,6 +312,12 @@ Menu::Menu() { DependencyManager::get()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog"); }); + // Settings > Graphics... + action = addActionToQMenuAndActionHash(settingsMenu, "Graphics..."); + connect(action, &QAction::triggered, [] { + DependencyManager::get()->toggle(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), "GraphicsPreferencesDialog"); + }); + // Settings > LOD...-- FIXME: needs implementation action = addActionToQMenuAndActionHash(settingsMenu, "LOD..."); connect(action, &QAction::triggered, [] { From 66e1d9668c78f9ab15373187f57c965c16e057fc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 8 Feb 2016 16:44:30 -0800 Subject: [PATCH 2/6] Add ComboBox preference --- .../preferences/BrowsablePreference.qml | 2 +- .../preferences/ComboBoxPreference.qml | 37 +++++++++++++++++++ .../qml/dialogs/preferences/Section.qml | 7 +++- libraries/shared/src/Preferences.h | 17 +++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml index 637cc6c02c..790d1d82ea 100644 --- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml @@ -49,7 +49,7 @@ Preference { Button { id: button anchors { right: parent.right; verticalCenter: dataTextField.verticalCenter } - text: "Browse" + text: preference.browseLabel onClicked: { var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); browser.selectedFile.connect(function(fileUrl){ diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml new file mode 100644 index 0000000000..9f323ace63 --- /dev/null +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -0,0 +1,37 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +Preference { + id: root + property real spacing: 8 + height: labelText.height + dataComboBox.height + spacing + + Component.onCompleted: { + dataComboBox.currentIndex = dataComboBox.find(preference.value); + } + + function save() { + preference.value = dataComboBox.currentText; + preference.save(); + } + + Text { + id: labelText + color: enabled ? "black" : "gray" + text: root.label + } + + ComboBox { + id: dataComboBox + model: preference.items + style: ComboBoxStyle { renderType: Text.QtRendering } + anchors { + top: labelText.bottom + left: parent.left + right: parent.right + topMargin: root.spacing + rightMargin: root.spacing + } + } +} diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index b1e59430a9..63aa19651a 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -81,6 +81,7 @@ Preference { property var sliderBuilder: Component { SliderPreference { } } property var avatarBuilder: Component { AvatarPreference { } } property var buttonBuilder: Component { ButtonPreference { } } + property var comboBoxBuilder: Component { ComboBoxPreference { } } property var preferences: [] function buildPreferences() { @@ -123,7 +124,11 @@ Preference { case Preference.Button: builder = buttonBuilder; - break + break; + + case Preference.ComboBox: + builder = comboBoxBuilder; + break; }; if (builder) { diff --git a/libraries/shared/src/Preferences.h b/libraries/shared/src/Preferences.h index 5a04b37ca1..0b8140af1b 100644 --- a/libraries/shared/src/Preferences.h +++ b/libraries/shared/src/Preferences.h @@ -54,6 +54,7 @@ public: Spinner, Checkbox, Button, + ComboBox, // Special casing for an unusual preference Avatar }; @@ -236,6 +237,22 @@ protected: QString _placeholderText; }; +class ComboBoxPreference : public EditPreference { + Q_OBJECT + Q_PROPERTY(QStringList items READ getItems CONSTANT) + +public: + ComboBoxPreference(const QString& category, const QString& name, Getter getter, Setter setter) + : EditPreference(category, name, getter, setter) { } + Type getType() { return ComboBox; } + + const QStringList& getItems() { return _items; } + void setItems(const QStringList& items) { _items = items; } + +protected: + QStringList _items; +}; + class BrowsePreference : public EditPreference { Q_OBJECT Q_PROPERTY(QString browseLabel READ getBrowseLabel CONSTANT) From 84197e5eb23de8d035b60753948c3f27fb1871ae Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 9 Feb 2016 11:07:10 -0800 Subject: [PATCH 3/6] Add persistent render engine configuration file --- interface/src/Application.cpp | 1 + interface/src/ui/PreferencesDialog.cpp | 14 +++++- libraries/render/src/render/Engine.cpp | 68 +++++++++++++++++++++++++- libraries/render/src/render/Engine.h | 21 ++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30f2802d70..829deda139 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1156,6 +1156,7 @@ void Application::initializeGL() { render::CullFunctor cullFunctor = LODManager::shouldRender; _renderEngine->addJob("RenderShadowTask", cullFunctor); _renderEngine->addJob("RenderDeferredTask", cullFunctor); + _renderEngine->loadConfig(); _renderEngine->registerScene(_main3DScene); // TODO: Load a cached config file diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index fd4647e429..94ea732b2c 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -335,7 +335,19 @@ void setupPreferences() { { static const QString RENDER("Graphics"); - auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + auto renderEngine = qApp->getRenderEngine(); + auto renderConfig = renderEngine->getConfiguration(); + { + auto getter = [renderEngine]()->QString { return renderEngine->getNamedConfig(); }; + auto setter = [renderEngine](QString config) { renderEngine->setNamedConfig(config); }; + auto preference = new ComboBoxBrowsePreference(RENDER, "Engine Profile", getter, setter); + preference->setItems(renderEngine->getNamedConfigList()); + preference->setBrowseLabel("Custom..."); + preference->setBrowseFilter("Engine Profiles (*.json)"); + preferences->addPreference(preference); + } + + // Theses will override the engine profile because they are defined afterwards { auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled(); }; auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled(enable); }; diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index be0481f97c..470eeb8822 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -9,17 +9,83 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Engine.h" + +#include + #include -#include "Engine.h" using namespace render; +const QString ENGINE_CONFIG_DEFAULT = "Default"; +// TODO: Presets (e.g., "Highest Performance", "Highest Quality") will go here +const QMap Engine::PRESETS = {}; + Engine::Engine() : + _namedConfig(QStringList() << "Render" << "Engine"), _sceneContext(std::make_shared()), _renderContext(std::make_shared()) { } +QStringList Engine::getNamedConfigList() { + QStringList list; + list << ENGINE_CONFIG_DEFAULT << PRESETS.keys(); + auto current = _namedConfig.get(); + if (!list.contains(current)) { + list << current; + } + + return list; +} + +QString Engine::getNamedConfig() { + return _namedConfig.get(); +} + +void Engine::setNamedConfig(const QString& config) { + _namedConfig.set(config); + loadConfig(); +} + +void Engine::loadConfig() { + auto config = getConfiguration(); + QString current = _namedConfig.get(); + + if (_defaultConfig.isNull()) { + // Set the default + _defaultConfig = + QJsonDocument::fromJson(config->toJSON().toUtf8()).object(); + } + + if (current == ENGINE_CONFIG_DEFAULT) { + // Load the default + config->load(_defaultConfig.toObject()); + } else if (PRESETS.contains(current)) { + // Load a preset + config->load(QJsonDocument::fromJson(PRESETS[current].toUtf8()).object()); + } else { + QFile file(current); + if (!file.exists()) { + qWarning() << "Engine configuration file" << current << "does not exist"; + } else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Engine configuration file" << current << "cannot be opened"; + } else { + QString data = file.readAll(); + file.close(); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &error); + if (error.error == error.NoError) { + config->load(doc.object()); + qDebug() << "Engine configuration file" << current << "loaded"; + } else { + qWarning() << "Engine configuration file" << current << "failed to load:" << + error.errorString() << "at offset" << error.offset; + } + } + } +} + void Engine::run() { // Sync GPU state before beginning to render _renderContext->args->_context->syncCache(); diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index e94de6f266..238754c46a 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -12,6 +12,8 @@ #ifndef hifi_render_Engine_h #define hifi_render_Engine_h +#include + #include "Context.h" #include "Task.h" @@ -25,6 +27,19 @@ public: Engine(); ~Engine() = default; + // Get the configurations + QStringList getNamedConfigList(); + + // Get the current named configuration + QString getNamedConfig(); + + // Set a named configuration + void setNamedConfig(const QString& config); + + // Load the current named config + // The first time this is run, it will also set the current configuration as Default + void loadConfig(); + // Register the scene void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; } @@ -37,8 +52,14 @@ public: void run(); protected: + Setting::Handle _namedConfig; + QJsonValue _defaultConfig; + SceneContextPointer _sceneContext; RenderContextPointer _renderContext; + +private: + static const QMap PRESETS; }; using EnginePointer = std::shared_ptr; From a7778daed25508486c30b081aa359690ead2be68 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 9 Feb 2016 15:45:47 -0800 Subject: [PATCH 4/6] Change graphics dialog to persisted dropdowns --- interface/resources/config/render.json | 19 ++++ interface/src/Application.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 39 ++++---- .../render-utils/src/AmbientOcclusionEffect.h | 4 +- .../render-utils/src/AntialiasingEffect.h | 4 +- libraries/render-utils/src/RenderShadowTask.h | 4 +- libraries/render/src/render/Engine.cpp | 74 ++++---------- libraries/render/src/render/Engine.h | 21 +--- libraries/render/src/render/Task.h | 96 ++++++++++++++++--- libraries/shared/src/shared/JSONHelpers.cpp | 2 +- 10 files changed, 150 insertions(+), 115 deletions(-) create mode 100644 interface/resources/config/render.json diff --git a/interface/resources/config/render.json b/interface/resources/config/render.json new file mode 100644 index 0000000000..092530d864 --- /dev/null +++ b/interface/resources/config/render.json @@ -0,0 +1,19 @@ +{ + "RenderShadowTask": { + "Enabled": { + "enabled": true + } + }, + "RenderDeferredTask": { + "AmbientOcclusion": { + "Enabled": { + "enabled": true + } + }, + "Antialiasing": { + "Enabled": { + "enabled": true + } + } + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 829deda139..4c4c515a0d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1156,7 +1156,7 @@ void Application::initializeGL() { render::CullFunctor cullFunctor = LODManager::shouldRender; _renderEngine->addJob("RenderShadowTask", cullFunctor); _renderEngine->addJob("RenderDeferredTask", cullFunctor); - _renderEngine->loadConfig(); + _renderEngine->load(); _renderEngine->registerScene(_main3DScene); // TODO: Load a cached config file diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 94ea732b2c..b1812b7bd3 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -335,37 +335,32 @@ void setupPreferences() { { static const QString RENDER("Graphics"); - auto renderEngine = qApp->getRenderEngine(); - auto renderConfig = renderEngine->getConfiguration(); + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + + auto ambientOcclusionConfig = renderConfig->getConfig(); { - auto getter = [renderEngine]()->QString { return renderEngine->getNamedConfig(); }; - auto setter = [renderEngine](QString config) { renderEngine->setNamedConfig(config); }; - auto preference = new ComboBoxBrowsePreference(RENDER, "Engine Profile", getter, setter); - preference->setItems(renderEngine->getNamedConfigList()); - preference->setBrowseLabel("Custom..."); - preference->setBrowseFilter("Engine Profiles (*.json)"); + auto getter = [ambientOcclusionConfig]()->QString { return ambientOcclusionConfig->getPreset(); }; + auto setter = [ambientOcclusionConfig](QString preset) { ambientOcclusionConfig->setPreset(preset); }; + auto preference = new ComboBoxPreference(RENDER, "Ambient Occlusion", getter, setter); + preference->setItems(ambientOcclusionConfig->getPresetList()); preferences->addPreference(preference); } - // Theses will override the engine profile because they are defined afterwards + auto antialiasingConfig = renderConfig->getConfig(); { - auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled(); }; - auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled(enable); }; - auto preference = new CheckPreference(RENDER, "Ambient Occlusion", getter, setter); + auto getter = [antialiasingConfig]()->QString { return antialiasingConfig->getPreset(); }; + auto setter = [antialiasingConfig](QString preset) { antialiasingConfig->setPreset(preset); }; + auto preference = new ComboBoxPreference(RENDER, "Antialiasing", getter, setter); + preference->setItems(antialiasingConfig->getPresetList()); preferences->addPreference(preference); } + auto shadowConfig = renderConfig->getConfig(); { - auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled(); }; - auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled(enable); }; - auto preference = new CheckPreference(RENDER, "Antialiasing", getter, setter); - preferences->addPreference(preference); - } - - { - auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled(); }; - auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled(enable); }; - auto preference = new CheckPreference(RENDER, "Shadows", getter, setter); + auto getter = [shadowConfig]()->QString { return shadowConfig->getPreset(); }; + auto setter = [shadowConfig](QString preset) { shadowConfig->setPreset(preset); }; + auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter); + preference->setItems(shadowConfig->getPresetList()); preferences->addPreference(preference); } } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index c040e31188..442c108af7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -16,7 +16,7 @@ #include "render/DrawTask.h" -class AmbientOcclusionEffectConfig : public render::Job::Config { +class AmbientOcclusionEffectConfig : public render::Job::PersistentConfig { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty) @@ -32,7 +32,7 @@ class AmbientOcclusionEffectConfig : public render::Job::Config { Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius) Q_PROPERTY(double gpuTime READ getGpuTime) public: - AmbientOcclusionEffectConfig() : render::Job::Config(false) {} + AmbientOcclusionEffectConfig() : render::Job::PersistentConfig("Ambient Occlusion", false) {} const int MAX_RESOLUTION_LEVEL = 4; const int MAX_BLUR_RADIUS = 6; diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index f0a32c68ff..000760a2e2 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -16,11 +16,11 @@ #include "render/DrawTask.h" -class AntiAliasingConfig : public render::Job::Config { +class AntiAliasingConfig : public render::Job::PersistentConfig { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled) public: - AntiAliasingConfig() : render::Job::Config(false) {} + AntiAliasingConfig() : render::Job::PersistentConfig("Antialiasing", false) {} }; class Antialiasing { diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index e1bf983b79..177a42aff7 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -31,11 +31,11 @@ protected: render::ShapePlumberPointer _shapePlumber; }; -class RenderShadowTaskConfig : public render::Task::Config { +class RenderShadowTaskConfig : public render::Task::PersistentConfig { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) public: - RenderShadowTaskConfig() : render::Task::Config(false) {} + RenderShadowTaskConfig() : render::Task::PersistentConfig("Shadows", false) {} signals: void dirty(); diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 470eeb8822..806c964ec0 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -13,75 +13,39 @@ #include +#include + #include using namespace render; -const QString ENGINE_CONFIG_DEFAULT = "Default"; -// TODO: Presets (e.g., "Highest Performance", "Highest Quality") will go here -const QMap Engine::PRESETS = {}; - Engine::Engine() : - _namedConfig(QStringList() << "Render" << "Engine"), _sceneContext(std::make_shared()), _renderContext(std::make_shared()) { } -QStringList Engine::getNamedConfigList() { - QStringList list; - list << ENGINE_CONFIG_DEFAULT << PRESETS.keys(); - auto current = _namedConfig.get(); - if (!list.contains(current)) { - list << current; - } - - return list; -} - -QString Engine::getNamedConfig() { - return _namedConfig.get(); -} - -void Engine::setNamedConfig(const QString& config) { - _namedConfig.set(config); - loadConfig(); -} - -void Engine::loadConfig() { +void Engine::load() { auto config = getConfiguration(); - QString current = _namedConfig.get(); + const QString configFile= "config/render.json"; - if (_defaultConfig.isNull()) { - // Set the default - _defaultConfig = - QJsonDocument::fromJson(config->toJSON().toUtf8()).object(); - } - - if (current == ENGINE_CONFIG_DEFAULT) { - // Load the default - config->load(_defaultConfig.toObject()); - } else if (PRESETS.contains(current)) { - // Load a preset - config->load(QJsonDocument::fromJson(PRESETS[current].toUtf8()).object()); + QUrl path(PathUtils::resourcesPath() + configFile); + QFile file(path.toString()); + if (!file.exists()) { + qWarning() << "Engine configuration file" << path << "does not exist"; + } else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Engine configuration file" << path << "cannot be opened"; } else { - QFile file(current); - if (!file.exists()) { - qWarning() << "Engine configuration file" << current << "does not exist"; - } else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Engine configuration file" << current << "cannot be opened"; + QString data = file.readAll(); + file.close(); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &error); + if (error.error == error.NoError) { + config->setPresetList(doc.object()); + qDebug() << "Engine configuration file" << path << "loaded"; } else { - QString data = file.readAll(); - file.close(); - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &error); - if (error.error == error.NoError) { - config->load(doc.object()); - qDebug() << "Engine configuration file" << current << "loaded"; - } else { - qWarning() << "Engine configuration file" << current << "failed to load:" << - error.errorString() << "at offset" << error.offset; - } + qWarning() << "Engine configuration file" << path << "failed to load:" << + error.errorString() << "at offset" << error.offset; } } } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 238754c46a..1af0e6d76f 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -27,18 +27,9 @@ public: Engine(); ~Engine() = default; - // Get the configurations - QStringList getNamedConfigList(); - - // Get the current named configuration - QString getNamedConfig(); - - // Set a named configuration - void setNamedConfig(const QString& config); - - // Load the current named config - // The first time this is run, it will also set the current configuration as Default - void loadConfig(); + // Load any persisted settings, and set up the presets + // This should be run after adding all jobs, and before building ui + void load(); // Register the scene void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; } @@ -52,14 +43,8 @@ public: void run(); protected: - Setting::Handle _namedConfig; - QJsonValue _defaultConfig; - SceneContextPointer _sceneContext; RenderContextPointer _renderContext; - -private: - static const QMap PRESETS; }; using EnginePointer = std::shared_ptr; diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index a47f8e39fe..2d29e5eedd 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -19,6 +19,8 @@ #include #include +#include "SettingHandle.h" + #include "Context.h" #include "gpu/Batch.h" @@ -71,12 +73,24 @@ public: bool alwaysEnabled{ true }; bool enabled{ true }; + virtual void setPresetList(const QJsonObject& object) { + for (auto it = object.begin(); it != object.end(); it++) { + JobConfig* child = findChild(it.key(), Qt::FindDirectChildrenOnly); + if (child) { + child->setPresetList(it.value().toObject()); + } + } + } + // This must be named toJSON to integrate with the global scripting JSON object Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); } - Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); } + Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); emit loaded(); } public slots: - void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); } + void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); } + +signals: + void loaded(); }; class TaskConfig : public JobConfig { @@ -95,15 +109,6 @@ public: return findChild(name); } - template void setJobEnabled(bool enable = true, std::string job = "") { - assert(getConfig(job)->alwaysEnabled != true); - getConfig(job)->enabled = enable; - refresh(); // trigger a Job->configure - } - template bool isJobEnabled(bool enable = true, std::string job = "") const { - return getConfig(job)->isEnabled(); - } - public slots: void refresh(); @@ -111,6 +116,69 @@ private: Task* _task; }; +template class PersistentConfig : public C { +public: + const QString DEFAULT = "Default"; + const QString NONE = "None"; + + PersistentConfig() = delete; + PersistentConfig(const QString& path) : + _preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { } + PersistentConfig(const QStringList& path) : + _preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { } + PersistentConfig(const QString& path, bool enabled) : C(enabled), + _preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { } + PersistentConfig(const QStringList& path, bool enabled) : C(enabled), + _preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { } + + QStringList getPresetList() { + if (_presets.empty()) { + setPresetList(QJsonObject()); + } + return _presets.keys(); + } + + virtual void setPresetList(const QJsonObject& list) override { + assert(_presets.empty()); + + _default = toJsonValue(*this).toObject().toVariantMap(); + + _presets.unite(list.toVariantMap()); + if (alwaysEnabled || enabled) { + _presets.insert(DEFAULT, _default); + } + if (!alwaysEnabled) { + _presets.insert(NONE, QVariantMap{{ "enabled", false }}); + } + + auto preset = _preset.get(); + if (preset != _preset.getDefault() && _presets.contains(preset)) { + // Load the persisted configuration + load(_presets[preset].toMap()); + } + } + + QString getPreset() { return _preset.get(); } + + void setPreset(const QString& preset) { + _preset.set(preset); + if (_presets.contains(preset)) { + // Always start back at default to remain deterministic + QVariantMap config = _default; + QVariantMap presetConfig = _presets[preset].toMap(); + for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) { + config.insert(it.key(), it.value()); + } + load(config); + } + } + +protected: + QVariantMap _default; + QVariantMap _presets; + Setting::Handle _preset; +}; + template void jobConfigure(T& data, const C& configuration) { data.configure(configuration); } @@ -133,6 +201,7 @@ template void jobRun(T& data, const SceneContextPoin class Job { public: using Config = JobConfig; + using PersistentConfig = PersistentConfig; using QConfigPointer = std::shared_ptr; using None = JobNoIO; @@ -220,6 +289,7 @@ public: class Task { public: using Config = TaskConfig; + using PersistentConfig = PersistentConfig; using QConfigPointer = Job::QConfigPointer; using None = Job::None; @@ -273,9 +343,11 @@ public: config->setParent(_config.get()); config->setObjectName(name.c_str()); - // Connect dirty->refresh if defined + // Connect loaded->refresh + QObject::connect(config.get(), SIGNAL(loaded()), _config.get(), SLOT(refresh())); static const char* DIRTY_SIGNAL = "dirty()"; if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + // Connect dirty->refresh if defined QObject::connect(config.get(), SIGNAL(dirty()), _config.get(), SLOT(refresh())); } diff --git a/libraries/shared/src/shared/JSONHelpers.cpp b/libraries/shared/src/shared/JSONHelpers.cpp index e717050055..c7cbf0e724 100644 --- a/libraries/shared/src/shared/JSONHelpers.cpp +++ b/libraries/shared/src/shared/JSONHelpers.cpp @@ -111,7 +111,7 @@ void qObjectFromJsonValue(const QJsonValue& j, QObject& o) { for (auto it = object.begin(); it != object.end(); it++) { std::string key = it.key().toStdString(); if (it.value().isObject()) { - QObject* child = o.findChild(key.c_str(), Qt::FindChildOption::FindDirectChildrenOnly); + QObject* child = o.findChild(key.c_str(), Qt::FindDirectChildrenOnly); if (child) { qObjectFromJsonValue(it.value(), *child); } From d0f3ad75b8f0dbad7f49391a7f69f8580ee5e76d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 11 Feb 2016 10:15:48 -0800 Subject: [PATCH 5/6] Nest Persistent in Config to compile on nix --- .../render-utils/src/AmbientOcclusionEffect.h | 4 +- .../render-utils/src/AntialiasingEffect.h | 4 +- libraries/render-utils/src/RenderShadowTask.h | 4 +- libraries/render/src/render/Task.h | 132 +++++++++--------- 4 files changed, 73 insertions(+), 71 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 442c108af7..717c9dc4fc 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -16,7 +16,7 @@ #include "render/DrawTask.h" -class AmbientOcclusionEffectConfig : public render::Job::PersistentConfig { +class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty) @@ -32,7 +32,7 @@ class AmbientOcclusionEffectConfig : public render::Job::PersistentConfig { Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius) Q_PROPERTY(double gpuTime READ getGpuTime) public: - AmbientOcclusionEffectConfig() : render::Job::PersistentConfig("Ambient Occlusion", false) {} + AmbientOcclusionEffectConfig() : render::Job::Config::Persistent("Ambient Occlusion", false) {} const int MAX_RESOLUTION_LEVEL = 4; const int MAX_BLUR_RADIUS = 6; diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index 000760a2e2..6185ed07dc 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -16,11 +16,11 @@ #include "render/DrawTask.h" -class AntiAliasingConfig : public render::Job::PersistentConfig { +class AntiAliasingConfig : public render::Job::Config::Persistent { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled) public: - AntiAliasingConfig() : render::Job::PersistentConfig("Antialiasing", false) {} + AntiAliasingConfig() : render::Job::Config::Persistent("Antialiasing", false) {} }; class Antialiasing { diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 177a42aff7..679302b69f 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -31,11 +31,11 @@ protected: render::ShapePlumberPointer _shapePlumber; }; -class RenderShadowTaskConfig : public render::Task::PersistentConfig { +class RenderShadowTaskConfig : public render::Task::Config::Persistent { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) public: - RenderShadowTaskConfig() : render::Task::PersistentConfig("Shadows", false) {} + RenderShadowTaskConfig() : render::Task::Config::Persistent("Shadows", false) {} signals: void dirty(); diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 2d29e5eedd..77d179472b 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -61,10 +61,75 @@ class Job; class Task; class JobNoIO {}; +template class PersistentConfig : public C { +public: + const QString DEFAULT = "Default"; + const QString NONE = "None"; + + PersistentConfig() = delete; + PersistentConfig(const QString& path) : + _preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { } + PersistentConfig(const QStringList& path) : + _preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { } + PersistentConfig(const QString& path, bool enabled) : C(enabled), + _preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { } + PersistentConfig(const QStringList& path, bool enabled) : C(enabled), + _preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { } + + QStringList getPresetList() { + if (_presets.empty()) { + setPresetList(QJsonObject()); + } + return _presets.keys(); + } + + virtual void setPresetList(const QJsonObject& list) override { + assert(_presets.empty()); + + _default = toJsonValue(*this).toObject().toVariantMap(); + + _presets.unite(list.toVariantMap()); + if (C::alwaysEnabled || C::enabled) { + _presets.insert(DEFAULT, _default); + } + if (!C::alwaysEnabled) { + _presets.insert(NONE, QVariantMap{{ "enabled", false }}); + } + + auto preset = _preset.get(); + if (preset != _preset.getDefault() && _presets.contains(preset)) { + // Load the persisted configuration + C::load(_presets[preset].toMap()); + } + } + + QString getPreset() { return _preset.get(); } + + void setPreset(const QString& preset) { + _preset.set(preset); + if (_presets.contains(preset)) { + // Always start back at default to remain deterministic + QVariantMap config = _default; + QVariantMap presetConfig = _presets[preset].toMap(); + for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) { + config.insert(it.key(), it.value()); + } + C::load(config); + } + } + +protected: + QVariantMap _default; + QVariantMap _presets; + Setting::Handle _preset; +}; + // A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled) class JobConfig : public QObject { Q_OBJECT public: + using Persistent = PersistentConfig; + JobConfig() = default; JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {} @@ -96,6 +161,8 @@ signals: class TaskConfig : public JobConfig { Q_OBJECT public: + using Persistent = PersistentConfig; + TaskConfig() = default ; TaskConfig(bool enabled) : JobConfig(enabled) {} @@ -116,69 +183,6 @@ private: Task* _task; }; -template class PersistentConfig : public C { -public: - const QString DEFAULT = "Default"; - const QString NONE = "None"; - - PersistentConfig() = delete; - PersistentConfig(const QString& path) : - _preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { } - PersistentConfig(const QStringList& path) : - _preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { } - PersistentConfig(const QString& path, bool enabled) : C(enabled), - _preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { } - PersistentConfig(const QStringList& path, bool enabled) : C(enabled), - _preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { } - - QStringList getPresetList() { - if (_presets.empty()) { - setPresetList(QJsonObject()); - } - return _presets.keys(); - } - - virtual void setPresetList(const QJsonObject& list) override { - assert(_presets.empty()); - - _default = toJsonValue(*this).toObject().toVariantMap(); - - _presets.unite(list.toVariantMap()); - if (alwaysEnabled || enabled) { - _presets.insert(DEFAULT, _default); - } - if (!alwaysEnabled) { - _presets.insert(NONE, QVariantMap{{ "enabled", false }}); - } - - auto preset = _preset.get(); - if (preset != _preset.getDefault() && _presets.contains(preset)) { - // Load the persisted configuration - load(_presets[preset].toMap()); - } - } - - QString getPreset() { return _preset.get(); } - - void setPreset(const QString& preset) { - _preset.set(preset); - if (_presets.contains(preset)) { - // Always start back at default to remain deterministic - QVariantMap config = _default; - QVariantMap presetConfig = _presets[preset].toMap(); - for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) { - config.insert(it.key(), it.value()); - } - load(config); - } - } - -protected: - QVariantMap _default; - QVariantMap _presets; - Setting::Handle _preset; -}; - template void jobConfigure(T& data, const C& configuration) { data.configure(configuration); } @@ -201,7 +205,6 @@ template void jobRun(T& data, const SceneContextPoin class Job { public: using Config = JobConfig; - using PersistentConfig = PersistentConfig; using QConfigPointer = std::shared_ptr; using None = JobNoIO; @@ -289,7 +292,6 @@ public: class Task { public: using Config = TaskConfig; - using PersistentConfig = PersistentConfig; using QConfigPointer = Job::QConfigPointer; using None = Job::None; From 232f06e1757bc18fe15c7b2c700e3e362f6d0065 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 11 Feb 2016 17:28:22 -0800 Subject: [PATCH 6/6] Avoid unnecessary TaskConfig dtor --- libraries/render/src/render/Task.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 77d179472b..de17ef499c 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -308,8 +308,7 @@ public: const Varying getInput() const { return _input; } const Varying getOutput() const { return _output; } - Model(const Varying& input, Data data = Data()) : Concept(std::make_shared()), _data(data), _input(input), _output(Output()) { - _config = _data._config; // use the data's config + Model(const Varying& input, Data data = Data()) : Concept(data._config), _data(data), _input(input), _output(Output()) { std::static_pointer_cast(_config)->init(&_data); applyConfiguration(); }