From a52321fd456e73c2d3909f974501ad1d3afb1b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Fri, 13 Jul 2012 12:23:58 +0000 Subject: [PATCH] paysages : Terrain canvas (WIP). git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@388 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- gui_qt/baseform.cpp | 6 +++ gui_qt/baseform.h | 2 + gui_qt/dialogheightmap.cpp | 93 ++++++++++++++++++++++++++++++++++ gui_qt/dialogheightmap.h | 25 +++++++++ gui_qt/formterraincanvas.cpp | 6 +-- gui_qt/inputheightmap.cpp | 59 ++++++++++++++++++++++ gui_qt/inputheightmap.h | 28 +++++++++++ gui_qt/widgetheightmap.cpp | 98 ++++++++++++++++++++++++++++++++++++ gui_qt/widgetheightmap.h | 30 +++++++++++ lib_paysages/heightmap.c | 56 +++++++++++++++++++++ lib_paysages/heightmap.h | 31 ++++++++++++ lib_paysages/terraincanvas.c | 31 +++--------- lib_paysages/terraincanvas.h | 8 +-- 13 files changed, 438 insertions(+), 35 deletions(-) create mode 100644 gui_qt/dialogheightmap.cpp create mode 100644 gui_qt/dialogheightmap.h create mode 100644 gui_qt/inputheightmap.cpp create mode 100644 gui_qt/inputheightmap.h create mode 100644 gui_qt/widgetheightmap.cpp create mode 100644 gui_qt/widgetheightmap.h create mode 100644 lib_paysages/heightmap.c create mode 100644 lib_paysages/heightmap.h diff --git a/gui_qt/baseform.cpp b/gui_qt/baseform.cpp index 5463568..27fd578 100644 --- a/gui_qt/baseform.cpp +++ b/gui_qt/baseform.cpp @@ -8,6 +8,7 @@ #include "inputnoise.h" #include "inputcurve.h" #include "inputmaterial.h" +#include "inputheightmap.h" #include "inputenum.h" #include "inputlayers.h" @@ -407,6 +408,11 @@ BaseInput* BaseForm::addInputMaterial(QString label, SurfaceMaterial* material) return addInput(new InputMaterial(_form, label, material)); } +BaseInput* BaseForm::addInputHeightMap(QString label, HeightMap* heightmap) +{ + return addInput(new InputHeightMap(_form, label, heightmap)); +} + BaseInput* BaseForm::addInputEnum(QString label, int* value, const QStringList& values) { return addInput(new InputEnum(_form, label, value, values)); diff --git a/gui_qt/baseform.h b/gui_qt/baseform.h index c648f28..6e94c3b 100644 --- a/gui_qt/baseform.h +++ b/gui_qt/baseform.h @@ -13,6 +13,7 @@ #include "../lib_paysages/curve.h" #include "../lib_paysages/color.h" #include "../lib_paysages/layers.h" +#include "../lib_paysages/heightmap.h" #include "../lib_paysages/pack.h" class BaseForm:public QWidget @@ -56,6 +57,7 @@ protected: BaseInput* addInputNoise(QString label, NoiseGenerator* value); BaseInput* addInputCurve(QString label, Curve* value, double xmin, double xmax, double ymin, double ymax, QString xlabel, QString ylabel); BaseInput* addInputMaterial(QString label, SurfaceMaterial* material); + BaseInput* addInputHeightMap(QString label, HeightMap* heightmap); BaseInput* addInputEnum(QString label, int* value, const QStringList& values); BaseInput* addInputLayers(QString label, Layers* value, FormLayerBuilder form_builder); diff --git a/gui_qt/dialogheightmap.cpp b/gui_qt/dialogheightmap.cpp new file mode 100644 index 0000000..005859b --- /dev/null +++ b/gui_qt/dialogheightmap.cpp @@ -0,0 +1,93 @@ +#include "dialogheightmap.h" +#include "widgetheightmap.h" + +#include +#include +#include +#include + +/**************** Dialog form ****************/ +DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : DialogWithPreview(parent) +{ + QWidget* mainarea; + QWidget* buttons; + QWidget* panel; + QWidget* viewer; + QGridLayout* viewer_layout; + + QSlider* slider; + QPushButton* button; + + _value_original = heightmap; + _value_modified = heightmapCreate(); + heightmapCopy(_value_original, &_value_modified); + setLayout(new QVBoxLayout()); + + // Dialog layout (main area + buttons) + mainarea = new QWidget(this); + mainarea->setLayout(new QHBoxLayout()); + this->layout()->addWidget(mainarea); + + buttons = new QWidget(this); + buttons->setLayout(new QHBoxLayout()); + buttons->layout()->setAlignment(buttons, Qt::AlignBottom); + this->layout()->addWidget(buttons); + + // Main area layout (viewer + panel) + viewer = new QWidget(mainarea); + viewer_layout = new QGridLayout(); + viewer->setLayout(viewer_layout); + mainarea->layout()->addWidget(viewer); + + panel = new QWidget(mainarea); + panel->setLayout(new QVBoxLayout()); + mainarea->layout()->addWidget(panel); + + // Viewer layout (3d display + sliders) + _3dview = new WidgetHeightMap(viewer, &_value_modified); + viewer_layout->addWidget(_3dview, 0, 0); + slider = new QSlider(Qt::Horizontal, viewer); + viewer_layout->addWidget(slider, 1, 0); + slider = new QSlider(Qt::Vertical, viewer); + viewer_layout->addWidget(slider, 0, 1); + + // Panel layout + button = new QPushButton(tr("Reset to terrain height"), buttons); + panel->layout()->addWidget(button); + + // Buttons layout + button = new QPushButton(tr("Validate"), buttons); + buttons->layout()->addWidget(button); + QObject::connect(button, SIGNAL(clicked()), this, SLOT(accept())); + + button = new QPushButton(tr("Revert"), buttons); + buttons->layout()->addWidget(button); + QObject::connect(button, SIGNAL(clicked()), this, SLOT(revert())); + + button = new QPushButton(tr("Cancel"), buttons); + buttons->layout()->addWidget(button); + QObject::connect(button, SIGNAL(clicked()), this, SLOT(reject())); + + setWindowTitle(tr("Paysages 3D - Height map painting")); +} + +bool DialogHeightMap::editHeightMap(QWidget* parent, HeightMap* heightmap) +{ + int result; + + DialogHeightMap* dialog = new DialogHeightMap(parent, heightmap); + result = dialog->exec(); + + delete dialog; + + return (result != 0) ? true : false; +} + +void DialogHeightMap::accept() +{ + QDialog::accept(); +} + +void DialogHeightMap::revert() +{ +} diff --git a/gui_qt/dialogheightmap.h b/gui_qt/dialogheightmap.h new file mode 100644 index 0000000..05b5ac4 --- /dev/null +++ b/gui_qt/dialogheightmap.h @@ -0,0 +1,25 @@ +#ifndef _PAYSAGES_QT_DIALOGHEIGHTMAP_H_ +#define _PAYSAGES_QT_DIALOGHEIGHTMAP_H_ + +#include "tools.h" +#include "widgetheightmap.h" +#include "../lib_paysages/heightmap.h" + +class DialogHeightMap : public DialogWithPreview +{ + Q_OBJECT +public: + explicit DialogHeightMap(QWidget* parent, HeightMap* heightmap); + static bool editHeightMap(QWidget* parent, HeightMap* heightmap); + +public slots: + virtual void accept(); + void revert(); + +private: + HeightMap* _value_original; + HeightMap _value_modified; + WidgetHeightMap* _3dview; +}; + +#endif diff --git a/gui_qt/formterraincanvas.cpp b/gui_qt/formterraincanvas.cpp index 7239bb7..6851e49 100644 --- a/gui_qt/formterraincanvas.cpp +++ b/gui_qt/formterraincanvas.cpp @@ -8,13 +8,13 @@ FormTerrainCanvas::FormTerrainCanvas(QWidget *parent, Layers* layers): // TODO Area addInputDouble(tr("Apply at height"), &_definition->offset_z, -20.0, 20.0, 0.1, 1.0); - // TODO Height map + addInputHeightMap(tr("Height map"), &_definition->height_map); addInputDouble(tr("Canvas height"), &_definition->height_factor, 0.0, 20.0, 0.1, 1.0); addInputNoise(tr("Detail noise"), _definition->detail_noise); addInputDouble(tr("Detail noise height"), &_definition->detail_height_factor, 0.0, 20.0, 0.1, 1.0); addInputDouble(tr("Detail noise scaling"), &_definition->detail_scaling, 0.0, 20.0, 0.1, 1.0); - // TODO Mask mode - // TODO Mask smoothing + addInputEnum(tr("Mask shape"), &_definition->mask_mode, QStringList(tr("Square")) << tr("Circle")); + addInputDouble(tr("Mask smoothing"), &_definition->mask_smoothing, 0.0, 1.0, 0.01, 0.1); revertConfig(); } diff --git a/gui_qt/inputheightmap.cpp b/gui_qt/inputheightmap.cpp new file mode 100644 index 0000000..640040d --- /dev/null +++ b/gui_qt/inputheightmap.cpp @@ -0,0 +1,59 @@ +#include "inputheightmap.h" + +#include +#include +#include "dialogheightmap.h" + +class SmallPreviewHeightMap:public QWidget +{ +public: + SmallPreviewHeightMap(QWidget* parent, HeightMap* value) : QWidget(parent) + { + _value = value; + } + + void paintEvent(QPaintEvent* event) + { + QPainter painter(this); + painter.fillRect(this->rect(), Qt::black); + } + HeightMap* _value; +}; + +InputHeightMap::InputHeightMap(QWidget* form, QString label, HeightMap* value) : BaseInput(form, label) +{ + _value = value; + + _preview = new SmallPreviewHeightMap(form, value); + _preview->setMinimumSize(100, 40); + + _control = new QPushButton(tr("Paint"), form); + _control->setMaximumWidth(150); + + connect((QPushButton*)_control, SIGNAL(clicked()), this, SLOT(editHeightMap())); +} + +void InputHeightMap::updatePreview() +{ + _preview->update(); + + BaseInput::updatePreview(); +} + +void InputHeightMap::applyValue() +{ + BaseInput::applyValue(); +} + +void InputHeightMap::revert() +{ + BaseInput::revert(); +} + +void InputHeightMap::editHeightMap() +{ + if (DialogHeightMap::editHeightMap(_control, _value)) + { + applyValue(); + } +} diff --git a/gui_qt/inputheightmap.h b/gui_qt/inputheightmap.h new file mode 100644 index 0000000..2cd25cd --- /dev/null +++ b/gui_qt/inputheightmap.h @@ -0,0 +1,28 @@ +#ifndef _PAYSAGES_QT_INPUTHEIGHTMAP_H_ +#define _PAYSAGES_QT_INPUTHEIGHTMAP_H_ + +#include +#include "baseinput.h" + +#include "../lib_paysages/heightmap.h" + +class InputHeightMap:public BaseInput +{ + Q_OBJECT + +public: + InputHeightMap(QWidget* form, QString label, HeightMap* value); + +public slots: + virtual void updatePreview(); + virtual void applyValue(); + virtual void revert(); + +private slots: + void editHeightMap(); + +private: + HeightMap* _value; +}; + +#endif diff --git a/gui_qt/widgetheightmap.cpp b/gui_qt/widgetheightmap.cpp new file mode 100644 index 0000000..6efbc03 --- /dev/null +++ b/gui_qt/widgetheightmap.cpp @@ -0,0 +1,98 @@ +#include "widgetheightmap.h" + +#include +#include +#include +#include "tools.h" + +WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap): + QGLWidget(parent) +{ + setMinimumSize(500, 500); + setFocusPolicy(Qt::StrongFocus); + + _average_frame_time = 0.0; + _last_mouse_x = 0; + _last_mouse_y = 0; +} + +WidgetHeightMap::~WidgetHeightMap() +{ +} + +void WidgetHeightMap::keyPressEvent(QKeyEvent* event) +{ +} + +void WidgetHeightMap::mousePressEvent(QMouseEvent* event) +{ +} + +void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event) +{ +} + +void WidgetHeightMap::wheelEvent(QWheelEvent* event) +{ +} + +void WidgetHeightMap::initializeGL() +{ + glClearColor(0.0, 0.0, 0.0, 0.0); + + glDisable(GL_LIGHTING); + + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + + glDepthFunc(GL_LESS); + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_LINE_SMOOTH); + glLineWidth(1.0); + + glDisable(GL_FOG); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void WidgetHeightMap::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + //gluPerspective(_current_camera.yfov * 180.0 / M_PI, _current_camera.xratio, _current_camera.znear, _current_camera.zfar); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void WidgetHeightMap::paintGL() +{ + GLenum error_code; + QTime start_time; + double frame_time; + + start_time = QTime::currentTime(); + + // Place camera + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + //gluLookAt(_current_camera.location.x, _current_camera.location.y, _current_camera.location.z, _current_camera.target.x, _current_camera.target.y, _current_camera.target.z, _current_camera.up.x, _current_camera.up.y, _current_camera.up.z); + + // Background + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Time stats + frame_time = 0.001 * (double)start_time.msecsTo(QTime::currentTime()); + _average_frame_time = _average_frame_time * 0.8 + frame_time * 0.2; + //printf("%d %f\n", quality, average_frame_time); + + while ((error_code = glGetError()) != GL_NO_ERROR) + { + logDebug(QString("[OpenGL] ERROR : ") + (const char*)gluErrorString(error_code)); + } +} diff --git a/gui_qt/widgetheightmap.h b/gui_qt/widgetheightmap.h new file mode 100644 index 0000000..f0b2273 --- /dev/null +++ b/gui_qt/widgetheightmap.h @@ -0,0 +1,30 @@ +#ifndef _PAYSAGES_QT_WIDGETHEIGHTMAP_H_ +#define _PAYSAGES_QT_WIDGETHEIGHTMAP_H_ + +#include +#include "../lib_paysages/heightmap.h" + +class WidgetHeightMap : public QGLWidget +{ + Q_OBJECT +public: + WidgetHeightMap(QWidget* parent, HeightMap* heightmap); + ~WidgetHeightMap(); + +protected: + void keyPressEvent(QKeyEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void wheelEvent(QWheelEvent* event); + + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + +private: + double _average_frame_time; + int _last_mouse_x; + int _last_mouse_y; +}; + +#endif diff --git a/lib_paysages/heightmap.c b/lib_paysages/heightmap.c new file mode 100644 index 0000000..bc22ce9 --- /dev/null +++ b/lib_paysages/heightmap.c @@ -0,0 +1,56 @@ +#include "heightmap.h" + +#include +#include + +HeightMap heightmapCreate() +{ + HeightMap result; + + result.data = malloc(sizeof(double)); + result.resolution_x = 1; + result.resolution_z = 1; + + return result; +} + +void heightmapDelete(HeightMap* heightmap) +{ + free(heightmap->data); +} + +void heightmapCopy(HeightMap* source, HeightMap* destination) +{ + destination->resolution_x = source->resolution_x; + destination->resolution_z = source->resolution_z; + destination->data = realloc(destination->data, sizeof(double) * destination->resolution_x * destination->resolution_z); + memcpy(destination->data, source->data, sizeof(double) * destination->resolution_x * destination->resolution_z); +} + +void heightmapValidate(HeightMap* heightmap) +{ +} + +void heightmapSave(PackStream* stream, HeightMap* heightmap) +{ + int i; + + packWriteInt(stream, &heightmap->resolution_x); + packWriteInt(stream, &heightmap->resolution_z); + for (i = 0; i < heightmap->resolution_x * heightmap->resolution_z; i++) + { + packWriteDouble(stream, &heightmap->data[i]); + } +} + +void heightmapLoad(PackStream* stream, HeightMap* heightmap) +{ + int i; + + packReadInt(stream, &heightmap->resolution_x); + packReadInt(stream, &heightmap->resolution_z); + for (i = 0; i < heightmap->resolution_x * heightmap->resolution_z; i++) + { + packReadDouble(stream, &heightmap->data[i]); + } +} diff --git a/lib_paysages/heightmap.h b/lib_paysages/heightmap.h new file mode 100644 index 0000000..9011e18 --- /dev/null +++ b/lib_paysages/heightmap.h @@ -0,0 +1,31 @@ +#ifndef _PAYSAGES_HEIGHTMAP_H_ +#define _PAYSAGES_HEIGHTMAP_H_ + +/* Height map for terrain */ + +#include "pack.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int resolution_x; + int resolution_z; + double* data; +} HeightMap; + +HeightMap heightmapCreate(); +void heightmapDelete(HeightMap* heightmap); +void heightmapCopy(HeightMap* source, HeightMap* destination); +void heightmapValidate(HeightMap* heightmap); + +void heightmapSave(PackStream* stream, HeightMap* heightmap); +void heightmapLoad(PackStream* stream, HeightMap* heightmap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_paysages/terraincanvas.c b/lib_paysages/terraincanvas.c index c849241..750ab8e 100644 --- a/lib_paysages/terraincanvas.c +++ b/lib_paysages/terraincanvas.c @@ -13,9 +13,7 @@ TerrainCanvas* terrainCanvasCreate() result->area.size_x = 1.0; result->area.size_z = 1.0; result->offset_z = 0.0; - result->height_map.data = malloc(sizeof(double)); - result->height_map.resolution_x = 1; - result->height_map.resolution_z = 1; + result->height_map = heightmapCreate(); result->height_factor = 1.0; result->detail_noise = noiseCreateGenerator(); result->detail_height_factor = 0.1; @@ -28,7 +26,7 @@ TerrainCanvas* terrainCanvasCreate() void terrainCanvasDelete(TerrainCanvas* canvas) { - free(canvas->height_map.data); + heightmapDelete(&canvas->height_map); noiseDeleteGenerator(canvas->detail_noise); free(canvas); } @@ -37,11 +35,8 @@ void terrainCanvasCopy(TerrainCanvas* source, TerrainCanvas* destination) { destination->area = source->area; destination->offset_z = source->offset_z; - destination->height_map.resolution_x = source->height_map.resolution_x; - destination->height_map.resolution_z = source->height_map.resolution_z; - destination->height_map.data = realloc(destination->height_map.data, sizeof(double) * destination->height_map.resolution_x * destination->height_map.resolution_z); - memcpy(destination->height_map.data, source->height_map.data, sizeof(double) * destination->height_map.resolution_x * destination->height_map.resolution_z); destination->height_factor = source->height_factor; + heightmapCopy(&source->height_map, &destination->height_map); noiseCopy(source->detail_noise, destination->detail_noise); destination->detail_height_factor = source->detail_height_factor; destination->detail_scaling = source->detail_scaling; @@ -55,6 +50,7 @@ void terrainCanvasValidate(TerrainCanvas* canvas) { canvas->detail_scaling = 0.00001; } + heightmapValidate(&canvas->height_map); noiseValidate(canvas->detail_noise); } @@ -74,20 +70,13 @@ LayerType terrainCanvasGetLayerType() void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas) { - int i; - packWriteInt(stream, &canvas->area.bounded); packWriteDouble(stream, &canvas->area.location_x); packWriteDouble(stream, &canvas->area.location_z); packWriteDouble(stream, &canvas->area.size_x); packWriteDouble(stream, &canvas->area.size_z); packWriteDouble(stream, &canvas->offset_z); - packWriteInt(stream, &canvas->height_map.resolution_x); - packWriteInt(stream, &canvas->height_map.resolution_z); - for (i = 0; i < canvas->height_map.resolution_x * canvas->height_map.resolution_z; i++) - { - packWriteDouble(stream, &canvas->height_map.data[i]); - } + heightmapSave(stream, &canvas->height_map); packWriteDouble(stream, &canvas->height_factor); noiseSaveGenerator(stream, canvas->detail_noise); packWriteDouble(stream, &canvas->detail_height_factor); @@ -98,21 +87,13 @@ void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas) void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas) { - int i; - packReadInt(stream, &canvas->area.bounded); packReadDouble(stream, &canvas->area.location_x); packReadDouble(stream, &canvas->area.location_z); packReadDouble(stream, &canvas->area.size_x); packReadDouble(stream, &canvas->area.size_z); packReadDouble(stream, &canvas->offset_z); - packReadInt(stream, &canvas->height_map.resolution_x); - packReadInt(stream, &canvas->height_map.resolution_z); - canvas->height_map.data = realloc(canvas->height_map.data, sizeof(double) * canvas->height_map.resolution_x * canvas->height_map.resolution_z); - for (i = 0; i < canvas->height_map.resolution_x * canvas->height_map.resolution_z; i++) - { - packReadDouble(stream, &canvas->height_map.data[i]); - } + heightmapLoad(stream, &canvas->height_map); packReadDouble(stream, &canvas->height_factor); noiseLoadGenerator(stream, canvas->detail_noise); packReadDouble(stream, &canvas->detail_height_factor); diff --git a/lib_paysages/terraincanvas.h b/lib_paysages/terraincanvas.h index a8e45f4..273b70a 100644 --- a/lib_paysages/terraincanvas.h +++ b/lib_paysages/terraincanvas.h @@ -7,6 +7,7 @@ #include "noise.h" #include "terrain.h" #include "layers.h" +#include "heightmap.h" #ifdef __cplusplus extern "C" { @@ -21,13 +22,6 @@ typedef struct double size_z; } GeoArea; -typedef struct -{ - int resolution_x; - int resolution_z; - double* data; -} HeightMap; - #define TERRAINCANVAS_MASKMODE_SQUARE 0 #define TERRAINCANVAS_MASKMODE_CIRCLE 1