Added daytime control to QtQuick UI

This commit is contained in:
Michaël Lemaire 2014-08-28 15:09:47 +02:00
parent 2251db361c
commit d0a5f19cc5
28 changed files with 486 additions and 15 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -7,6 +7,7 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm" width="210mm"
@ -27,18 +28,19 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="3.959798" inkscape:zoom="1.979899"
inkscape:cx="170.49504" inkscape:cx="468.77289"
inkscape:cy="957.94588" inkscape:cy="831.55692"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="g3986"
showgrid="true" showgrid="true"
inkscape:window-width="1920" inkscape:window-width="1920"
inkscape:window-height="1030" inkscape:window-height="1030"
inkscape:window-x="1440" inkscape:window-x="1440"
inkscape:window-y="25" inkscape:window-y="25"
inkscape:window-maximized="1" inkscape:window-maximized="1"
showguides="true"> showguides="true"
inkscape:snap-object-midpoints="false">
<inkscape:grid <inkscape:grid
type="xygrid" type="xygrid"
id="grid3004" /> id="grid3004" />
@ -51,7 +53,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -95,5 +97,100 @@
id="path3807" id="path3807"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" /> sodipodi:nodetypes="ccccccccccc" />
<g
id="g3986">
<g
id="g3969">
<path
sodipodi:type="arc"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:3.58400011;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3819"
sodipodi:cx="70"
sodipodi:cy="187.36218"
sodipodi:rx="35"
sodipodi:ry="35"
d="m 105,187.36218 c 0,19.32997 -15.670034,35 -35,35 -19.329966,0 -35,-15.67003 -35,-35 0,-19.32996 15.670034,-35 35,-35 19.329966,0 35,15.67004 35,35 z"
transform="translate(5.3571428,58.571429)" />
<g
id="g3961">
<path
inkscape:connector-curvature="0"
id="path3821"
d="m 75,182.36218 0,20"
style="fill:none;stroke:#000000;stroke-width:6.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3821-7"
d="m 75,290.21932 0,20"
style="fill:none;stroke:#000000;stroke-width:6.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
style="fill:none;stroke:#000000;stroke-width:6.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 19.636234,214.32646 17.320508,10"
id="path3862"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:6.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 113.04326,268.25503 17.32051,10"
id="path3864"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3866"
d="m 19.636235,278.25503 17.320508,-10"
style="fill:none;stroke:#000000;stroke-width:6.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3868"
d="m 113.04326,224.32646 17.32051,-10"
style="fill:none;stroke:#000000;stroke-width:6.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
</g>
<g
id="g3979">
<path
style="fill:none;stroke:#000000;stroke-width:7.0999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:14.2, 28.4;stroke-dashoffset:0"
d="m 194.28571,244.50504 -85,125"
id="path3884"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:7.0999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:14.2, 28.4;stroke-dashoffset:0"
d="m 212.82124,240.1624 -85,125"
id="path3884-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:7.0999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:14.2, 28.4;stroke-dashoffset:0"
d="m 213.12327,258.90099 -85,125"
id="path3884-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:7.0999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:14.2, 28.4;stroke-dashoffset:0"
d="m 236.40754,248.54565 -85,125"
id="path3884-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:7.0999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:14.2, 28.4;stroke-dashoffset:0"
d="m 241.60804,265.97206 -85,125"
id="path3884-7"
inkscape:connector-curvature="0" />
</g>
<use
x="0"
y="0"
xlink:href="#g3969"
id="use4014"
transform="translate(329.54824,-14.835395)"
width="744.09448"
height="1052.3622" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:7.0999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
d="m 589.06344,183.95535 c -3.46775,0 -6.83723,0.35694 -10.09375,1.0625 21.37557,4.63457 37.40625,23.67418 37.40625,46.4375 0,22.76332 -16.03068,41.77168 -37.40625,46.40625 3.25652,0.70556 6.626,1.09375 10.09375,1.09375 26.23353,0 47.5,-21.26647 47.5,-47.5 0,-26.23353 -21.26647,-47.5 -47.5,-47.5 z"
id="path4016"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:5.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:10.2,10.2;stroke-dashoffset:0"
d="m 440,292.36218 65,95 70,-95"
id="path4025"
inkscape:connector-curvature="0" />
</g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View file

