paysages : Terrain canvas - Height map painting (WIP).
git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@390 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
parent
82181ed5b0
commit
2fc252f59a
4 changed files with 233 additions and 13 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include "dialogheightmap.h"
|
#include "dialogheightmap.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
@ -16,6 +17,7 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
|
||||||
QWidget* viewer;
|
QWidget* viewer;
|
||||||
QGridLayout* viewer_layout;
|
QGridLayout* viewer_layout;
|
||||||
|
|
||||||
|
QLabel* label;
|
||||||
QSlider* slider;
|
QSlider* slider;
|
||||||
QPushButton* button;
|
QPushButton* button;
|
||||||
|
|
||||||
|
@ -43,6 +45,7 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
|
||||||
panel = new QWidget(mainarea);
|
panel = new QWidget(mainarea);
|
||||||
panel->setLayout(new QVBoxLayout());
|
panel->setLayout(new QVBoxLayout());
|
||||||
mainarea->layout()->addWidget(panel);
|
mainarea->layout()->addWidget(panel);
|
||||||
|
mainarea->layout()->setAlignment(panel, Qt::AlignTop);
|
||||||
|
|
||||||
// Viewer layout (3d display + sliders)
|
// Viewer layout (3d display + sliders)
|
||||||
_3dview = new WidgetHeightMap(viewer, &_value_modified);
|
_3dview = new WidgetHeightMap(viewer, &_value_modified);
|
||||||
|
@ -57,10 +60,28 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
|
||||||
viewer_layout->addWidget(slider, 0, 1);
|
viewer_layout->addWidget(slider, 0, 1);
|
||||||
|
|
||||||
// Panel layout
|
// Panel layout
|
||||||
button = new QPushButton(tr("Reset to terrain height"), buttons);
|
button = new QPushButton(tr("Reset to terrain height"), panel);
|
||||||
connect(button, SIGNAL(clicked()), _3dview, SLOT(resetToTerrain()));
|
connect(button, SIGNAL(clicked()), _3dview, SLOT(resetToTerrain()));
|
||||||
panel->layout()->addWidget(button);
|
panel->layout()->addWidget(button);
|
||||||
|
|
||||||
|
label = new QLabel(tr("Brush size"), panel);
|
||||||
|
panel->layout()->addWidget(label);
|
||||||
|
|
||||||
|
slider = new QSlider(Qt::Horizontal, panel);
|
||||||
|
slider->setRange(6, 150);
|
||||||
|
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushSizeChanged(int)));
|
||||||
|
panel->layout()->addWidget(slider);
|
||||||
|
slider->setValue(30);
|
||||||
|
|
||||||
|
label = new QLabel(tr("Brush smoothing"), panel);
|
||||||
|
panel->layout()->addWidget(label);
|
||||||
|
|
||||||
|
slider = new QSlider(Qt::Horizontal, panel);
|
||||||
|
slider->setRange(0, 1000);
|
||||||
|
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushSmoothingChanged(int)));
|
||||||
|
panel->layout()->addWidget(slider);
|
||||||
|
slider->setValue(200);
|
||||||
|
|
||||||
// Buttons layout
|
// Buttons layout
|
||||||
button = new QPushButton(tr("Validate"), buttons);
|
button = new QPushButton(tr("Validate"), buttons);
|
||||||
buttons->layout()->addWidget(button);
|
buttons->layout()->addWidget(button);
|
||||||
|
@ -107,3 +128,13 @@ void DialogHeightMap::angleVChanged(int value)
|
||||||
{
|
{
|
||||||
_3dview->setVerticalViewAngle(M_PI_2 * ((double)value) / 1000.0);
|
_3dview->setVerticalViewAngle(M_PI_2 * ((double)value) / 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialogHeightMap::brushSizeChanged(int value)
|
||||||
|
{
|
||||||
|
_3dview->setBrushSize((double)value / 10.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogHeightMap::brushSmoothingChanged(int value)
|
||||||
|
{
|
||||||
|
_3dview->setBrushSmoothing((double)value / 1000.0);
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ public slots:
|
||||||
private slots:
|
private slots:
|
||||||
void angleHChanged(int value);
|
void angleHChanged(int value);
|
||||||
void angleVChanged(int value);
|
void angleVChanged(int value);
|
||||||
|
void brushSizeChanged(int value);
|
||||||
|
void brushSmoothingChanged(int value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HeightMap* _value_original;
|
HeightMap* _value_original;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "widgetheightmap.h"
|
#include "widgetheightmap.h"
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QMouseEvent>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <GL/glu.h>
|
#include <GL/glu.h>
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
@ -12,8 +13,12 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
|
||||||
{
|
{
|
||||||
setMinimumSize(500, 500);
|
setMinimumSize(500, 500);
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
_heightmap = heightmap;
|
_heightmap = heightmap;
|
||||||
|
_vertexes = new _VertexInfo[heightmap->resolution_x * heightmap->resolution_z];
|
||||||
|
|
||||||
|
_dirty = true;
|
||||||
|
|
||||||
_average_frame_time = 0.0;
|
_average_frame_time = 0.0;
|
||||||
|
|
||||||
|
@ -22,10 +27,16 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
|
||||||
|
|
||||||
_angle_h = 0.0;
|
_angle_h = 0.0;
|
||||||
_angle_v = 0.3;
|
_angle_v = 0.3;
|
||||||
|
|
||||||
|
_brush_x = 0.0;
|
||||||
|
_brush_z = 0.0;
|
||||||
|
_brush_size = 10.0;
|
||||||
|
_brush_smoothing = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetHeightMap::~WidgetHeightMap()
|
WidgetHeightMap::~WidgetHeightMap()
|
||||||
{
|
{
|
||||||
|
delete[] _vertexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetHeightMap::setHorizontalViewAngle(double angle_h)
|
void WidgetHeightMap::setHorizontalViewAngle(double angle_h)
|
||||||
|
@ -40,6 +51,22 @@ void WidgetHeightMap::setVerticalViewAngle(double angle_v)
|
||||||
updateGL();
|
updateGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetHeightMap::setBrushSize(double size)
|
||||||
|
{
|
||||||
|
_brush_size = size;
|
||||||
|
_brush_x = 0.0;
|
||||||
|
_brush_z = 0.0;
|
||||||
|
updateGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetHeightMap::setBrushSmoothing(double smoothing)
|
||||||
|
{
|
||||||
|
_brush_smoothing = smoothing;
|
||||||
|
_brush_x = 0.0;
|
||||||
|
_brush_z = 0.0;
|
||||||
|
updateGL();
|
||||||
|
}
|
||||||
|
|
||||||
void WidgetHeightMap::resetToTerrain()
|
void WidgetHeightMap::resetToTerrain()
|
||||||
{
|
{
|
||||||
TerrainDefinition terrain;
|
TerrainDefinition terrain;
|
||||||
|
@ -59,6 +86,7 @@ void WidgetHeightMap::resetToTerrain()
|
||||||
}
|
}
|
||||||
|
|
||||||
terrainDeleteDefinition(&terrain);
|
terrainDeleteDefinition(&terrain);
|
||||||
|
_dirty = true;
|
||||||
updateGL();
|
updateGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +100,44 @@ void WidgetHeightMap::mousePressEvent(QMouseEvent* event)
|
||||||
|
|
||||||
void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event)
|
void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
|
int move_x = event->x() - _last_mouse_x;
|
||||||
|
int move_y = event->y() - _last_mouse_y;
|
||||||
|
|
||||||
|
if (event->buttons() & Qt::MiddleButton)
|
||||||
|
{
|
||||||
|
// Rotate around the turntable
|
||||||
|
_angle_h -= (double)move_x * 0.008;
|
||||||
|
_angle_v += (double)move_y * 0.003;
|
||||||
|
|
||||||
|
updateGL();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// OpenGL picking using z-buffer
|
||||||
|
GLint viewport[4];
|
||||||
|
GLdouble modelview[16];
|
||||||
|
GLdouble projection[16];
|
||||||
|
GLfloat winX, winY, winZ;
|
||||||
|
Vector3 point;
|
||||||
|
|
||||||
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
|
||||||
|
glGetDoublev(GL_PROJECTION_MATRIX, projection);
|
||||||
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||||
|
|
||||||
|
winX = (float)event->x();
|
||||||
|
winY = (float)height() - (float)event->y();
|
||||||
|
glReadPixels(event->x(), (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
|
||||||
|
|
||||||
|
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &point.x, &point.y, &point.z);
|
||||||
|
|
||||||
|
_brush_x = point.x;
|
||||||
|
_brush_z = point.z;
|
||||||
|
|
||||||
|
updateGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
_last_mouse_x = event->x();
|
||||||
|
_last_mouse_y = event->y();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetHeightMap::wheelEvent(QWheelEvent* event)
|
void WidgetHeightMap::wheelEvent(QWheelEvent* event)
|
||||||
|
@ -82,19 +148,28 @@ void WidgetHeightMap::initializeGL()
|
||||||
{
|
{
|
||||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
glDisable(GL_LIGHTING);
|
GLfloat light_position[] = { 40.0, 40.0, 40.0, 0.0 };
|
||||||
|
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
|
||||||
|
GLfloat light_specular[] = { 0.0, 0.0, 0.0, 0.0 };
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
|
||||||
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
||||||
|
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glEnable(GL_LIGHT0);
|
||||||
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
|
|
||||||
glFrontFace(GL_CCW);
|
//glFrontFace(GL_CCW);
|
||||||
glCullFace(GL_BACK);
|
//glCullFace(GL_BACK);
|
||||||
glEnable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
glDepthFunc(GL_LESS);
|
glDepthFunc(GL_LESS);
|
||||||
glDepthMask(true);
|
glDepthMask(true);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
glEnable(GL_LINE_SMOOTH);
|
//glEnable(GL_LINE_SMOOTH);
|
||||||
glLineWidth(1.0);
|
//glLineWidth(1.0);
|
||||||
|
|
||||||
glDisable(GL_FOG);
|
glDisable(GL_FOG);
|
||||||
|
|
||||||
|
@ -121,6 +196,13 @@ void WidgetHeightMap::paintGL()
|
||||||
|
|
||||||
start_time = QTime::currentTime();
|
start_time = QTime::currentTime();
|
||||||
|
|
||||||
|
// Update vertex cache
|
||||||
|
if (_dirty)
|
||||||
|
{
|
||||||
|
updateVertexInfo();
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Place camera
|
// Place camera
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
@ -129,18 +211,57 @@ void WidgetHeightMap::paintGL()
|
||||||
// Background
|
// Background
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
glBegin(GL_POINTS);
|
// Height map
|
||||||
glColor3d(1.0, 0.0, 0.0);
|
|
||||||
rx = _heightmap->resolution_x;
|
rx = _heightmap->resolution_x;
|
||||||
rz = _heightmap->resolution_z;
|
rz = _heightmap->resolution_z;
|
||||||
for (int x = 0; x < rx; x++)
|
for (int x = 0; x < rx - 1; x++)
|
||||||
{
|
{
|
||||||
|
glBegin(GL_QUAD_STRIP);
|
||||||
for (int z = 0; z < rz; z++)
|
for (int z = 0; z < rz; z++)
|
||||||
{
|
{
|
||||||
glVertex3d(80.0 * (double)x / (double)(rx - 1) - 40.0, _heightmap->data[z * rx + x], 80.0 * (double)z / (double)(rz - 1) - 40.0);
|
_VertexInfo* vertex = _vertexes + z * rx + x;
|
||||||
|
double diff_x, diff_z, diff;
|
||||||
|
|
||||||
|
diff_x = (vertex + 1)->point.x - _brush_x;
|
||||||
|
diff_z = (vertex + 1)->point.z - _brush_z;
|
||||||
|
diff = sqrt(diff_x * diff_x + diff_z * diff_z);
|
||||||
|
if (diff > _brush_size)
|
||||||
|
{
|
||||||
|
diff = 0.0;
|
||||||
|
}
|
||||||
|
else if (diff > _brush_size * (1.0 - _brush_smoothing))
|
||||||
|
{
|
||||||
|
diff = 1.0 - (diff - _brush_size * (1.0 - _brush_smoothing)) / (_brush_size * _brush_smoothing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diff = 1.0;
|
||||||
|
}
|
||||||
|
glColor3d(1.0, 1.0 - diff, 1.0 - diff);
|
||||||
|
glNormal3d((vertex + 1)->normal.x, (vertex + 1)->normal.y, (vertex + 1)->normal.z);
|
||||||
|
glVertex3d((vertex + 1)->point.x, (vertex + 1)->point.y, (vertex + 1)->point.z);
|
||||||
|
|
||||||
|
diff_x = vertex->point.x - _brush_x;
|
||||||
|
diff_z = vertex->point.z - _brush_z;
|
||||||
|
diff = sqrt(diff_x * diff_x + diff_z * diff_z);
|
||||||
|
if (diff > _brush_size)
|
||||||
|
{
|
||||||
|
diff = 0.0;
|
||||||
|
}
|
||||||
|
else if (diff > _brush_size * (1.0 - _brush_smoothing))
|
||||||
|
{
|
||||||
|
diff = 1.0 - (diff - _brush_size * (1.0 - _brush_smoothing)) / (_brush_size * _brush_smoothing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diff = 1.0;
|
||||||
|
}
|
||||||
|
glColor3d(1.0, 1.0 - diff, 1.0 - diff);
|
||||||
|
glNormal3d(vertex->normal.x, vertex->normal.y, vertex->normal.z);
|
||||||
|
glVertex3d(vertex->point.x, vertex->point.y, vertex->point.z);
|
||||||
}
|
}
|
||||||
|
glEnd();
|
||||||
}
|
}
|
||||||
glEnd();
|
|
||||||
|
|
||||||
// Time stats
|
// Time stats
|
||||||
frame_time = 0.001 * (double)start_time.msecsTo(QTime::currentTime());
|
frame_time = 0.001 * (double)start_time.msecsTo(QTime::currentTime());
|
||||||
|
@ -152,3 +273,49 @@ void WidgetHeightMap::paintGL()
|
||||||
logDebug(QString("[OpenGL] ERROR : ") + (const char*)gluErrorString(error_code));
|
logDebug(QString("[OpenGL] ERROR : ") + (const char*)gluErrorString(error_code));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetHeightMap::updateVertexInfo()
|
||||||
|
{
|
||||||
|
int rx = _heightmap->resolution_x;
|
||||||
|
int rz = _heightmap->resolution_z;
|
||||||
|
|
||||||
|
// Update positions
|
||||||
|
for (int x = 0; x < rx; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < rz; z++)
|
||||||
|
{
|
||||||
|
_VertexInfo* vertex = _vertexes + z * rx + x;
|
||||||
|
|
||||||
|
vertex->point.x = 80.0 * (double)x / (double)(rx - 1) - 40.0;
|
||||||
|
vertex->point.y = _heightmap->data[z * rx + x];
|
||||||
|
vertex->point.z = 80.0 * (double)z / (double)(rz - 1) - 40.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update normals
|
||||||
|
for (int x = 0; x < rx; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < rz; z++)
|
||||||
|
{
|
||||||
|
_VertexInfo* vertex = _vertexes + z * rx + x;
|
||||||
|
|
||||||
|
if (x == rx - 1)
|
||||||
|
{
|
||||||
|
vertex->normal = (vertex - 1)->normal;
|
||||||
|
}
|
||||||
|
else if (z == rz - 1)
|
||||||
|
{
|
||||||
|
vertex->normal = (vertex - rx)->normal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector3 dx, dz;
|
||||||
|
|
||||||
|
dx = v3Sub((vertex + 1)->point, vertex->point);
|
||||||
|
dz = v3Sub((vertex + rx)->point, vertex->point);
|
||||||
|
|
||||||
|
vertex->normal = v3Cross(v3Normalize(dz), v3Normalize(dx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
#define _PAYSAGES_QT_WIDGETHEIGHTMAP_H_
|
#define _PAYSAGES_QT_WIDGETHEIGHTMAP_H_
|
||||||
|
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
|
#include "../lib_paysages/euclid.h"
|
||||||
#include "../lib_paysages/heightmap.h"
|
#include "../lib_paysages/heightmap.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Vector3 point;
|
||||||
|
Vector3 normal;
|
||||||
|
} _VertexInfo;
|
||||||
|
|
||||||
class WidgetHeightMap : public QGLWidget
|
class WidgetHeightMap : public QGLWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -13,6 +20,8 @@ public:
|
||||||
|
|
||||||
void setHorizontalViewAngle(double angle_h);
|
void setHorizontalViewAngle(double angle_h);
|
||||||
void setVerticalViewAngle(double angle_v);
|
void setVerticalViewAngle(double angle_v);
|
||||||
|
void setBrushSize(double size);
|
||||||
|
void setBrushSmoothing(double smoothing);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void resetToTerrain();
|
void resetToTerrain();
|
||||||
|
@ -27,8 +36,14 @@ protected:
|
||||||
void resizeGL(int w, int h);
|
void resizeGL(int w, int h);
|
||||||
void paintGL();
|
void paintGL();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateVertexInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HeightMap* _heightmap;
|
HeightMap* _heightmap;
|
||||||
|
_VertexInfo* _vertexes;
|
||||||
|
|
||||||
|
bool _dirty;
|
||||||
|
|
||||||
double _average_frame_time;
|
double _average_frame_time;
|
||||||
|
|
||||||
|
@ -37,6 +52,11 @@ private:
|
||||||
|
|
||||||
double _angle_h;
|
double _angle_h;
|
||||||
double _angle_v;
|
double _angle_v;
|
||||||
|
|
||||||
|
double _brush_x;
|
||||||
|
double _brush_z;
|
||||||
|
double _brush_size;
|
||||||
|
double _brush_smoothing;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue