mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 16:55:06 +02:00
Change graphics dialog to persisted dropdowns
This commit is contained in:
parent
84197e5eb2
commit
a7778daed2
10 changed files with 150 additions and 115 deletions
19
interface/resources/config/render.json
Normal file
19
interface/resources/config/render.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"RenderShadowTask": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"RenderDeferredTask": {
|
||||
"AmbientOcclusion": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"Antialiasing": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1156,7 +1156,7 @@ void Application::initializeGL() {
|
|||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", cullFunctor);
|
||||
_renderEngine->loadConfig();
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
// TODO: Load a cached config file
|
||||
|
||||
|
|
|
@ -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<AmbientOcclusionEffect>();
|
||||
{
|
||||
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<Antialiasing>();
|
||||
{
|
||||
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<AmbientOcclusionEffect>(); };
|
||||
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<AmbientOcclusionEffect>(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<RenderShadowTask>();
|
||||
{
|
||||
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<Antialiasing>(); };
|
||||
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<Antialiasing>(enable); };
|
||||
auto preference = new CheckPreference(RENDER, "Antialiasing", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<RenderShadowTask>(); };
|
||||
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<RenderShadowTask>(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -13,75 +13,39 @@
|
|||
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
|
||||
using namespace render;
|
||||
|
||||
const QString ENGINE_CONFIG_DEFAULT = "Default";
|
||||
// TODO: Presets (e.g., "Highest Performance", "Highest Quality") will go here
|
||||
const QMap<QString, QString> Engine::PRESETS = {};
|
||||
|
||||
Engine::Engine() :
|
||||
_namedConfig(QStringList() << "Render" << "Engine"),
|
||||
_sceneContext(std::make_shared<SceneContext>()),
|
||||
_renderContext(std::make_shared<RenderContext>()) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<QString> _namedConfig;
|
||||
QJsonValue _defaultConfig;
|
||||
|
||||
SceneContextPointer _sceneContext;
|
||||
RenderContextPointer _renderContext;
|
||||
|
||||
private:
|
||||
static const QMap<QString, QString> PRESETS;
|
||||
};
|
||||
using EnginePointer = std::shared_ptr<Engine>;
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <QtCore/qjsonvalue.h>
|
||||
#include <shared/JSONHelpers.h>
|
||||
|
||||
#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<JobConfig*>(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<typename T::Config*>(name);
|
||||
}
|
||||
|
||||
template <class T> void setJobEnabled(bool enable = true, std::string job = "") {
|
||||
assert(getConfig<T>(job)->alwaysEnabled != true);
|
||||
getConfig<T>(job)->enabled = enable;
|
||||
refresh(); // trigger a Job->configure
|
||||
}
|
||||
template <class T> bool isJobEnabled(bool enable = true, std::string job = "") const {
|
||||
return getConfig<T>(job)->isEnabled();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
|
||||
|
@ -111,6 +116,69 @@ private:
|
|||
Task* _task;
|
||||
};
|
||||
|
||||
template <class C> 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<QString> _preset;
|
||||
};
|
||||
|
||||
template <class T, class C> void jobConfigure(T& data, const C& configuration) {
|
||||
data.configure(configuration);
|
||||
}
|
||||
|
@ -133,6 +201,7 @@ template <class T, class I, class O> void jobRun(T& data, const SceneContextPoin
|
|||
class Job {
|
||||
public:
|
||||
using Config = JobConfig;
|
||||
using PersistentConfig = PersistentConfig<Config>;
|
||||
using QConfigPointer = std::shared_ptr<QObject>;
|
||||
using None = JobNoIO;
|
||||
|
||||
|
@ -220,6 +289,7 @@ public:
|
|||
class Task {
|
||||
public:
|
||||
using Config = TaskConfig;
|
||||
using PersistentConfig = PersistentConfig<Config>;
|
||||
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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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<QObject*>(key.c_str(), Qt::FindChildOption::FindDirectChildrenOnly);
|
||||
QObject* child = o.findChild<QObject*>(key.c_str(), Qt::FindDirectChildrenOnly);
|
||||
if (child) {
|
||||
qObjectFromJsonValue(it.value(), *child);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue