Refactored CelestialBodyDefinition, with new sun/moon widget

This commit is contained in:
Michaël Lemaire 2015-12-30 00:20:20 +01:00
parent 06cd5e31fd
commit 61a43410db
34 changed files with 425 additions and 279 deletions

View file

@ -5,29 +5,24 @@
#include "RandomGenerator.h" #include "RandomGenerator.h"
#include "FloatNode.h" #include "FloatNode.h"
#include "GodRaysDefinition.h" #include "GodRaysDefinition.h"
#include "CelestialBodyDefinition.h"
AtmosphereDefinition::AtmosphereDefinition(DefinitionNode *parent) AtmosphereDefinition::AtmosphereDefinition(DefinitionNode *parent)
: DefinitionNode(parent, "atmosphere", "atmosphere") { : DefinitionNode(parent, "atmosphere", "atmosphere") {
model = ATMOSPHERE_MODEL_DISABLED; model = ATMOSPHERE_MODEL_DISABLED;
godrays = new GodRaysDefinition(this); godrays = new GodRaysDefinition(this);
daytime = new FloatNode(this, "daytime"); sun = new CelestialBodyDefinition(this, "sun");
moon = new CelestialBodyDefinition(this, "moon");
humidity = new FloatNode(this, "humidity"); humidity = new FloatNode(this, "humidity");
sun_radius = new FloatNode(this, "sun_radius");
sun_color = COLOR_RED; sun_color = COLOR_RED;
} }
AtmosphereDefinition::~AtmosphereDefinition() {
}
void AtmosphereDefinition::save(PackStream *stream) const { void AtmosphereDefinition::save(PackStream *stream) const {
DefinitionNode::save(stream); DefinitionNode::save(stream);
stream->write((int *)&model); stream->write((int *)&model);
sun_color.save(stream); sun_color.save(stream);
stream->write(&dome_lighting); stream->write(&dome_lighting);
stream->write(&moon_radius);
stream->write(&moon_theta);
stream->write(&moon_phi);
int star_count = stars.size(); int star_count = stars.size();
stream->write(&star_count); stream->write(&star_count);
@ -44,9 +39,6 @@ void AtmosphereDefinition::load(PackStream *stream) {
stream->read((int *)&model); stream->read((int *)&model);
sun_color.load(stream); sun_color.load(stream);
stream->read(&dome_lighting); stream->read(&dome_lighting);
stream->read(&moon_radius);
stream->read(&moon_theta);
stream->read(&moon_phi);
int star_count; int star_count;
stream->read(&star_count); stream->read(&star_count);
@ -66,39 +58,41 @@ void AtmosphereDefinition::load(PackStream *stream) {
void AtmosphereDefinition::copy(DefinitionNode *_destination) const { void AtmosphereDefinition::copy(DefinitionNode *_destination) const {
DefinitionNode::copy(_destination); DefinitionNode::copy(_destination);
AtmosphereDefinition *destination = (AtmosphereDefinition *)_destination; AtmosphereDefinition *destination = static_cast<AtmosphereDefinition *>(_destination);
if (destination) {
destination->model = model;
destination->sun_color = sun_color;
destination->dome_lighting = dome_lighting;
destination->stars = stars;
destination->model = model; destination->validate();
destination->sun_color = sun_color; }
destination->dome_lighting = dome_lighting;
destination->moon_radius = moon_radius;
destination->moon_theta = moon_theta;
destination->moon_phi = moon_phi;
destination->stars = stars;
destination->validate();
} }
void AtmosphereDefinition::setDayTime(double value) { void AtmosphereDefinition::setDayTime(double value) {
daytime->setValue(value); sun->propTheta()->setValue((value + 0.75) * M_2PI);
} }
void AtmosphereDefinition::setDayTime(int hour, int minute, int second) { void AtmosphereDefinition::setDayTime(int hour, int minute, int second) {
setDayTime(to_double(hour) / 24.0 + to_double(minute) / 1440.0 + to_double(second) / 86400.0); setDayTime(to_double(hour) / 24.0 + to_double(minute) / 1440.0 + to_double(second) / 86400.0);
} }
void AtmosphereDefinition::getHMS(int *hour, int *minute, int *second) const { double AtmosphereDefinition::getDaytime() const {
double value = daytime->getValue(); double value = (sun->propTheta()->getValue() / M_2PI) - 0.75;
if (value >= 0.0) { if (value >= 0.0) {
value = fmod(value, 1.0); value = fmod(value, 1.0);
} else { } else {
value = 1.0 - fmod(-value, 1.0); value = 1.0 - fmod(-value, 1.0);
} }
value *= 86400.0; return value;
*hour = value / 3600.0; }
value -= 3600.0 * *hour;
*minute = value / 60.0; void AtmosphereDefinition::getHMS(int *hour, int *minute, int *second) const {
*second = value - *minute * 60.0; double value = getDaytime() * 86400.0;
*hour = round_to_int(value / 3600.0);
value -= 3600.0 * to_double(*hour);
*minute = round_to_int(value / 60.0);
*second = round_to_int(value - to_double(*minute) * 60.0);
} }
void AtmosphereDefinition::applyPreset(AtmospherePreset preset, RandomGenerator &random) { void AtmosphereDefinition::applyPreset(AtmospherePreset preset, RandomGenerator &random) {
@ -106,10 +100,10 @@ void AtmosphereDefinition::applyPreset(AtmospherePreset preset, RandomGenerator
sun_color.g = 0.95; sun_color.g = 0.95;
sun_color.b = 0.9; sun_color.b = 0.9;
sun_color.a = 1.0; sun_color.a = 1.0;
sun_radius->setValue(0.8); sun->propRadius()->setValue(1.0);
moon_radius = 1.0; moon->propRadius()->setValue(1.0);
moon_theta = 0.3; moon->propPhi()->setValue(0.5);
moon_phi = 0.5; moon->propTheta()->setValue(0.3);
model = ATMOSPHERE_MODEL_BRUNETON; model = ATMOSPHERE_MODEL_BRUNETON;
@ -139,8 +133,6 @@ void AtmosphereDefinition::applyPreset(AtmospherePreset preset, RandomGenerator
humidity->setValue(0.9); humidity->setValue(0.9);
dome_lighting = 0.05; dome_lighting = 0.05;
break; break;
default:
;
} }
generateStars(2000, random); generateStars(2000, random);

View file

@ -31,7 +31,6 @@ class DEFINITIONSHARED_EXPORT AtmosphereDefinition : public DefinitionNode {
public: public:
AtmosphereDefinition(DefinitionNode *parent); AtmosphereDefinition(DefinitionNode *parent);
virtual ~AtmosphereDefinition();
virtual void save(PackStream *stream) const override; virtual void save(PackStream *stream) const override;
virtual void load(PackStream *stream) override; virtual void load(PackStream *stream) override;
@ -41,15 +40,15 @@ class DEFINITIONSHARED_EXPORT AtmosphereDefinition : public DefinitionNode {
inline GodRaysDefinition *childGodRays() const { inline GodRaysDefinition *childGodRays() const {
return godrays; return godrays;
} }
inline FloatNode *propDayTime() const { inline CelestialBodyDefinition *childSun() const {
return daytime; return sun;
}
inline CelestialBodyDefinition *childMoon() const {
return moon;
} }
inline FloatNode *propHumidity() const { inline FloatNode *propHumidity() const {
return humidity; return humidity;
} }
inline FloatNode *propSunRadius() const {
return sun_radius;
}
/** /**
* Set the daytime from a 0.0-1.0 value. * Set the daytime from a 0.0-1.0 value.
@ -59,6 +58,10 @@ class DEFINITIONSHARED_EXPORT AtmosphereDefinition : public DefinitionNode {
* Set the daytime from hour/minute/second info. * Set the daytime from hour/minute/second info.
*/ */
void setDayTime(int hour, int minute = 0, int second = 0); void setDayTime(int hour, int minute = 0, int second = 0);
/**
* Get the daytime info, in 0.0-1.0 value.
*/
double getDaytime() const;
/** /**
* Get the daytime info, in hour/minute/second. * Get the daytime info, in hour/minute/second.
*/ */
@ -73,17 +76,13 @@ class DEFINITIONSHARED_EXPORT AtmosphereDefinition : public DefinitionNode {
Color sun_color; Color sun_color;
double dome_lighting; double dome_lighting;
double moon_radius;
double moon_theta;
double moon_phi;
vector<Star> stars; vector<Star> stars;
private: private:
GodRaysDefinition *godrays; GodRaysDefinition *godrays;
CelestialBodyDefinition *sun;
CelestialBodyDefinition *moon;
FloatNode *humidity; FloatNode *humidity;
FloatNode *daytime;
FloatNode *sun_radius;
}; };
} }
} }

View file

@ -0,0 +1,18 @@
#include "CelestialBodyDefinition.h"
#include "Vector3.h"
#include "FloatNode.h"
CelestialBodyDefinition::CelestialBodyDefinition(DefinitionNode *parent, const string &name)
: DefinitionNode(parent, name) {
phi = new FloatNode(this, "phi");
theta = new FloatNode(this, "theta");
radius = new FloatNode(this, "radius");
}
Vector3 CelestialBodyDefinition::getDirection() const {
VectorSpherical spc = {1.0, theta->getValue(), -phi->getValue()};
return Vector3(spc);
}
// VectorSpherical moon_location_s = {MOON_DISTANCE_SCALED, atmosphere->moon_theta, -atmosphere->moon_phi};

View file

@ -0,0 +1,38 @@
#ifndef CELESTIALBODYDEFINITION_H
#define CELESTIALBODYDEFINITION_H
#include "definition_global.h"
#include "DefinitionNode.h"
namespace paysages {
namespace definition {
class DEFINITIONSHARED_EXPORT CelestialBodyDefinition : public DefinitionNode {
public:
CelestialBodyDefinition(DefinitionNode *parent, const string &name);
inline FloatNode *propPhi() const {
return phi;
}
inline FloatNode *propTheta() const {
return theta;
}
inline FloatNode *propRadius() const {
return radius;
}
/**
* Get the normalized direction toward the celestial body (from the center of the earth).
*/
Vector3 getDirection() const;
private:
FloatNode *phi;
FloatNode *theta;
FloatNode *radius;
};
}
}
#endif // CELESTIALBODYDEFINITION_H

View file

@ -14,7 +14,7 @@ TimeManager::TimeManager() {
void TimeManager::moveForward(Scenery *scenery, double amount) { void TimeManager::moveForward(Scenery *scenery, double amount) {
// Move the sun // Move the sun
scenery->getAtmosphere()->setDayTime(scenery->getAtmosphere()->propDayTime()->getValue() + amount); scenery->getAtmosphere()->setDayTime(scenery->getAtmosphere()->getDaytime() + amount);
// Move the clouds // Move the clouds
int n = scenery->getClouds()->getLayerCount(); int n = scenery->getClouds()->getLayerCount();

View file

@ -32,6 +32,7 @@ class LayersDiff;
class CloudsDefinition; class CloudsDefinition;
class CloudLayerDefinition; class CloudLayerDefinition;
class AtmosphereDefinition; class AtmosphereDefinition;
class CelestialBodyDefinition;
class GodRaysDefinition; class GodRaysDefinition;
class TexturesDefinition; class TexturesDefinition;
class TextureLayerDefinition; class TextureLayerDefinition;

View file

@ -270,7 +270,7 @@ static void testAtmosphereBruneton() {
for (int i = 0; i <= 60; i++) { for (int i = 0; i <= 60; i++) {
double daytime = (i < 40) ? (0.24 + 0.0005 * to_double(i)) : (0.26 + 0.005 * to_double(i - 40)); double daytime = (i < 40) ? (0.24 + 0.0005 * to_double(i)) : (0.26 + 0.005 * to_double(i - 40));
scenery.getAtmosphere()->propDayTime()->setValue(daytime); scenery.getAtmosphere()->setDayTime(daytime);
startTestRender(&renderer, "atmosphere_bruneton", i); startTestRender(&renderer, "atmosphere_bruneton", i);
} }
} }

View file

@ -3,19 +3,15 @@
#include "MainModelerWindow.h" #include "MainModelerWindow.h"
#include "Scenery.h" #include "Scenery.h"
#include "AtmosphereDefinition.h" #include "AtmosphereDefinition.h"
#include "FloatPropertyBind.h"
AtmosphereModeler::AtmosphereModeler(MainModelerWindow *main) { AtmosphereModeler::AtmosphereModeler(MainModelerWindow *main) : BaseModelerTool(main) {
prop_daytime = addFloatBinding("atmosphere_humidity", "value", "/atmosphere/humidity");
new FloatPropertyBind(main, "atmosphere_daytime", "value", main->getScenery()->getAtmosphere()->propDayTime()); addFloatBinding("atmosphere_sun_direction", "phi", "/atmosphere/sun/phi");
prop_humidity = new FloatPropertyBind(main, "atmosphere_humidity", "value", addFloatBinding("atmosphere_sun_direction", "theta", "/atmosphere/sun/theta");
main->getScenery()->getAtmosphere()->propHumidity()); addFloatBinding("atmosphere_sun_radius", "value", "/atmosphere/sun/radius");
prop_sun_radius = new FloatPropertyBind(main, "atmosphere_sun_radius", "value", addFloatBinding("atmosphere_moon_direction", "phi", "/atmosphere/moon/phi");
main->getScenery()->getAtmosphere()->propSunRadius()); addFloatBinding("atmosphere_moon_direction", "theta", "/atmosphere/moon/theta");
} // addFloatBinding("atmosphere_moon_radius", "value", "/atmosphere/moon/radius");
AtmosphereModeler::~AtmosphereModeler() { main->setQmlProperty("atmosphere_daytime", "value", main->getScenery()->getAtmosphere()->getDaytime());
delete prop_daytime;
delete prop_humidity;
delete prop_sun_radius;
} }

View file

@ -3,18 +3,14 @@
#include "modeler_global.h" #include "modeler_global.h"
#include "BaseModelerTool.h"
namespace paysages { namespace paysages {
namespace modeler { namespace modeler {
class AtmosphereModeler { class AtmosphereModeler : protected BaseModelerTool {
public: public:
AtmosphereModeler(MainModelerWindow *main); AtmosphereModeler(MainModelerWindow *main);
~AtmosphereModeler();
private:
FloatPropertyBind *prop_daytime;
FloatPropertyBind *prop_humidity;
FloatPropertyBind *prop_sun_radius;
}; };
} }
} }

View file

@ -0,0 +1,39 @@
#include "BaseModelerTool.h"
#include "MainModelerWindow.h"
#include "Scenery.h"
#include "IntNode.h"
#include "IntPropertyBind.h"
#include "FloatNode.h"
#include "FloatPropertyBind.h"
#include "Logs.h"
class BaseModelerTool::pimpl {
public:
vector<unique_ptr<IntPropertyBind>> int_bindings;
vector<unique_ptr<FloatPropertyBind>> float_bindings;
};
BaseModelerTool::BaseModelerTool(MainModelerWindow *main) : impl(new pimpl), main(main) {
}
BaseModelerTool::~BaseModelerTool() {
}
void BaseModelerTool::addIntBinding(const string &object, const string &property, const string &path) {
auto node = static_cast<IntNode *>(main->getScenery()->findByPath(path));
if (node) {
impl->int_bindings.push_back(make_unique<IntPropertyBind>(main, object, property, node));
} else {
Logs::error("UI") << "Can't find int node for binding : " << path << endl;
}
}
void BaseModelerTool::addFloatBinding(const string &object, const string &property, const string &path) {
auto node = static_cast<FloatNode *>(main->getScenery()->findByPath(path));
if (node) {
impl->float_bindings.push_back(make_unique<FloatPropertyBind>(main, object, property, node));
} else {
Logs::error("UI") << "Can't find float node for binding : " << path << endl;
}
}

View file

@ -0,0 +1,35 @@
#ifndef BASEMODELERTOOL_H
#define BASEMODELERTOOL_H
#include "modeler_global.h"
#include <memory>
namespace paysages {
namespace modeler {
class BaseModelerTool {
public:
BaseModelerTool(MainModelerWindow *main);
virtual ~BaseModelerTool();
/**
* Add an automated two-way binding between a QML int property and a scenery IntNode.
*/
void addIntBinding(const string &object, const string &property, const string &path);
/**
* Add an automated two-way binding between a QML int property and a scenery IntNode.
*/
void addFloatBinding(const string &object, const string &property, const string &path);
private:
class pimpl;
unique_ptr<pimpl> impl;
MainModelerWindow *main;
};
}
}
#endif // BASEMODELERTOOL_H

View file

@ -6,27 +6,30 @@
#include <cmath> #include <cmath>
FloatPropertyBind::FloatPropertyBind(MainModelerWindow *window, const QString &object_name, FloatPropertyBind::FloatPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
const QString &property_name, FloatNode *node) FloatNode *node)
: QObject(window), node(node), property(property_name) { : QObject(window), node(node), property(property_name) {
item = window->findQmlObject(object_name); item = window->findQmlObject(object_name);
if (item) { if (item) {
node->addWatcher(this, true); node->addWatcher(this, true);
connect(item, SIGNAL(changed(double)), this, SLOT(propertyChanged(double))); string signal_name("2" + property_name + "Changed()");
connect(item, signal_name.c_str(), this, SLOT(propertyChanged()));
} else { } else {
item = NULL; item = NULL;
Logs::error("UI") << "Can't find object :" << object_name.toStdString() << endl; Logs::error("UI") << "Can't find object :" << object_name << endl;
} }
} }
void FloatPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) { void FloatPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) {
if (item) { if (item) {
item->setProperty(property.toLocal8Bit(), node->getValue()); item->setProperty(property.c_str(), node->getValue());
} }
} }
void FloatPropertyBind::propertyChanged(double value) { void FloatPropertyBind::propertyChanged() {
if (fabs(value - node->getValue()) > 0.00000001) { bool ok;
double value = item->property(property.c_str()).toDouble(&ok);
if (ok and fabs(value - node->getValue()) > 0.00000001) {
node->setValue(value); node->setValue(value);
} }
} }

View file

@ -17,17 +17,17 @@ namespace modeler {
class FloatPropertyBind : public QObject, public DefinitionWatcher { class FloatPropertyBind : public QObject, public DefinitionWatcher {
Q_OBJECT Q_OBJECT
public: public:
FloatPropertyBind(MainModelerWindow *window, const QString &object_name, const QString &property_name, FloatPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
FloatNode *node); FloatNode *node);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override; virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
private slots: private slots:
void propertyChanged(double value); void propertyChanged();
private: private:
FloatNode *node; FloatNode *node;
QString property; string property;
QObject *item; QObject *item;
}; };
} }