@ -105,6 +105,22 @@ void AtmosphereDefinition::validate()
_daytime = (double)hour / 24.0 + (double)minute / 1440.0; _daytime = (double)hour / 24.0 + (double)minute / 1440.0;
} }
void AtmosphereDefinition::setDaytime(double value)
{
if (value >= 0.0)
{
value = fmod(value, 1.0);
}
else
{
value = 1.0 - fmod(-value, 1.0);
}
value *= 1440.0;
hour = value / 60.0;
minute = value - 60.0 * hour;
validate();
}
void AtmosphereDefinition::applyPreset(AtmospherePreset preset) void AtmosphereDefinition::applyPreset(AtmospherePreset preset)
{ {
sun_color.r = 1.0; sun_color.r = 1.0;

View file

@ -46,6 +46,11 @@ public:
virtual void copy(BaseDefinition* destination) const override; virtual void copy(BaseDefinition* destination) const override;
virtual void validate() override; virtual void validate() override;
/**
* Set the daytime from a 0.0-1.0 value.
*/
void setDaytime(double value);
void applyPreset(AtmospherePreset preset); void applyPreset(AtmospherePreset preset);
void generateStars(int count); void generateStars(int count);

View file

@ -0,0 +1,26 @@
#include "AtmosphereModeler.h"
#include "MainModelerWindow.h"
#include "Scenery.h"
#include "AtmosphereDefinition.h"
#include "OpenGLRenderer.h"
#include "OpenGLSkybox.h"
AtmosphereModeler::AtmosphereModeler(MainModelerWindow *main):
main(main)
{
QObject *item = main->findQmlObject("atmosphere_daytime");
if (item)
{
connect(item, SIGNAL(changed(double)), this, SLOT(daytimeChanged(double)));
}
}
void AtmosphereModeler::daytimeChanged(double value)
{
main->getScenery()->getAtmosphere()->setDaytime(value);
main->getRenderer()->getScenery()->setAtmosphere(main->getScenery()->getAtmosphere());
main->getRenderer()->getSkybox()->update();
}

View file

@ -0,0 +1,27 @@
#ifndef ATMOSPHEREMODELER_H
#define ATMOSPHEREMODELER_H
#include "modeler_global.h"
#include <QObject>
namespace paysages {
namespace modeler {
class AtmosphereModeler : public QObject
{
Q_OBJECT
public:
AtmosphereModeler(MainModelerWindow *main);
public slots:
void daytimeChanged(double value);
private:
MainModelerWindow *main;
};
}
}
#endif // ATMOSPHEREMODELER_H

View file

@ -3,6 +3,8 @@
#include "OpenGLView.h" #include "OpenGLView.h"
#include "Scenery.h" #include "Scenery.h"
#include "OpenGLRenderer.h" #include "OpenGLRenderer.h"
#include "AtmosphereModeler.h"
#include "WaterModeler.h"
MainModelerWindow::MainModelerWindow() MainModelerWindow::MainModelerWindow()
{ {
@ -15,10 +17,21 @@ MainModelerWindow::MainModelerWindow()
setTitle(QObject::tr("Paysages 3D")); setTitle(QObject::tr("Paysages 3D"));
setResizeMode(QQuickView::SizeRootObjectToView); setResizeMode(QQuickView::SizeRootObjectToView);
setSource(QUrl("qrc:///main.qml")); setSource(QUrl("qrc:///main.qml"));
atmosphere = new AtmosphereModeler(this);
water = new WaterModeler(this);
} }
MainModelerWindow::~MainModelerWindow() MainModelerWindow::~MainModelerWindow()
{ {
delete atmosphere;
delete water;
delete renderer; delete renderer;
delete scenery; delete scenery;
} }
QObject *MainModelerWindow::findQmlObject(const QString &objectName)
{
return rootObject()->findChild<QObject *>(objectName);
}

View file

@ -15,11 +15,17 @@ public:
MainModelerWindow(); MainModelerWindow();
virtual ~MainModelerWindow(); virtual ~MainModelerWindow();
QObject *findQmlObject(const QString& objectName);
inline Scenery *getScenery() const {return scenery;}
inline OpenGLRenderer *getRenderer() const {return renderer;} inline OpenGLRenderer *getRenderer() const {return renderer;}
private: private:
OpenGLRenderer *renderer; OpenGLRenderer *renderer;
Scenery *scenery; Scenery *scenery;
AtmosphereModeler *atmosphere;
WaterModeler *water;
}; };
} }

View file

@ -0,0 +1,19 @@
#include "WaterModeler.h"
#include "MainModelerWindow.h"
WaterModeler::WaterModeler(MainModelerWindow *main):
main(main)
{
QObject *item = main->findQmlObject("water_level");
if (item)
{
connect(item, SIGNAL(changed(double)), this, SLOT(waterLevelChanged(double)));
}
}
void WaterModeler::waterLevelChanged(double value)
{
// TODO
//qDebug() << "water level : " << value;
}

View file

