Merge branch 'quick_ui'

This commit is contained in:
Michaël Lemaire 2015-07-22 18:05:10 +02:00
commit 404b54a865
90 changed files with 2006 additions and 83 deletions

1
.gitignore vendored
View file

@ -22,3 +22,4 @@ ui_*.h
/paysages3d-linux/
/paysages3d-linux.tar.bz2
/config.vim
/callgrind.out.*

View file

@ -45,6 +45,9 @@ endif
run_cli:build
LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/commandline/paysages-cli $(ARGS)
run_modeler:build
LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/modeler/quickapp/paysages-modeler $(ARGS)
run:build
LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/desktop/paysages-gui $(ARGS)

BIN
graphics/icons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

196
graphics/icons.svg Normal file
View file

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="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:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="icons.svg"
inkscape:export-filename="/home/michael/workspace/paysages3d/graphics/icons.png"
inkscape:export-xdpi="154.89854"
inkscape:export-ydpi="154.89854">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="468.77289"
inkscape:cy="831.55692"
inkscape:document-units="px"
inkscape:current-layer="g3986"
showgrid="true"
inkscape:window-width="1920"
inkscape:window-height="1030"
inkscape:window-x="1440"
inkscape:window-y="25"
inkscape:window-maximized="1"
showguides="true"
inkscape:snap-object-midpoints="false">
<inkscape:grid
type="xygrid"
id="grid3004" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#000000;stroke:#000000;stroke-width:3.7;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 55,32.362183 c -10,35 -25,40 -25,50 0,10 5.355339,25.254827 23.790623,25.254827 C 72.225907,107.61701 80,92.362183 80,82.362183 c 0,-10 -15,-15 -25,-50 z"
id="path3006"
inkscape:connector-curvature="0"
sodipodi:nodetypes="czzzc" />
<path
style="fill:#ffffff;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 46.711902,68.575386 c -4.70494,1.249464 -15,15 -10,15 5,0 10,5 10,5 -1.6011,-6.345755 4.41534,-10.613999 10,-15 0,0 -5.29506,-6.249464 -10,-5 z"
id="path3776"
inkscape:connector-curvature="0"
sodipodi:nodetypes="zzccz" />
<path
style="fill:none;stroke:#000000;stroke-width:4.319;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 140.61815,83.142861 c 0,0 10.6138,-9.86109 20.06933,-9.708785 17.76848,0.286206 17.35284,19.13136 35.12131,19.417571 18.91107,0.304603 21.21711,-19.417571 40.13865,-19.417571 18.92154,0 21.2171,19.417571 40.13864,19.417571 9.46077,0 20.06933,-9.708786 20.06933,-9.708786"
id="path3780"
inkscape:connector-curvature="0"
sodipodi:nodetypes="caaaac" />
<path
style="fill:none;stroke:#000000;stroke-width:4.319;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 153.97268,88.56225 c 0,0 10.6138,-9.861089 20.06933,-9.708784 17.76847,0.286206 17.35284,19.13136 35.12131,19.417571 18.91106,0.304603 21.21711,-19.417571 40.13865,-19.417571 18.92153,0 21.2171,19.417571 40.13864,19.417571 9.46077,0 20.06933,-9.708787 20.06933,-9.708787"
id="path3780-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="caaaac" />
<path
style="fill:none;stroke:#000000;stroke-width:4.319;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 167.88393,94.110016 c 0,0 10.6138,-9.86109 20.06933,-9.708785 17.76847,0.286206 17.35284,19.131359 35.12131,19.417569 18.91106,0.30461 21.21711,-19.417569 40.13865,-19.417569 18.92153,0 21.2171,19.417569 40.13864,19.417569 9.46077,0 20.06933,-9.708784 20.06933,-9.708784"
id="path3780-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="caaaac" />
<path
style="fill:none;stroke:#000000;stroke-width:3.58400011;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 185.73773,125.20138 0,-77.092101 -25.69737,0 38.54605,-32.121711 38.54605,32.121711 -25.69736,0 0,77.092101 25.69736,0 -38.54605,32.12171 -38.54605,-32.12171 z"
id="path3807"
inkscape:connector-curvature="0"
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>
</svg>

After

Width:  |  Height:  |  Size: 9.9 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -105,6 +105,22 @@ void AtmosphereDefinition::validate()
_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)
{
sun_color.r = 1.0;

View file

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

View file

@ -182,7 +182,7 @@ void Scenery::getWater(WaterDefinition* water)
void Scenery::checkCameraAboveGround()
{
Vector3 camera_location = camera->getLocation();
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 2.0;
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, true, true) + 2.0;
double water_height = 1.5;
if (camera_location.y < water_height || camera_location.y < terrain_height)
{

View file

@ -82,7 +82,7 @@ void TerrainDefinition::load(PackStream* stream)
validate();
}
double TerrainDefinition::getGridHeight(int x, int z, int with_painting)
double TerrainDefinition::getGridHeight(int x, int z, bool with_painting)
{
double h;
@ -94,7 +94,7 @@ double TerrainDefinition::getGridHeight(int x, int z, int with_painting)
return h;
}
double TerrainDefinition::getInterpolatedHeight(double x, double z, int scaled, int with_painting)
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled, bool with_painting)
{
double h;
x /= scaling;

View file

@ -27,8 +27,8 @@ public:
virtual void copy(BaseDefinition* destination) const override;
virtual void validate() override;
double getGridHeight(int x, int z, int with_painting);
double getInterpolatedHeight(double x, double z, int scaled, int with_painting);
double getGridHeight(int x, int z, bool with_painting);
double getInterpolatedHeight(double x, double z, bool scaled, bool with_painting);
unsigned long getMemoryStats();
HeightInfo getHeightInfo();

View file

@ -135,7 +135,7 @@ void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double
case PAINTING_BRUSH_FLATTEN:
if (reverse)
{
_height = terrain->getInterpolatedHeight(x * terrain->scaling, z * terrain->scaling, 0, 1);
_height = terrain->getInterpolatedHeight(x * terrain->scaling, z * terrain->scaling, false, true);
}
else
{

View file

@ -218,7 +218,7 @@ void WidgetHeightMap::timerEvent(QTimerEvent*)
_last_time = new_time;
// Update top camera
Vector3 target = {_target_x, _terrain->getInterpolatedHeight(_target_x, _target_z, 1, 1), _target_z};
Vector3 target = {_target_x, _terrain->getInterpolatedHeight(_target_x, _target_z, true, true), _target_z};
_top_camera->setLocationCoords(target.x, target.y + 1.0, target.z + 0.1);
_top_camera->setTarget(target);
_top_camera->setZoomToTarget(_zoom);

View file

@ -0,0 +1,35 @@
TEMPLATE = lib
TARGET = extension
QT += qml quick
CONFIG += qt plugin
TARGET = $$qtLibraryTarget($$TARGET)
uri = Paysages
# Input
SOURCES += \
extension_plugin.cpp \
paysages.cpp
HEADERS += \
extension_plugin.h \
paysages.h
OTHER_FILES = qmldir
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
copy_qmldir.target = $$OUT_PWD/qmldir
copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
copy_qmldir.commands = $(COPY_FILE) \"$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)\"
QMAKE_EXTRA_TARGETS += copy_qmldir
PRE_TARGETDEPS += $$copy_qmldir.target
}
qmldir.files = qmldir
unix {
installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir
}

View file

@ -0,0 +1,12 @@
#include "extension_plugin.h"
#include "paysages.h"
#include <qqml.h>
void ExtensionPlugin::registerTypes(const char *uri)
{
// @uri Paysages
qmlRegisterType<Paysages>(uri, 1, 0, "Paysages");
}

View file

@ -0,0 +1,16 @@
#ifndef EXTENSION_PLUGIN_H
#define EXTENSION_PLUGIN_H
#include <QQmlExtensionPlugin>
class ExtensionPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri);
};
#endif // EXTENSION_PLUGIN_H