View file

@ -4,27 +4,30 @@
#include "IntNode.h" #include "IntNode.h"
#include "Logs.h" #include "Logs.h"
IntPropertyBind::IntPropertyBind(MainModelerWindow *window, const QString &object_name, const QString &property_name, IntPropertyBind::IntPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
IntNode *node) IntNode *node)
: QObject(window), node(node), property(property_name) { : QObject(window), node(node), property(property_name) {
item = window->findQmlObject(object_name); item = window->findQmlObject(object_name);
if (item) { if (item) {
node->addWatcher(this, true); node->addWatcher(this, true);
connect(item, SIGNAL(changed(int)), this, SLOT(propertyChanged(int))); string signal_name("2" + property_name + "Changed()");
connect(item, signal_name.c_str(), this, SLOT(propertyChanged()));
} else { } else {
item = NULL; item = NULL;
Logs::error("UI") << "Can't find object :" << object_name.toStdString() << endl; Logs::error("UI") << "Can't find object :" << object_name << endl;
} }
} }
void IntPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) { void IntPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) {
if (item) { if (item) {
item->setProperty(property.toLocal8Bit(), node->getValue()); item->setProperty(property.c_str(), node->getValue());
} }
} }
void IntPropertyBind::propertyChanged(int value) { void IntPropertyBind::propertyChanged() {
if (value != node->getValue()) { bool ok;
int value = item->property(property.c_str()).toInt(&ok);
if (ok and value != node->getValue()) {
node->setValue(value); node->setValue(value);
} }
} }