@ -0,0 +1,27 @@
#ifndef WATERMODELER_H
#define WATERMODELER_H
#include "modeler_global.h"
#include <QObject>
namespace paysages {
namespace modeler {
class WaterModeler: public QObject
{
Q_OBJECT
public:
WaterModeler(MainModelerWindow *main);
public slots:
void waterLevelChanged(double value);
private:
MainModelerWindow *main;
};
}
}
#endif // WATERMODELER_H

View file

@ -9,6 +9,9 @@ namespace paysages {
namespace modeler { namespace modeler {
class MainModelerWindow; class MainModelerWindow;
class OpenGLView; class OpenGLView;
class AtmosphereModeler;
class WaterModeler;
} }
} }

View file

@ -0,0 +1,29 @@
import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
Item {
default property alias children : inner_layout.children
property int value
width: 100
height: 32
ExclusiveGroup {
id: choice_group
onCurrentChanged: value = current.value
}
Row {
id: inner_layout
spacing: 5
anchors.fill: parent
}
onChildrenChanged: {
for (var i = 0; i < children.length; i++)
{
children[i].exclusiveGroup = choice_group;
}
}
}

View file

@ -0,0 +1,50 @@
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: choice_item
property string icon
property bool checked: false
property ExclusiveGroup exclusiveGroup: null
property int value
color: "#333333"
signal toggled(bool value)
width: 20
height: 20
Image {
anchors.fill: parent
source: parent.icon
antialiasing: true
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: checked = true
}
onExclusiveGroupChanged: {
if (exclusiveGroup) {
exclusiveGroup.bindCheckable(choice_item);
}
}
onCheckedChanged: choice_item.toggled(checked)
states: [
State {
name: "Checked"
when: checked
PropertyChanges {
target: choice_item
color: "#999999"
}
}
]
}

View file

@ -4,14 +4,21 @@ Rectangle {
property ToolbarButton tool property ToolbarButton tool
id: panel id: panel
opacity: 0
width: 200 width: 200
height: parent.height - 100 height: parent.height - 100
color: "red" color: "#a0909090"
enabled: visible enabled: visible
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Behavior on opacity {
PropertyAnimation {
duration: 200
}
}
states: [ states: [
State { State {
name: "Active" name: "Active"
@ -20,6 +27,7 @@ Rectangle {
PropertyChanges { PropertyChanges {
target: panel target: panel
visible: true visible: true
opacity: 1
} }
} }

View file

@ -0,0 +1,7 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
Slider {
signal changed(real value)
onValueChanged: changed(value)
}

View file

@ -0,0 +1,46 @@
import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
BasePanel {
width: 70
objectName: "atmosphere_daytime"
default property real value: day_night.value == 2 ? 1.0 : slider.value * 0.54 + 0.23;
signal changed(real value)
onValueChanged: changed(value)
ColumnLayout
{
anchors.fill: parent
anchors.margins: 10
spacing: 20
BaseChoice {
id: day_night
width: parent.width
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
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
visible: day_night.value == 1
}
}
}

View file

@ -1,10 +1,10 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2
BasePanel { BasePanel {
width: 20 width: 20
Slider { BaseSlider {
objectName: "water_level"
orientation: Qt.Vertical orientation: Qt.Vertical
anchors.fill: parent anchors.fill: parent
} }

View file

@ -19,4 +19,14 @@ Rectangle {
duration: 200 duration: 200
} }
} }
onEnabledChanged: {
if (!enabled)
{
for (var i = 0; i < children.length; i++)
{
children[i].selected = false;
}
}
}
} }

View file

@ -17,5 +17,13 @@
<file>images/icon_water_level.png</file> <file>images/icon_water_level.png</file>
<file>BasePanel.qml</file> <file>BasePanel.qml</file>
<file>PanelWaterLevel.qml</file> <file>PanelWaterLevel.qml</file>
<file>images/icon_atmosphere.png</file>
<file>images/icon_atmosphere_daytime.png</file>
<file>BaseSlider.qml</file>
<file>PanelAtmosphereDaytime.qml</file>
<file>images/icon_atmosphere_day.png</file>
<file>images/icon_atmosphere_night.png</file>
<file>BaseChoice.qml</file>
<file>BaseChoiceItem.qml</file>
</qresource> </qresource>
</RCC> </RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

View file

@ -41,7 +41,8 @@ OpenGLView {
} }
ToolbarButton { ToolbarButton {
id: tool_atmosphere id: tool_atmosphere
picture: "images/tab_atmosphere.png" picture: "images/icon_atmosphere.png"
hovertext: "Atmosphere/weather tools"
} }
ToolbarButton { ToolbarButton {
id: tool_clouds id: tool_clouds
@ -78,11 +79,26 @@ OpenGLView {
} }
} }
Toolbar {
id: atmosphere_toolbar
opacity: 0
anchors.left: primary_toolbar.right
ToolbarButton {
id: tool_atmosphere_daytime
picture: "images/icon_atmosphere_daytime.png"
hovertext: qsTr("Change the time of day")
}
}
PanelWaterLevel { PanelWaterLevel {
id: panel_water_level id: panel_water_level
visible: false
tool: tool_water_level tool: tool_water_level
} }
PanelAtmosphereDaytime {
id: panel_atmosphere_daytime
tool: tool_atmosphere_daytime
}
states: [ states: [
State { State {
@ -102,6 +118,15 @@ OpenGLView {
target: water_toolbar target: water_toolbar
opacity: 1 opacity: 1
} }
},
State {
name: "Atmosphere Mode"
when: tool_atmosphere.selected
PropertyChanges {
target: atmosphere_toolbar
opacity: 1
}
} }
] ]