View file

@ -0,0 +1,16 @@
#include "paysages.h"
Paysages::Paysages(QQuickItem *parent):
QQuickItem(parent)
{
// By default, QQuickItem does not draw anything. If you subclass
// QQuickItem to create a visual item, you will need to uncomment the
// following line and re-implement updatePaintNode()
// setFlag(ItemHasContents, true);
}
Paysages::~Paysages()
{
}

View file

@ -0,0 +1,17 @@
#ifndef PAYSAGES_H
#define PAYSAGES_H
#include <QQuickItem>
class Paysages : public QQuickItem
{
Q_OBJECT
Q_DISABLE_COPY(Paysages)
public:
Paysages(QQuickItem *parent = 0);
~Paysages();
};
#endif // PAYSAGES_H

View file

@ -0,0 +1,3 @@
module Paysages
plugin extension

View file

@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
quickapp \
extension

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

@ -0,0 +1,76 @@
#include "MainModelerWindow.h"
#include "OpenGLView.h"
#include "Scenery.h"
#include "OpenGLRenderer.h"
#include "AtmosphereModeler.h"
#include "WaterModeler.h"
#include "ModelerCameras.h"
#include "RenderPreviewProvider.h"
#include "RenderProcess.h"
#include "RenderConfig.h"
#include <QQmlEngine>
MainModelerWindow::MainModelerWindow()
{
scenery = new Scenery();
scenery->autoPreset();
renderer = new OpenGLRenderer(scenery);
render_preview_provider = new RenderPreviewProvider();
render_process = new RenderProcess(render_preview_provider);
qmlRegisterType<OpenGLView>("Paysages", 1, 0, "OpenGLView");
engine()->addImageProvider("renderpreviewprovider", render_preview_provider);
setMinimumSize(QSize(1000, 800));
setTitle(QObject::tr("Paysages 3D"));
setResizeMode(QQuickView::SizeRootObjectToView);
setSource(QUrl("qrc:///main.qml"));
cameras = new ModelerCameras(this);
atmosphere = new AtmosphereModeler(this);
water = new WaterModeler(this);
}
MainModelerWindow::~MainModelerWindow()
{
delete atmosphere;
delete water;
delete cameras;
delete render_preview_provider;
delete render_process;
delete renderer;
delete scenery;
}
QObject *MainModelerWindow::findQmlObject(const QString &objectName)
{
return rootObject()->findChild<QObject *>(objectName);
}
void MainModelerWindow::keyReleaseEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_F5)
{
// Start render in a thread
render_process->startRender(scenery, RenderConfig(400, 300, 1, 3));
// Resize preview
QSize preview_size = render_process->getPreviewSize();
findQmlObject("preview_image")->setProperty("width", preview_size.width());
findQmlObject("preview_image")->setProperty("height", preview_size.height());
// Show render dialog
rootObject()->setProperty("state", QString("Render Dialog"));
}
else if (event->key() == Qt::Key_Escape)
{
render_process->stopRender();
rootObject()->setProperty("state", QString("Init"));
}
}

View file

@ -0,0 +1,43 @@
#ifndef MAINMODELERWINDOW_H
#define MAINMODELERWINDOW_H
#include "modeler_global.h"
#include <QQuickView>
namespace paysages {
namespace modeler {
class MainModelerWindow: public QQuickView
{
Q_OBJECT
public:
MainModelerWindow();
virtual ~MainModelerWindow();
QObject *findQmlObject(const QString& objectName);
inline Scenery *getScenery() const {return scenery;}
inline OpenGLRenderer *getRenderer() const {return renderer;}
inline ModelerCameras *getCamera() const {return cameras;}
protected:
virtual void keyReleaseEvent(QKeyEvent *event) override;
private:
OpenGLRenderer *renderer;
Scenery *scenery;
AtmosphereModeler *atmosphere;
WaterModeler *water;
ModelerCameras *cameras;
RenderPreviewProvider *render_preview_provider;
RenderProcess *render_process;
};
}
}
#endif // MAINMODELERWINDOW_H

View file