View file

@ -17,16 +17,16 @@ namespace modeler {
class IntPropertyBind : public QObject, public DefinitionWatcher { class IntPropertyBind : public QObject, public DefinitionWatcher {
Q_OBJECT Q_OBJECT
public: public:
IntPropertyBind(MainModelerWindow *window, const QString &object_name, const QString &property_name, IntNode *node); IntPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name, IntNode *node);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override; virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
private slots: private slots:
void propertyChanged(int value); void propertyChanged();
private: private:
IntNode *node; IntNode *node;
QString property; string property;
QObject *item; QObject *item;
}; };
} }

View file

@ -60,39 +60,39 @@ MainModelerWindow::~MainModelerWindow() {
delete scenery; delete scenery;
} }
QObject *MainModelerWindow::findQmlObject(const QString &objectName) { QObject *MainModelerWindow::findQmlObject(const string &objectName) {
if (objectName == "ui" || objectName == "root") { if (objectName == "ui" || objectName == "root") {
return rootObject(); return rootObject();
} else { } else {
return rootObject()->findChild<QObject *>(objectName); return rootObject()->findChild<QObject *>(QString::fromStdString(objectName));
} }
} }
void MainModelerWindow::setQmlProperty(const QString &objectName, const QString &propertyName, const QVariant &value) { void MainModelerWindow::setQmlProperty(const string &objectName, const string &propertyName, const QVariant &value) {
QObject *item = findQmlObject(objectName); QObject *item = findQmlObject(objectName);
if (item) { if (item) {
item->setProperty(propertyName.toLocal8Bit(), value); item->setProperty(propertyName.c_str(), value);
} else { } else {
Logs::error("UI") << "QML object not found :" << objectName.toStdString() << endl; Logs::error("UI") << "QML object not found :" << objectName << endl;
} }
} }
void MainModelerWindow::connectQmlSignal(const QString &objectName, const char *signal, const QObject *receiver, void MainModelerWindow::connectQmlSignal(const string &objectName, const char *signal, const QObject *receiver,
const char *method) { const char *method) {
QObject *item = findQmlObject(objectName); QObject *item = findQmlObject(objectName);
if (item) { if (item) {
connect(item, signal, receiver, method); connect(item, signal, receiver, method);
} else { } else {
Logs::error("UI") << "QML object not found :" << objectName.toStdString() << endl; Logs::error("UI") << "QML object not found :" << objectName << endl;
} }
} }
QString MainModelerWindow::getState() const { string MainModelerWindow::getState() const {
return rootObject()->property("state").toString(); return rootObject()->property("state").toString().toStdString();
} }
void MainModelerWindow::setState(const QString &stateName) { void MainModelerWindow::setState(const string &stateName) {
rootObject()->setProperty("state", stateName); rootObject()->setProperty("state", QString::fromStdString(stateName));
} }
void MainModelerWindow::newFile() { void MainModelerWindow::newFile() {

View file

@ -14,12 +14,12 @@ class MainModelerWindow : public QQuickView {
MainModelerWindow(); MainModelerWindow();
virtual ~MainModelerWindow(); virtual ~MainModelerWindow();
QObject *findQmlObject(const QString &objectName); QObject *findQmlObject(const string &objectName);
void setQmlProperty(const QString &objectName, const QString &propertyName, const QVariant &value); void setQmlProperty(const string &objectName, const string &propertyName, const QVariant &value);
void connectQmlSignal(const QString &objectName, const char *signal, const QObject *receiver, const char *method); void connectQmlSignal(const string &objectName, const char *signal, const QObject *receiver, const char *method);
QString getState() const; string getState() const;
void setState(const QString &stateName); void setState(const string &stateName);
inline Scenery *getScenery() const { inline Scenery *getScenery() const {
return scenery; return scenery;

View file

@ -62,7 +62,8 @@ void ModelerCameras::startSunTool() {
current->copy(tool); current->copy(tool);
active = tool; active = tool;
parent->getScenery()->getAtmosphere()->propDayTime()->addWatcher(this, true); // FIXME
// parent->getScenery()->getAtmosphere()->propDayTime()->addWatcher(this, true);
} }
void ModelerCameras::endTool() { void ModelerCameras::endTool() {

View file

@ -149,7 +149,7 @@ void RenderProcess::stopRender() {
renderer->interrupt(); renderer->interrupt();
} else { } else {
destination->hide(); destination->hide();
window->setState(window->rootObject()->property("previous_state").toString()); window->setState(window->rootObject()->property("previous_state").toString().toStdString());
} }
} }

View file

@ -10,6 +10,8 @@ namespace modeler {
class MainModelerWindow; class MainModelerWindow;
class OpenGLView; class OpenGLView;
class BaseModelerTool;
class AtmosphereModeler; class AtmosphereModeler;
class WaterModeler; class WaterModeler;

View file

@ -2,7 +2,5 @@ import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
Slider { Slider {
signal changed(real value)
onValueChanged: changed(value)
opacity: enabled ? 1.0 : 0.1 opacity: enabled ? 1.0 : 0.1
} }

View file

@ -1,148 +1,49 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
BasePanel { BasePanel {
id: daytime width: 200
width: 100
objectName: "atmosphere_daytime" Column {
default property real value: day_night.value == 2 ? 0.0 : slider.value * 0.54 + 0.23; anchors.centerIn: parent
signal changed(real value) width: parent.width - 10
spacing: 30
onValueChanged: { Text {
changed(value); text: "Sun location in the sky"
day_night.value = (value >= 0.23 && value <= 0.77) ? 1 : 2; anchors.horizontalCenter: parent.horizontalCenter
if (day_night.value == 1) }
{
slider.value = (value - 0.23) / 0.54; WidgetSphericalCoords {
id: atmosphere_sun_direction
objectName: "atmosphere_sun_direction"
anchors.horizontalCenter: parent.horizontalCenter
icon: "images/icon_atmosphere_day.png"
width: parent.width
}
Text {
text: "Time of day"
anchors.horizontalCenter: parent.horizontalCenter
}
WidgetDayTime {
id: atmosphere_daytime
objectName: "atmosphere_daytime"
anchors.horizontalCenter: parent.horizontalCenter
onValueChanged: atmosphere_sun_direction.theta = (atmosphere_daytime.value + 0.75) * Math.PI * 2.0
}
Text {
text: "Moon location in the sky"
anchors.horizontalCenter: parent.horizontalCenter
}
WidgetSphericalCoords {
id: atmosphere_moon_direction
objectName: "atmosphere_moon_direction"
icon: "images/icon_atmosphere_night.png"
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
} }
} }
ColumnLayout
{
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
spacing: 20
Item {height: 1}
BaseChoice {
id: day_night
Layout.alignment: Qt.AlignHCenter
spacing: 10
width: 90
height: 40
BaseChoiceItem {
icon: "images/icon_atmosphere_day.png"
value: 1
checked: true
}
BaseChoiceItem {
icon: "images/icon_atmosphere_night.png"
value: 2
}
}
BaseSlider {
id: slider
orientation: Qt.Vertical
Layout.maximumWidth: 15
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
}
Grid {
id: clock
property int hour: daytime.value * 86400 / 3600
property int minute: (daytime.value * 86400 - 3600 * hour) / 60
property int second: daytime.value * 86400 - 3600 * hour - 60 * minute
rows: 3
columns: 5
rowSpacing: 4
ClickableImage {
width: 20
height: 10
source: "qrc:/images/arrow_up.png"
onClicked: slider.value += (1.0 / 24.0) / 0.54
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "qrc:/images/arrow_up.png"
onClicked: slider.value += (1.0 / 1440.0) / 0.54
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "qrc:/images/arrow_up.png"
onClicked: slider.value += (1.0 / 86400.0) / 0.54
}
Text {
text: (clock.hour > 9 ? "" : "0") + clock.hour.toString()
font.pixelSize: 14
}
Text {
text: " : "
font.pixelSize: 14
}
Text {
text: (clock.minute > 9 ? "" : "0") + clock.minute.toString()
font.pixelSize: 14
}
Text {
text: " : "
font.pixelSize: 14
}
Text {
text: (clock.second > 9 ? "" : "0") + clock.second.toString()
font.pixelSize: 14
}
ClickableImage {
width: 20
height: 10
source: "qrc:/images/arrow_down.png"
onClicked: slider.value -= (1.0 / 24.0) / 0.54
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "qrc:/images/arrow_down.png"
onClicked: slider.value -= (1.0 / 1440.0) / 0.54
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "qrc:/images/arrow_down.png"
onClicked: slider.value -= (1.0 / 86400.0) / 0.54
}
}
Item {height: 1}
}
states: [
State {
name: "night"
when: day_night.value == 2
PropertyChanges {
target: slider
enabled: false
}
PropertyChanges {
target: clock
enabled: false
}
}
]
} }

View file

@ -8,7 +8,6 @@ BasePanel {
property alias items: container.children property alias items: container.children
property int value: -1 property int value: -1
width: items[0].width + 10 width: items[0].width + 10
signal changed(int value)
ExclusiveGroup { ExclusiveGroup {
id: exclusive_item id: exclusive_item
@ -30,7 +29,6 @@ BasePanel {
exclusive_item.current = null; exclusive_item.current = null;
} }
} }
changed(value);
} }
onItemsChanged: { onItemsChanged: {

View file

@ -0,0 +1,77 @@
import QtQuick 2.0
Grid {
id: clock
property real value
property int hour: value * 86400 / 3600
property int minute: (value * 86400 - 3600 * hour) / 60
property int second: value * 86400 - 3600 * hour - 60 * minute
rows: 3
columns: 5
rowSpacing: 4
ClickableImage {
width: 20
height: 10
source: "images/arrow_up.png"
onClicked: value += 1.0 / 24.0
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "images/arrow_up.png"
onClicked: value += 1.0 / 1440.0
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "images/arrow_up.png"
onClicked: value += 1.0 / 86400.0
}
Text {
text: (clock.hour > 9 ? "" : "0") + clock.hour.toString()
font.pixelSize: 14
}
Text {
text: " : "
font.pixelSize: 14
}
Text {
text: (clock.minute > 9 ? "" : "0") + clock.minute.toString()
font.pixelSize: 14
}
Text {
text: " : "
font.pixelSize: 14
}
Text {
text: (clock.second > 9 ? "" : "0") + clock.second.toString()
font.pixelSize: 14
}
ClickableImage {
width: 20
height: 10
source: "images/arrow_down.png"
onClicked: value -= 1.0 / 24.0
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "images/arrow_down.png"
onClicked: value -= 1.0 / 1440.0
}
Item {width: 1; height: 1}
ClickableImage {
width: 20
height: 10
source: "images/arrow_down.png"
onClicked: value -= 1.0 / 86400.0
}
}

View file

@ -0,0 +1,45 @@
import QtQuick 2.0
// Widget to edit spherical coordinates
Row {
id: widget
property real theta: 0
property real phi: 0
property string icon
height: width / 2
Item {
height: parent.height
width: height
Image {
source: "images/bg_phi_coord.png"
anchors.fill: parent
}
Image {
source: widget.icon
width: parent.width / 10
height: parent.width / 10
anchors.centerIn: parent
anchors.horizontalCenterOffset: width * 4 * Math.cos(phi) * Math.cos(theta)
anchors.verticalCenterOffset: -width * 4 * Math.sin(phi) * Math.cos(theta)
}
}
Item {
height: parent.height
width: height
Image {
source: "images/bg_theta_coord.png"
anchors.fill: parent
}
Image {
source: widget.icon
width: parent.width / 10
height: parent.width / 10
anchors.centerIn: parent
anchors.horizontalCenterOffset: width * 4.5 * Math.cos(theta)
anchors.verticalCenterOffset: -width * 4.5 * Math.sin(theta)
}
}
}

View file

@ -53,5 +53,9 @@
<file>images/icon_render_final.png</file> <file>images/icon_render_final.png</file>
<file>images/icon_cancel.png</file> <file>images/icon_cancel.png</file>
<file>images/icon_sun_radius.png</file> <file>images/icon_sun_radius.png</file>
<file>images/bg_phi_coord.png</file>
<file>WidgetSphericalCoords.qml</file>
<file>images/bg_theta_coord.png</file>
<file>WidgetDayTime.qml</file>
</qresource> </qresource>
</RCC> </RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View file

@ -12,9 +12,10 @@
#include "FloatNode.h" #include "FloatNode.h"
#include "Logs.h" #include "Logs.h"
static const string path_daytime = "/atmosphere/daytime";
static const string path_humidity = "/atmosphere/humidity"; static const string path_humidity = "/atmosphere/humidity";
static const string path_sun_radius = "/atmosphere/sun_radius"; static const string path_sun_phi = "/atmosphere/sun/phi";
static const string path_sun_theta = "/atmosphere/sun/theta";
static const string path_sun_radius = "/atmosphere/sun/radius";
OpenGLSkybox::OpenGLSkybox(OpenGLRenderer *renderer) : OpenGLPart(renderer, "skybox") { OpenGLSkybox::OpenGLSkybox(OpenGLRenderer *renderer) : OpenGLPart(renderer, "skybox") {
program = createShader("skybox"); program = createShader("skybox");
@ -56,9 +57,10 @@ OpenGLSkybox::~OpenGLSkybox() {
void OpenGLSkybox::initialize() { void OpenGLSkybox::initialize() {
// Watch for definition changes // Watch for definition changes
Scenery *scenery = renderer->getScenery(); Scenery *scenery = renderer->getScenery();
startWatching(scenery, path_daytime); startWatching(scenery, path_sun_phi);
startWatching(scenery, path_humidity); startWatching(scenery, path_sun_theta);
startWatching(scenery, path_sun_radius); startWatching(scenery, path_sun_radius);
startWatching(scenery, path_humidity);
} }
void OpenGLSkybox::update() { void OpenGLSkybox::update() {
@ -79,14 +81,14 @@ void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff
OpenGLSharedState *state = renderer->getSharedState(); OpenGLSharedState *state = renderer->getSharedState();
AtmosphereDefinition *newdef = renderer->getScenery()->getAtmosphere(); AtmosphereDefinition *newdef = renderer->getScenery()->getAtmosphere();
if (node->getPath() == path_daytime) { if (node->getPath() == path_sun_phi or node->getPath() == path_sun_theta) {
Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection(false); Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection(false);
state->set("sunDirection", sun_direction); state->set("sunDirection", sun_direction);
Color sun_color = newdef->sun_color; Color sun_color = newdef->sun_color;
state->set("sunColor", sun_color); state->set("sunColor", sun_color);
state->set("dayTime", newdef->propDayTime()->getValue()); state->set("dayTime", newdef->getDaytime());
} }
DefinitionWatcher::nodeChanged(node, diff); DefinitionWatcher::nodeChanged(node, diff);

View file

@ -9,12 +9,7 @@
#include "Thread.h" #include "Thread.h"
#include "Mutex.h" #include "Mutex.h"
#include "OpenGLTerrainChunk.h" #include "OpenGLTerrainChunk.h"
#include "WaterRenderer.h"
#include "CameraDefinition.h"
#include "AtmosphereDefinition.h"
#include "Scenery.h" #include "Scenery.h"
#include "FloatNode.h"
#include "FloatDiff.h"
class ChunkMaintenanceThreads : public ParallelPool { class ChunkMaintenanceThreads : public ParallelPool {
public: public:
@ -92,8 +87,11 @@ void OpenGLTerrain::initialize() {
work->start(); work->start();
// Watch for definition changes // Watch for definition changes
renderer->getScenery()->getTerrain()->propWaterHeight()->addWatcher(this); startWatching(renderer->getScenery(), "/terrain/water_height");
renderer->getScenery()->getAtmosphere()->propDayTime()->addWatcher(this); startWatching(renderer->getScenery(), "/atmosphere/sun/phi");
startWatching(renderer->getScenery(), "/atmosphere/sun/theta");
startWatching(renderer->getScenery(), "/atmosphere/moon/phi");
startWatching(renderer->getScenery(), "/atmosphere/moon/theta");
} }
void OpenGLTerrain::update() { void OpenGLTerrain::update() {
@ -170,7 +168,7 @@ void OpenGLTerrain::performChunksMaintenance() {
void OpenGLTerrain::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) { void OpenGLTerrain::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
if (node->getPath() == "/terrain/water_height") { if (node->getPath() == "/terrain/water_height") {
resetTextures(); resetTextures();
} else if (node->getPath() == "/atmosphere/daytime") { } else if (node->getPath().find("/atmosphere") == 0) {
resetTextures(); resetTextures();
} }
} }

View file

@ -18,6 +18,7 @@
#include "AtmosphereResult.h" #include "AtmosphereResult.h"
#include "SoftwareRenderer.h" #include "SoftwareRenderer.h"
#include "WaterRenderer.h" #include "WaterRenderer.h"
#include "CelestialBodyDefinition.h"
#include "LightComponent.h" #include "LightComponent.h"
#include "LightStatus.h" #include "LightStatus.h"
#include "Texture2D.h" #include "Texture2D.h"
@ -1079,7 +1080,7 @@ AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3
AtmosphereResult result; AtmosphereResult result;
Vector3 attenuation; Vector3 attenuation;
Color sunColor = Color sunColor =
_sunColor(v, s, r, mu, parent->getScenery()->getAtmosphere()->propSunRadius()->getValue()); /* L0 */ _sunColor(v, s, r, mu, parent->getScenery()->getAtmosphere()->childSun()->propRadius()->getValue()); /* L0 */
/*result.base.r = base.r + sunColor.r; /*result.base.r = base.r + sunColor.r;
result.base.g = base.g + sunColor.g; result.base.g = base.g + sunColor.g;

View file

@ -10,6 +10,7 @@
#include "LightStatus.h" #include "LightStatus.h"
#include "Scenery.h" #include "Scenery.h"
#include "NightSky.h" #include "NightSky.h"
#include "CelestialBodyDefinition.h"
#include "FloatNode.h" #include "FloatNode.h"
/* Factor to convert software units to kilometers */ /* Factor to convert software units to kilometers */
@ -40,7 +41,7 @@ static inline void _applyWeatherEffects(AtmosphereDefinition *definition, Atmosp
} }
distancefactor = (distance > max_distance ? max_distance : distance) / max_distance; distancefactor = (distance > max_distance ? max_distance : distance) / max_distance;
/* TODO Get day lighting from model */ /* TODO Get day lighting from model */
dayfactor = _getDayFactor(definition->propDayTime()->getValue()); dayfactor = _getDayFactor(definition->getDaytime());
/* Fog masking */ /* Fog masking */
if (humidity > 0.3) { if (humidity > 0.3) {
@ -87,9 +88,7 @@ AtmosphereResult BaseAtmosphereRenderer::getSkyColor(const Vector3 &) {
} }
Vector3 BaseAtmosphereRenderer::getSunDirection(bool) const { Vector3 BaseAtmosphereRenderer::getSunDirection(bool) const {
AtmosphereDefinition *atmosphere = getDefinition(); return getDefinition()->childSun()->getDirection();
double sun_angle = (atmosphere->propDayTime()->getValue() + 0.75) * M_PI * 2.0;
return Vector3(cos(sun_angle), sin(sun_angle), 0.0);
} }
bool BaseAtmosphereRenderer::getLightsAt(vector<LightComponent> &, const Vector3 &) const { bool BaseAtmosphereRenderer::getLightsAt(vector<LightComponent> &, const Vector3 &) const {

View file

@ -10,6 +10,8 @@
#include "SurfaceMaterial.h" #include "SurfaceMaterial.h"
#include "LightComponent.h" #include "LightComponent.h"
#include "LightStatus.h" #include "LightStatus.h"
#include "CelestialBodyDefinition.h"
#include "FloatNode.h"
#define WORLD_SCALING 0.05 #define WORLD_SCALING 0.05
#define MOON_DISTANCE 384403.0 #define MOON_DISTANCE 384403.0
@ -56,11 +58,10 @@ const Color NightSky::getColor(double altitude, const Vector3 &direction) {
} }
// Get moon // Get moon
VectorSpherical moon_location_s = {MOON_DISTANCE_SCALED, atmosphere->moon_theta, -atmosphere->moon_phi}; Vector3 moon_direction = atmosphere->childMoon()->getDirection();
Vector3 moon_position(moon_location_s); Vector3 moon_position = moon_direction.scale(MOON_DISTANCE_SCALED);
Vector3 moon_direction = moon_position.normalize();
if (moon_direction.dotProduct(direction) >= 0) { if (moon_direction.dotProduct(direction) >= 0) {
double moon_radius = MOON_RADIUS_SCALED * 5.0 * atmosphere->moon_radius; double moon_radius = MOON_RADIUS_SCALED * 5.0 * atmosphere->childMoon()->propRadius()->getValue();
Vector3 hit1, hit2; Vector3 hit1, hit2;
int hits = Geometry::rayIntersectSphere(location, direction, moon_position, moon_radius, &hit1, &hit2); int hits = Geometry::rayIntersectSphere(location, direction, moon_position, moon_radius, &hit1, &hit2);
if (hits > 1) { if (hits > 1) {
@ -87,10 +88,9 @@ bool NightSky::getLightsAt(vector<LightComponent> &result, const Vector3 &) cons
LightComponent moon, sky; LightComponent moon, sky;
AtmosphereDefinition *atmosphere = renderer->getScenery()->getAtmosphere(); AtmosphereDefinition *atmosphere = renderer->getScenery()->getAtmosphere();
VectorSpherical moon_location_s = {MOON_DISTANCE_SCALED, atmosphere->moon_theta, -atmosphere->moon_phi};
moon.color = Color(0.03, 0.03, 0.03); // TODO take moon phase into account moon.color = Color(0.03, 0.03, 0.03); // TODO take moon phase into account
moon.direction = Vector3(moon_location_s).normalize().scale(-1.0); moon.direction = atmosphere->childMoon()->getDirection().scale(-1.0);
moon.reflection = 0.2; moon.reflection = 0.2;
moon.altered = 1; moon.altered = 1;

View file

@ -10,15 +10,15 @@ TEST(Scenery, saveGlobal) {
Scenery scenery1; Scenery scenery1;
scenery1.autoPreset(); scenery1.autoPreset();
scenery1.getTerrain()->propWaterHeight()->setValue(0.2); scenery1.getTerrain()->propWaterHeight()->setValue(0.2);
scenery1.getAtmosphere()->propDayTime()->setValue(0.53); scenery1.getAtmosphere()->setDayTime(0.53);
Scenery::FileOperationResult result = scenery1.saveGlobal("/tmp/test_paysages_scenery"); Scenery::FileOperationResult result = scenery1.saveGlobal("/tmp/test_paysages_scenery");
EXPECT_EQ((int)Scenery::FILE_OPERATION_OK, result); EXPECT_EQ(Scenery::FILE_OPERATION_OK, result);
Scenery scenery2; Scenery scenery2;
result = scenery2.loadGlobal("/tmp/test_paysages_scenery"); result = scenery2.loadGlobal("/tmp/test_paysages_scenery");
EXPECT_EQ((int)Scenery::FILE_OPERATION_OK, result); EXPECT_EQ(Scenery::FILE_OPERATION_OK, result);
EXPECT_DOUBLE_EQ(0.2, scenery2.getTerrain()->propWaterHeight()->getValue()); EXPECT_DOUBLE_EQ(0.2, scenery2.getTerrain()->propWaterHeight()->getValue());
EXPECT_DOUBLE_EQ(0.53, scenery2.getAtmosphere()->propDayTime()->getValue()); EXPECT_DOUBLE_EQ(0.53, scenery2.getAtmosphere()->getDaytime());
} }