View file

@ -6,7 +6,9 @@ include(../../../common.pri)
SOURCES += main.cpp \ SOURCES += main.cpp \
OpenGLView.cpp \ OpenGLView.cpp \
MainModelerWindow.cpp MainModelerWindow.cpp \
WaterModeler.cpp \
AtmosphereModeler.cpp
RESOURCES += \ RESOURCES += \
qml/app.qrc qml/app.qrc
@ -22,7 +24,9 @@ include(deployment.pri)
HEADERS += \ HEADERS += \
OpenGLView.h \ OpenGLView.h \
modeler_global.h \ modeler_global.h \
MainModelerWindow.h MainModelerWindow.h \
WaterModeler.h \
AtmosphereModeler.h
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../system/release/ -lpaysages_system win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../system/release/ -lpaysages_system
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../system/debug/ -lpaysages_system else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../system/debug/ -lpaysages_system
@ -61,4 +65,8 @@ OTHER_FILES += \
qml/Toolbar.qml \ qml/Toolbar.qml \
qml/Tooltip.qml \ qml/Tooltip.qml \
qml/BasePanel.qml \ qml/BasePanel.qml \
qml/PanelWaterLevel.qml qml/PanelWaterLevel.qml \
qml/PanelAtmosphereDaytime.qml \
qml/BaseSlider.qml \
qml/BaseChoice.qml \
qml/BaseChoiceItem.qml

View file

@ -17,6 +17,10 @@ public:
OpenGLRenderer(Scenery* scenery=0); OpenGLRenderer(Scenery* scenery=0);
virtual ~OpenGLRenderer(); virtual ~OpenGLRenderer();
inline OpenGLSkybox *getSkybox() const {return skybox;}
inline OpenGLWater *getWater() const {return water;}
inline OpenGLTerrain *getTerrain() const {return terrain;}
void initialize(); void initialize();
void prepareOpenGLState(); void prepareOpenGLState();
void resize(int width, int height); void resize(int width, int height);

View file

@ -0,0 +1,36 @@
#include "BaseTestCase.h"
#include "AtmosphereDefinition.h"
TEST(AtmosphereDefinition, setDaytime)
{
AtmosphereDefinition atmo(NULL);
atmo.setDaytime(0.0);
EXPECT_EQ(atmo.hour, 0);
EXPECT_EQ(atmo.minute, 0);
atmo.setDaytime(0.1);
EXPECT_EQ(atmo.hour, 2);
EXPECT_EQ(atmo.minute, 24);
atmo.setDaytime(0.25);
EXPECT_EQ(atmo.hour, 6);
EXPECT_EQ(atmo.minute, 0);
atmo.setDaytime(0.5);
EXPECT_EQ(atmo.hour, 12);
EXPECT_EQ(atmo.minute, 0);
atmo.setDaytime(1.0);
EXPECT_EQ(atmo.hour, 0);
EXPECT_EQ(atmo.minute, 0);
atmo.setDaytime(-0.5);
EXPECT_EQ(atmo.hour, 12);
EXPECT_EQ(atmo.minute, 0);
atmo.setDaytime(1.5);
EXPECT_EQ(atmo.hour, 12);
EXPECT_EQ(atmo.minute, 0);
}

View file

@ -20,7 +20,8 @@ SOURCES += main.cpp \
FractalNoise_Test.cpp \ FractalNoise_Test.cpp \
Canvas_Test.cpp \ Canvas_Test.cpp \
CanvasPortion_Test.cpp \ CanvasPortion_Test.cpp \
CanvasPreview_Test.cpp CanvasPreview_Test.cpp \
AtmosphereDefinition_Test.cpp
HEADERS += \ HEADERS += \
BaseTestCase.h BaseTestCase.h