@ -0,0 +1,64 @@
#include "ModelerCameras.h"
#include "MainModelerWindow.h"
#include "OpenGLRenderer.h"
#include "Scenery.h"
#include "CameraDefinition.h"
ModelerCameras::ModelerCameras(MainModelerWindow *parent):
QObject(parent), parent(parent)
{
render = new CameraDefinition();
topdown = new CameraDefinition();
current = new CameraDefinition();
active = render;
topdown->strafeForward(-10.0);
topdown->strafeUp(25.0);
topdown->rotatePitch(-0.8);
// Watch GUI choice
QObject *widget = parent->findQmlObject("camera_choice");
connect(widget, SIGNAL(stateChanged(QString)), this, SLOT(changeActiveCamera(QString)));
// Start update timer
startTimer(50);
}
ModelerCameras::~ModelerCameras()
{
delete current;
delete render;
delete topdown;
}
void ModelerCameras::processZoom(double value)
{
active->strafeForward(value);
}
void ModelerCameras::processScroll(double xvalue, double yvalue)
{
active->strafeRight(xvalue);
active->strafeUp(yvalue);
}
void ModelerCameras::timerEvent(QTimerEvent *)
{
OpenGLRenderer *renderer = parent->getRenderer();
current->transitionToAnother(active, 0.3);
renderer->setCamera(current);
}
void ModelerCameras::changeActiveCamera(const QString &name)
{
if (name == "Render camera")
{
active = render;
}
else if (name == "Top-down camera")
{
active = topdown;
}
}

View file

@ -0,0 +1,49 @@
#ifndef MODELERCAMERAS_H
#define MODELERCAMERAS_H
#include "modeler_global.h"
#include <QObject>
namespace paysages {
namespace modeler {
/**
* Storage for modeler cameras.
*/
class ModelerCameras: public QObject
{
Q_OBJECT
public:
ModelerCameras(MainModelerWindow *parent);
~ModelerCameras();
/**
* Process a zoom request.
*/
void processZoom(double value);
/**
* Process a scroll request.
*/
void processScroll(double xvalue, double yvalue);
protected:
void timerEvent(QTimerEvent *event);
public slots:
void changeActiveCamera(const QString &name);
private:
MainModelerWindow *parent;
CameraDefinition *active;
CameraDefinition *current;
CameraDefinition *render;
CameraDefinition *topdown;
};
}
}
#endif // MODELERCAMERAS_H

View file

@ -0,0 +1,92 @@
#include "OpenGLView.h"
#include <QQuickWindow>
#include <QHoverEvent>
#include "MainModelerWindow.h"
#include "OpenGLRenderer.h"
#include "ModelerCameras.h"
OpenGLView::OpenGLView(QQuickItem *parent) :
QQuickItem(parent)
{
initialized = false;
window = NULL;
renderer = NULL;
setAcceptedMouseButtons(Qt::AllButtons);
mouse_button = Qt::NoButton;
connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)));
startTimer(50);
}
void OpenGLView::handleWindowChanged(QQuickWindow *win)
{
if (win)
{
window = qobject_cast<MainModelerWindow *>(win);
if (window)
{
renderer = window->getRenderer();
connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
win->setClearBeforeRendering(false);
initialized = false;
}
}
}
void OpenGLView::paint()
{
if (not initialized or not renderer)
{
renderer->initialize();
initialized = true;
}
renderer->resize(width(), height());
renderer->prepareOpenGLState();
renderer->paint();
if (window)
{
window->resetOpenGLState();
}
}
void OpenGLView::wheelEvent(QWheelEvent *event)
{
window->getCamera()->processZoom(0.1 * (double)event->angleDelta().y());
}
void OpenGLView::mousePressEvent(QMouseEvent *event)
{
mouse_button = event->button();
mouse_pos = event->windowPos();
}
void OpenGLView::mouseReleaseEvent(QMouseEvent *)
{
mouse_button = Qt::NoButton;
}
void OpenGLView::mouseMoveEvent(QMouseEvent *event)
{
QPointF diff = event->windowPos() - mouse_pos;
if (mouse_button == Qt::MidButton)
{
window->getCamera()->processScroll(-0.1 * diff.x(), 0.1 * diff.y());
}
mouse_pos = event->windowPos();
}
void OpenGLView::timerEvent(QTimerEvent *)
{
if (window)
{
window->update();
}
}

View file

@ -0,0 +1,40 @@
#ifndef OPENGLVIEW_H
#define OPENGLVIEW_H
#include "modeler_global.h"
#include <QQuickItem>
namespace paysages {
namespace modeler {
class OpenGLView : public QQuickItem
{
Q_OBJECT
public:
explicit OpenGLView(QQuickItem *parent = 0);
public slots:
void handleWindowChanged(QQuickWindow *win);
void paint();
protected:
virtual void wheelEvent(QWheelEvent *event) override;
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void timerEvent(QTimerEvent *event) override;
private:
bool initialized;
MainModelerWindow *window;
OpenGLRenderer *renderer;
Qt::MouseButton mouse_button;
QPointF mouse_pos;
};
}
}
#endif // OPENGLVIEW_H

View file

@ -0,0 +1,85 @@
#include "RenderPreviewProvider.h"
#include "Canvas.h"
#include "CanvasPreview.h"
#include "Color.h"
static inline QColor colorToQColor(Color color)
{
color.normalize();
return QColor(color.r * 255.0, color.g * 255.0, color.b * 255.0, color.a * 255.0);
}
RenderPreviewProvider::RenderPreviewProvider() :
QQuickImageProvider(QQuickImageProvider::Image)
{
canvas = NULL;
pixbuf = new QImage(1, 1, QImage::Format_ARGB32);
}
RenderPreviewProvider::~RenderPreviewProvider()
{
delete pixbuf;
}
QImage RenderPreviewProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
if (canvas)
{
canvas->getPreview()->updateLive(this);
}
if (size)
{
*size = pixbuf->size();
}
return *pixbuf;
}
void RenderPreviewProvider::setCanvas(const Canvas *canvas)
{
if (not this->canvas)
{
this->canvas = canvas;
canvas->getPreview()->initLive(this);
}
}
void RenderPreviewProvider::releaseCanvas()
{
if (canvas)
{
canvas->getPreview()->updateLive(this);
canvas = NULL;
}
}
void RenderPreviewProvider::setToneMapping(const ColorProfile &profile)
{
if (canvas)
{
canvas->getPreview()->setToneMapping(profile);
canvas->getPreview()->updateLive(this);
}
}
void RenderPreviewProvider::canvasResized(int width, int height)
{
if (QSize(width, height) != pixbuf->size())
{
delete pixbuf;
pixbuf = new QImage(width, height, QImage::Format_ARGB32);
pixbuf->fill(Qt::black);
}
}
void RenderPreviewProvider::canvasCleared(const Color &col)
{
pixbuf->fill(colorToQColor(col));
}
void RenderPreviewProvider::canvasPainted(int x, int y, const Color &col)
{
pixbuf->setPixel(x, pixbuf->height() - 1 - y, colorToQColor(col).rgb());
}

View file

@ -0,0 +1,53 @@
#ifndef RENDERPREVIEWPROVIDER_H
#define RENDERPREVIEWPROVIDER_H
#include "modeler_global.h"
#include <QQuickImageProvider>
#include "CanvasLiveClient.h"
namespace paysages {
namespace modeler {
/**
* Provider for a Qml Image content, filled from a canvas rendering.
*/
class RenderPreviewProvider : public QQuickImageProvider, public CanvasLiveClient
{
public:
RenderPreviewProvider();
virtual ~RenderPreviewProvider();
/**
* Set the canvas to watch and display, null to stop watching.
*
* This function must be called from the graphics thread.
*/
void setCanvas(const Canvas *canvas);
/**
* Release the bound canvas.
*/
void releaseCanvas();
/**
* Set the tone mapping to apply to pixel colors.
*/
void setToneMapping(const ColorProfile &profile);
protected:
virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
virtual void canvasResized(int width, int height) override;
virtual void canvasCleared(const Color &col) override;
virtual void canvasPainted(int x, int y, const Color &col) override;
private:
QImage* pixbuf;
const Canvas *canvas;
};
}
}
#endif // RENDERPREVIEWPROVIDER_H

View file

@ -0,0 +1,111 @@
#include "RenderProcess.h"
#include <QSize>
#include "SoftwareCanvasRenderer.h"
#include "RenderPreviewProvider.h"
#include "RenderConfig.h"
#include "Thread.h"
#include "Canvas.h"
#include "CanvasPreview.h"
class RenderThread: public Thread
{
public:
RenderThread(SoftwareCanvasRenderer *renderer): renderer(renderer)
{
}
virtual void run() override
{
renderer->render();
}
private:
SoftwareCanvasRenderer *renderer;
};
RenderProcess::RenderProcess(RenderPreviewProvider *destination):
destination(destination)
{
rendering = false;
renderer = NULL;
render_thread = NULL;
startTimer(100);
}
RenderProcess::~RenderProcess()
{
if (rendering)
{
renderer->interrupt();
}
rendering = false;
if (render_thread)
{
render_thread->join();
delete render_thread;
}
if (renderer)
{
delete renderer;
}
}
void RenderProcess::startRender(Scenery *scenery, const RenderConfig &config)
{
if (rendering)
{
return;
}
rendering = true;
if (renderer)
{
delete renderer;
}
renderer = new SoftwareCanvasRenderer();
renderer->setScenery(scenery);
renderer->setConfig(config);
destination->setCanvas(renderer->getCanvas());
render_thread = new RenderThread(renderer);
render_thread->start();
}
void RenderProcess::stopRender()
{
if (rendering)
{
renderer->interrupt();
}
}
const QSize RenderProcess::getPreviewSize()
{
if (renderer)
{
return QSize(renderer->getCanvas()->getPreview()->getWidth(), renderer->getCanvas()->getPreview()->getHeight());
}
else
{
return QSize(10, 10);
}
}
void RenderProcess::timerEvent(QTimerEvent *)
{
if (rendering and renderer->isFinished())
{
destination->releaseCanvas();
rendering = false;
render_thread->join();
delete render_thread;
render_thread = NULL;
}
}

View file

@ -0,0 +1,47 @@
#ifndef RENDERPROCESS_H
#define RENDERPROCESS_H
#include "modeler_global.h"
#include <QObject>
namespace paysages {
namespace modeler {
class RenderProcess: public QObject
{
Q_OBJECT
public:
RenderProcess(RenderPreviewProvider *destination);
virtual ~RenderProcess();
/**
* Start the rendering process in a separate thread.
*/
void startRender(Scenery *scenery, const RenderConfig &config);
/**
* Stop any currently running render.
*/
void stopRender();
/**
* Get the size of the preview image.
*/
const QSize getPreviewSize();
protected:
virtual void timerEvent(QTimerEvent *event) override;
private:
RenderPreviewProvider *destination;
bool rendering;
SoftwareCanvasRenderer *renderer;
Thread *render_thread;
};
}
}
#endif // RENDERPROCESS_H

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

@ -0,0 +1,27 @@
android-no-sdk {
target.path = /data/user/qt
export(target.path)
INSTALLS += target
} else:android {
x86 {
target.path = /libs/x86
} else: armeabi-v7a {
target.path = /libs/armeabi-v7a
} else {
target.path = /libs/armeabi
}
export(target.path)
INSTALLS += target
} else:unix {
isEmpty(target.path) {
qnx {
target.path = /tmp/$${TARGET}/bin
} else {
target.path = /opt/$${TARGET}/bin
}
export(target.path)
}
INSTALLS += target
}
export(INSTALLS)

View file

@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/toolbar/primary">
<file>images/tab_atmosphere.png</file>
<file>images/tab_terrain.png</file>
<file>images/tab_textures.png</file>
<file>images/tab_water.png</file>
<file>images/tab_clouds.png</file>
<file>images/tab_render.png</file>
</qresource>
</RCC>

View file

@ -0,0 +1,13 @@
#include <QGuiApplication>
#include "MainModelerWindow.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
MainModelerWindow view;
view.show();
return app.exec();
}

View file

@ -0,0 +1,25 @@
#ifndef MODELER_GLOBAL_H
#define MODELER_GLOBAL_H
#include "definition_global.h"
#include "software_global.h"
#include "opengl_global.h"
namespace paysages {
namespace modeler {
class MainModelerWindow;
class OpenGLView;
class AtmosphereModeler;
class WaterModeler;
class RenderPreviewProvider;
class RenderProcess;
class ModelerCameras;
}
}
using namespace paysages::modeler;
#endif // MODELER_GLOBAL_H

View file

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/">
<file>qml/main.qml</file>
<file>qml/ToolbarButton.qml</file>
<file>qml/OpenGLView.qml</file>
</qresource>
</RCC>

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

@ -0,0 +1,35 @@
import QtQuick 2.0
Rectangle {
property ToolbarButton tool
id: panel
opacity: 0
width: 200
height: parent.height - 100
color: "#a0909090"
enabled: visible
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Behavior on opacity {
PropertyAnimation {
duration: 200
}
}
states: [
State {
name: "Active"
when: tool.selected
PropertyChanges {
target: panel
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,39 @@
import QtQuick 2.0
Rectangle {
id: camera_choice
width: 200
height: 50
color: "#90888888"
objectName: "camera_choice"
Row {
id: inner_space
anchors.centerIn: parent
spacing: 15
ToolbarButton {
id: camera_choice_render
picture: "images/tab_display.png"
hovertext: qsTr("Switch to the final camera")
selected: true
}
ToolbarButton {
id: camera_choice_topdown
picture: "images/display_topdown.png"
hovertext: qsTr("Switch to the top-down camera")
}
}
states: [
State {
name: "Render camera"
when: camera_choice_render.selected
},
State {
name: "Top-down camera"
when: camera_choice_topdown.selected
}
]
}

View file

@ -0,0 +1,6 @@
import QtQuick 2.0
Rectangle {
width: 100
height: 62
}

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

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

View file

@ -0,0 +1,27 @@
import QtQuick 2.2
Rectangle {
width: 400
height: 300
Image {
id: preview_image
objectName: "preview_image"
anchors.centerIn: parent
width: 100
height: 100
source: ""
cache: false
}
Timer {
interval: 500
running: true
repeat: true
onTriggered: {
preview_image.source = "";
preview_image.source = "image://renderpreviewprovider/live";
}
}
}

View file

@ -0,0 +1,32 @@
import QtQuick 2.0
Rectangle {
default property alias children : inner_space.children
width: 70
height: parent.height
color: "#50888888"
enabled: opacity > 0
Column {
id: inner_space
spacing: (parent.height - children.length * tool_terrain.height) / (children.length + 1)
anchors.centerIn: parent
}
Behavior on opacity {
PropertyAnimation {
duration: 200
}
}
onEnabledChanged: {
if (!enabled)
{
for (var i = 0; i < children.length; i++)
{
children[i].selected = false;
}
}
}
}

View file

@ -0,0 +1,87 @@
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
property string picture
property bool selected: false
property bool hovered: false
property string helptext
property string hovertext
width: image.width + 10
height: image.height + 10
Rectangle {
id: glow
anchors.fill: parent
color: "#cccccc"
radius: 8
opacity: parent.selected ? 1.0 : (parent.hovered ? 0.5 : 0.0)
Behavior on opacity {
PropertyAnimation {
duration: 200
}
}
RectangularGlow {
anchors.fill: glow
glowRadius: 8
spread: 0.2
color: "white"
cornerRadius: glow.radius + glowRadius
}
}
Image {
id: image
source: parent.picture
anchors.centerIn: parent
width: 32
height: 32
antialiasing: true
}
DropShadow {
anchors.fill: image
horizontalOffset: 2
verticalOffset: 2
radius: 4.0
samples: 16
color: "#80000000"
source: image
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: {
parent.hovered = true;
tooltip_widget.hovertext = hovertext;
}
onExited: {
parent.hovered = false;
tooltip_widget.hovertext = "";
}
onClicked: {
parent.selected = !parent.selected;
if (parent.selected)
{
var toolbar = parent.parent;
for (var i = 0; i < toolbar.children.length; ++i)
{
var child = toolbar.children[i]
if (child !== parent)
{
child.selected = false;
}
}
tooltip_widget.helptext = helptext;
}
else
{
tooltip_widget.helptext = "";
}
}
}
}

View file

@ -0,0 +1,16 @@
import QtQuick 2.0
Rectangle {
property string helptext
property string hovertext
width: content.width
height: content.height
color: "#99000000"
Text {
id: content
color: "white"
text: parent.helptext || parent.hovertext
}
}

View file

@ -0,0 +1,31 @@
<RCC>
<qresource prefix="/">
<file>ToolbarButton.qml</file>
<file>main.qml</file>
<file>images/tab_atmosphere.png</file>
<file>images/tab_clouds.png</file>
<file>images/tab_render.png</file>
<file>images/tab_terrain.png</file>
<file>images/tab_textures.png</file>
<file>images/tab_water.png</file>
<file>images/tab_display.png</file>
<file>Toolbar.qml</file>
<file>images/display_topdown.png</file>
<file>images/help.png</file>
<file>Tooltip.qml</file>
<file>images/icon_water.png</file>
<file>images/icon_water_level.png</file>
<file>BasePanel.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>
<file>RenderDialog.qml</file>
<file>CameraChoice.qml</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,158 @@
import QtQuick 2.2
import Paysages 1.0
OpenGLView {
id: main_ui
state: "Init"
width: 800
height: 600
Tooltip {
id: tooltip_widget
anchors.top: parent.top
anchors.right: parent.right
}
Toolbar {
id: primary_toolbar
color: "#90888888"
anchors.left: parent.left
ToolbarButton {
id: tool_display
picture: "images/tab_display.png"
hovertext: qsTr("Display options")
}
ToolbarButton {
id: tool_terrain
picture: "images/tab_terrain.png"
}
ToolbarButton {
id: tool_textures
picture: "images/tab_textures.png"
}
ToolbarButton {
id: tool_water
picture: "images/icon_water.png"
hovertext: "Water tools"
}
ToolbarButton {
id: tool_atmosphere
picture: "images/icon_atmosphere.png"
hovertext: "Atmosphere/weather tools"
}
ToolbarButton {
id: tool_clouds
picture: "images/tab_clouds.png"
}
ToolbarButton {
id: tool_render
picture: "images/tab_render.png"
}
}
Toolbar {
id: display_toolbar
opacity: 0
anchors.left: primary_toolbar.right
ToolbarButton {
id: tool_display_topdown
picture: "images/display_topdown.png"
hovertext: qsTr("Top-down view")
helptext: qsTr("Drag the mouse on the map to change the viewpoint.")
}
}
Toolbar {
id: water_toolbar
opacity: 0
anchors.left: primary_toolbar.right
ToolbarButton {
id: tool_water_level
picture: "images/icon_water_level.png"
hovertext: qsTr("Change the water altitude")
}
}
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")
}
}
CameraChoice {
id: camera_choice
anchors.bottom: main_ui.bottom
anchors.horizontalCenter: main_ui.horizontalCenter
}
RenderDialog {
id: render_dialog
opacity: 0
anchors.fill: parent
}
PanelWaterLevel {
id: panel_water_level
tool: tool_water_level
}
PanelAtmosphereDaytime {
id: panel_atmosphere_daytime
tool: tool_atmosphere_daytime
}
states: [
State {
name: "Display Mode"
when: tool_display.selected
PropertyChanges {
target: display_toolbar
opacity: 1
}
},
State {
name: "Water Mode"
when: tool_water.selected
PropertyChanges {
target: water_toolbar
opacity: 1
}
},
State {
name: "Atmosphere Mode"
when: tool_atmosphere.selected
PropertyChanges {
target: atmosphere_toolbar
opacity: 1
}
},
State {
name: "Render Dialog"
when: tool_display.selected
PropertyChanges {
target: primary_toolbar
opacity: 0
}
PropertyChanges {
target: render_dialog
opacity: 1
}
}
]
}

View file

@ -0,0 +1,80 @@
TEMPLATE = app
QT += qml quick widgets
include(../../../common.pri)
SOURCES += main.cpp \
OpenGLView.cpp \
MainModelerWindow.cpp \
WaterModeler.cpp \
AtmosphereModeler.cpp \
RenderPreviewProvider.cpp \
RenderProcess.cpp \
ModelerCameras.cpp
RESOURCES += \
qml/app.qrc
TARGET = paysages-modeler
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH = ../extension
# Default rules for deployment.
include(deployment.pri)
HEADERS += \
OpenGLView.h \
modeler_global.h \
MainModelerWindow.h \
WaterModeler.h \
AtmosphereModeler.h \
RenderPreviewProvider.h \
RenderProcess.h \
ModelerCameras.h
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:unix: LIBS += -L$$OUT_PWD/../../../system/ -lpaysages_system
INCLUDEPATH += $$PWD/../../../system
DEPENDPATH += $$PWD/../../../system
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../basics/release/ -lpaysages_basics
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../basics/debug/ -lpaysages_basics
else:unix: LIBS += -L$$OUT_PWD/../../../basics/ -lpaysages_basics
INCLUDEPATH += $$PWD/../../../basics
DEPENDPATH += $$PWD/../../../basics
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../definition/release/ -lpaysages_definition
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../definition/debug/ -lpaysages_definition
else:unix: LIBS += -L$$OUT_PWD/../../../definition/ -lpaysages_definition
INCLUDEPATH += $$PWD/../../../definition
DEPENDPATH += $$PWD/../../../definition
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../render/software/release/ -lpaysages_render_software
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../render/software/debug/ -lpaysages_render_software
else:unix: LIBS += -L$$OUT_PWD/../../../render/software/ -lpaysages_render_software
INCLUDEPATH += $$PWD/../../../render/software
DEPENDPATH += $$PWD/../../../render/software
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../render/opengl/release/ -lpaysages_render_opengl
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../render/opengl/debug/ -lpaysages_render_opengl
else:unix: LIBS += -L$$OUT_PWD/../../../render/opengl/ -lpaysages_render_opengl
INCLUDEPATH += $$PWD/../../../render/opengl
DEPENDPATH += $$PWD/../../../render/opengl
OTHER_FILES += \
qml/main.qml \
qml/ToolbarButton.qml \
qml/OpenGLView.qml \
qml/Toolbar.qml \
qml/Tooltip.qml \
qml/BasePanel.qml \
qml/PanelWaterLevel.qml \
qml/PanelAtmosphereDaytime.qml \
qml/BaseSlider.qml \
qml/BaseChoice.qml \
qml/BaseChoiceItem.qml \
qml/RenderDialog.qml \
qml/CameraChoice.qml

View file

@ -9,7 +9,8 @@ SUBDIRS = \
render/preview \
render/opengl \
interface/commandline \
interface/desktop
interface/desktop \
interface/modeler
exists( tests/googletest/sources/src/gtest-all.cc ) {
SUBDIRS += \

View file

@ -85,7 +85,7 @@ bool ExplorerChunkTerrain::maintain()
double x = _startx + _tessellation_step * (float)i;
double z = _startz + _tessellation_step * (float)j;
double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1);
double height = _renderer->getTerrainRenderer()->getHeight(x, z, true);
if (height >= _water_height)
{
overwater = true;

View file

@ -16,6 +16,8 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery):
SoftwareRenderer(scenery)
{
ready = false;
vp_width = 1;
vp_height = 1;
render_quality = 3;
@ -50,25 +52,7 @@ void OpenGLRenderer::initialize()
if (ready)
{
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
functions->glDisable(GL_LIGHTING);
functions->glFrontFace(GL_CCW);
functions->glCullFace(GL_BACK);
functions->glEnable(GL_CULL_FACE);
functions->glDepthFunc(GL_LESS);
functions->glDepthMask(1);
functions->glEnable(GL_DEPTH_TEST);
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
functions->glEnable(GL_LINE_SMOOTH);
functions->glLineWidth(1.0);
functions->glDisable(GL_FOG);
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
prepareOpenGLState();
prepare();
@ -92,28 +76,63 @@ void OpenGLRenderer::initialize()
}
}
void OpenGLRenderer::resize(int width, int height)
void OpenGLRenderer::prepareOpenGLState()
{
if (ready)
{
functions->glViewport(0, 0, width, height);
functions->glDisable(GL_LIGHTING);
functions->glFrontFace(GL_CCW);
functions->glCullFace(GL_BACK);
functions->glEnable(GL_CULL_FACE);
functions->glDepthFunc(GL_LESS);
functions->glDepthMask(1);
functions->glEnable(GL_DEPTH_TEST);
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
functions->glEnable(GL_LINE_SMOOTH);
functions->glLineWidth(1.0);
functions->glDisable(GL_FOG);
functions->glEnable(GL_BLEND);
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
functions->glViewport(0, 0, vp_width, vp_height);
}
}
void OpenGLRenderer::setCamera(CameraDefinition *camera)
{
camera->copy(render_camera);
getScenery()->setCamera(camera);
getScenery()->getCamera(camera);
cameraChangeEvent(camera);
}
void OpenGLRenderer::resize(int width, int height)
{
vp_width = width;
vp_height = height;
getScenery()->getCamera()->setRenderSize(width, height);
render_camera->setRenderSize(width, height);
cameraChangeEvent(getScenery()->getCamera());
prepareOpenGLState();
}
void OpenGLRenderer::paint()
{
if (ready)
{
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
functions->glEnable(GL_BLEND);
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
skybox->render();
terrain->render();
water->render();

View file

@ -17,10 +17,21 @@ public:
OpenGLRenderer(Scenery* scenery=0);
virtual ~OpenGLRenderer();
inline OpenGLSkybox *getSkybox() const {return skybox;}
inline OpenGLWater *getWater() const {return water;}
inline OpenGLTerrain *getTerrain() const {return terrain;}
void initialize();
void prepareOpenGLState();
void resize(int width, int height);
void paint();
/**
* Change the camera location.
*
* This may change the camera passed as argument (to stay above ground for example).
*/
void setCamera(CameraDefinition *camera);
void cameraChangeEvent(CameraDefinition* camera);
inline OpenGLFunctions* getOpenGlFunctions() const {return functions;}
@ -31,6 +42,8 @@ public:
private:
bool ready;
int vp_width;
int vp_height;
OpenGLFunctions* functions;
OpenGLSharedState* shared_state;

View file

@ -25,7 +25,7 @@ void OpenGLSkybox::initialize()
{
program = createShader("skybox");
program->addVertexSource("skybox");
program->addFragmentSource("bruneton");
program->addFragmentSource("atmosphere");
program->addFragmentSource("tonemapping");
program->addFragmentSource("skybox");

View file

@ -52,7 +52,7 @@ void OpenGLTerrain::initialize()
// Prepare shader programs
program = createShader("terrain");
program->addVertexSource("terrain");
program->addFragmentSource("bruneton");
program->addFragmentSource("atmosphere");
program->addFragmentSource("tonemapping");
program->addFragmentSource("fadeout");
program->addFragmentSource("terrain");

View file

@ -24,7 +24,7 @@ void OpenGLWater::initialize()
{
program = createShader("water");
program->addVertexSource("water");
program->addFragmentSource("bruneton");
program->addFragmentSource("atmosphere");
program->addFragmentSource("tonemapping");
program->addFragmentSource("fadeout");
program->addFragmentSource("noise");

View file

@ -224,3 +224,53 @@ vec4 getSkyColor(vec3 location, vec3 direction)
result += sunTransmittance + vec4(inscattering, 0.0);
return result;
}
vec4 applyLighting(vec3 location, vec3 normal, vec4 color, float shininess)
{
float material_hardness = 0.3;
float material_reflection = 1.0;
float r0 = Rg + location.y * WORLD_SCALING;
vec3 sun_position = sunDirection * SUN_DISTANCE;
float muS = dot(vec3(0.0, 1.0, 0.0), normalize(sun_position - vec3(0.0, r0, 0.0)));
vec4 light_color = _transmittanceWithShadow(r0, muS);
vec4 result = vec4(0.0, 0.0, 0.0, 1.0);
/* diffused light */
float diffuse = dot(sunDirection, normal);
float sign = (diffuse < 0.0) ? -1.0 : 1.0;
if (material_hardness <= 0.5)
{
float hardness = material_hardness * 2.0;
diffuse = (1.0 - hardness) * (diffuse * diffuse) * sign + hardness * diffuse;
}
else if (diffuse != 0.0)
{
float hardness = (material_hardness - 0.5) * 2.0;
diffuse = (1.0 - hardness) * diffuse + hardness * sign * sqrt(abs(diffuse));
}
if (diffuse > 0.0)
{
result += diffuse * color * light_color;
}
/* specular reflection */
if (shininess > 0.0 && material_reflection > 0.0)
{
vec3 view = normalize(location - cameraLocation);
vec3 reflect = sunDirection - normal * 2.0 * dot(sunDirection, normal);
float specular = dot(reflect, view);
if (specular > 0.0)
{
specular = pow(specular, shininess) * material_reflection;
if (specular > 0.0)
{
result += specular * light_color;
}
}
}
return result;
}

View file

@ -4,7 +4,7 @@
<file>skybox.vert</file>
<file>water.frag</file>
<file>water.vert</file>
<file>bruneton.frag</file>
<file>atmosphere.frag</file>
<file>tonemapping.frag</file>
<file>terrain.frag</file>
<file>terrain.vert</file>

View file

@ -1,32 +1,11 @@
uniform vec4 waterColor;
uniform float waterReflection;
vec4 applyLighting(vec3 location, vec3 normal, vec4 color, float shininess)
{
// TEMP phong lighting implementation for testing
vec3 N = normalize(normal);
vec3 L = sunDirection;
vec3 E = normalize(cameraLocation - location);
vec3 R = normalize(-reflect(L, N));
//calculate Ambient Term:
vec4 Iamb = vec4(0.1, 0.1, 0.1, 1.0);
//calculate Diffuse Term:
vec4 Idiff = vec4(3.0, 3.0, 3.0, 1.0) * color * max(dot(N, L), 0.0);
// calculate Specular Term:
vec4 Ispec = vec4(3.0, 3.0, 3.0, 1.0) * pow(max(dot(R,E),0.0),0.3*shininess);
// write Total Color:
return Iamb + Idiff + Ispec;
}
void main(void)
{
vec3 normal = noiseNormal2d(unprojected.xz, 0.001);
gl_FragColor = applyLighting(unprojected, normal, waterColor, 100.0);
gl_FragColor = applyLighting(unprojected, normal, waterColor, 16.0);
vec3 reflected = reflect(unprojected - cameraLocation, normal);
reflected.y = max(reflected.y, 0.0);

View file

@ -46,7 +46,7 @@ void SceneryTopDownPreviewRenderer::updateEvent()
Color SceneryTopDownPreviewRenderer::getColor2D(double x, double y, double scaling)
{
Vector3 location;
double height = getTerrainRenderer()->getHeight(x, y, 1);
double height = getTerrainRenderer()->getHeight(x, y, true);
if (height < getWaterRenderer()->getHeightInfo().max_height)
{

View file

@ -57,7 +57,7 @@ Color TerrainShapePreviewRenderer::getColor2D(double x, double y, double scaling
{
double height;
height = getTerrainRenderer()->getHeight(x, y, 1);
height = getTerrainRenderer()->getHeight(x, y, true);
if (height > 0.0)
{
return getTerrainRenderer()->getFinalColor(Vector3(x, height, y), 0.000001);

View file

@ -53,7 +53,7 @@ Color TextureLayerCoveragePreviewRenderer::getColor2D(double x, double y, double
TexturesRenderer* textures_renderer = getTexturesRenderer();
TerrainRenderer* terrain_renderer = getTerrainRenderer();
double presence = textures_renderer->getBasePresence(layer, terrain_renderer->getResult(x, y, 1, 0));
double presence = textures_renderer->getBasePresence(layer, terrain_renderer->getResult(x, y, true, false));
return Color(presence, presence, presence);
}

View file

@ -53,6 +53,6 @@ void TexturesMixPreviewRenderer::updateEvent()
Color TexturesMixPreviewRenderer::getColor2D(double x, double y, double scaling)
{
TerrainRenderer* terrain_renderer = getTerrainRenderer();
Vector3 location(x, terrain_renderer->getHeight(x, y, 1), y);
Vector3 location(x, terrain_renderer->getHeight(x, y, true), y);
return terrain_renderer->getFinalColor(location, scaling);
}

View file

@ -17,6 +17,7 @@
SoftwareCanvasRenderer::SoftwareCanvasRenderer()
{
started = false;
finished = false;
interrupted = false;
canvas = new Canvas();
progress = 0.0;
@ -95,6 +96,7 @@ void SoftwareCanvasRenderer::render()
progress = (double)i / (double)n;
}
}
finished = true;
}
void SoftwareCanvasRenderer::interrupt()

View file

@ -24,6 +24,7 @@ public:
inline const Canvas *getCanvas() const {return canvas;}
inline double getProgress() const {return progress;}
inline bool isFinished() const {return finished;}
/**
* Set the renderer configuration.
@ -78,6 +79,7 @@ private:
int samples;
std::vector<Rasterizer*> rasterizers;
bool started;
bool finished;
bool interrupted;
ParallelWork *current_work;

View file

@ -17,7 +17,7 @@ TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id):
static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z)
{
return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, 1), z);
return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, true), z);
}
void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail)
@ -52,19 +52,19 @@ void TerrainRasterizer::renderQuad(CanvasPortion *canvas, double x, double z, do
ov1.x = x;
ov1.z = z;
dv1 = renderer->getTerrainRenderer()->getResult(x, z, 1, 1).location;
dv1 = renderer->getTerrainRenderer()->getResult(x, z, true, true).location;
ov2.x = x;
ov2.z = z + size;
dv2 = renderer->getTerrainRenderer()->getResult(x, z + size, 1, 1).location;
dv2 = renderer->getTerrainRenderer()->getResult(x, z + size, true, true).location;
ov3.x = x + size;
ov3.z = z + size;
dv3 = renderer->getTerrainRenderer()->getResult(x + size, z + size, 1, 1).location;
dv3 = renderer->getTerrainRenderer()->getResult(x + size, z + size, true, true).location;
ov4.x = x + size;
ov4.z = z;
dv4 = renderer->getTerrainRenderer()->getResult(x + size, z, 1, 1).location;
dv4 = renderer->getTerrainRenderer()->getResult(x + size, z, true, true).location;
if (dv1.y > water_height || dv2.y > water_height || dv3.y > water_height || dv4.y > water_height)
{
@ -72,12 +72,12 @@ void TerrainRasterizer::renderQuad(CanvasPortion *canvas, double x, double z, do
}
}
static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChunkInfo* chunk, double x, double z, double size, int displaced)
static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChunkInfo* chunk, double x, double z, double size, bool displaced)
{
chunk->point_nw = renderer->getTerrainRenderer()->getResult(x, z, 1, displaced).location;
chunk->point_sw = renderer->getTerrainRenderer()->getResult(x, z + size, 1, displaced).location;
chunk->point_se = renderer->getTerrainRenderer()->getResult(x + size, z + size, 1, displaced).location;
chunk->point_ne = renderer->getTerrainRenderer()->getResult(x + size, z, 1, displaced).location;
chunk->point_nw = renderer->getTerrainRenderer()->getResult(x, z, true, displaced).location;
chunk->point_sw = renderer->getTerrainRenderer()->getResult(x, z + size, true, displaced).location;
chunk->point_se = renderer->getTerrainRenderer()->getResult(x + size, z + size, true, displaced).location;
chunk->point_ne = renderer->getTerrainRenderer()->getResult(x + size, z, true, displaced).location;
double displacement_power;
if (displaced)
@ -125,7 +125,7 @@ static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChun
}
}
void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, int displaced)
void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displaced)
{
TerrainChunkInfo chunk;
int chunk_factor, chunk_count, i;
@ -199,7 +199,7 @@ void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* ch
void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
{
getTessellationInfo(canvas, 0);
getTessellationInfo(canvas, false);
}
Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const

View file

@ -34,7 +34,7 @@ public:
*
* The terrain will be broken in chunks, most detailed near the camera.
*/
void getTessellationInfo(CanvasPortion* canvas, int displaced);
void getTessellationInfo(CanvasPortion* canvas, bool displaced);
/**
* Tessellate a terrain chunk, pushing the quads in the render area.

View file

@ -23,9 +23,9 @@ void TerrainRenderer::update()
walker->update();
}
double TerrainRenderer::getHeight(double x, double z, int with_painting)
double TerrainRenderer::getHeight(double x, double z, bool with_painting)
{
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, 1, with_painting);
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, true, with_painting);
}
static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west)
@ -50,7 +50,7 @@ static inline Vector3 _getNormal2(Vector3 center, Vector3 east, Vector3 south)
return south.sub(center).crossProduct(east.sub(center)).normalize();
}
TerrainRenderer::TerrainResult TerrainRenderer::getResult(double x, double z, int with_painting, int with_textures)
TerrainRenderer::TerrainResult TerrainRenderer::getResult(double x, double z, bool with_painting, bool with_textures)
{
TerrainResult result;
double detail = 0.001; /* TODO */

View file

@ -27,8 +27,8 @@ public:
virtual void update();
virtual RayCastingResult castRay(const Vector3 &start, const Vector3 &direction);
virtual double getHeight(double x, double z, int with_painting);
virtual TerrainResult getResult(double x, double z, int with_painting, int with_textures);
virtual double getHeight(double x, double z, bool with_painting);
virtual TerrainResult getResult(double x, double z, bool with_painting, bool with_textures);
virtual Color getFinalColor(const Vector3 &location, double precision);
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override;

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 \
Canvas_Test.cpp \
CanvasPortion_Test.cpp \
CanvasPreview_Test.cpp
CanvasPreview_Test.cpp \
AtmosphereDefinition_Test.cpp
HEADERS += \
BaseTestCase.h