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 <QLabel>
|
||||
#include <QBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
@ -16,6 +17,7 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
|
|||
QWidget* viewer;
|
||||
QGridLayout* viewer_layout;
|
||||
|
||||
QLabel* label;
|
||||
QSlider* slider;
|
||||
QPushButton* button;
|
||||
|
||||
|
@ -43,6 +45,7 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
|
|||
panel = new QWidget(mainarea);
|
||||
panel->setLayout(new QVBoxLayout());
|
||||
mainarea->layout()->addWidget(panel);
|
||||
mainarea->layout()->setAlignment(panel, Qt::AlignTop);
|
||||
|
||||
// Viewer layout (3d display + sliders)
|
||||
_3dview = new WidgetHeightMap(viewer, &_value_modified);
|
||||
|
@ -57,10 +60,28 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
|
|||
viewer_layout->addWidget(slider, 0, 1);
|
||||
|
||||
// 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()));
|
||||
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
|
||||
button = new QPushButton(tr("Validate"), buttons);
|
||||
buttons->layout()->addWidget(button);
|
||||
|
@ -107,3 +128,13 @@ void DialogHeightMap::angleVChanged(int value)
|
|||
{
|
||||
_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:
|
||||
void angleHChanged(int value);
|
||||
void angleVChanged(int value);
|
||||
void brushSizeChanged(int value);
|
||||
void brushSmoothingChanged(int value);
|
||||
|
||||
private:
|
||||
HeightMap* _value_original;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "widgetheightmap.h"
|
||||
|
||||
#include <QTime>
|
||||
#include <QMouseEvent>
|
||||
#include <math.h>
|
||||
#include <GL/glu.h>
|
||||
#include "tools.h"
|
||||
|
@ -12,8 +13,12 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
|
|||
{
|
||||
setMinimumSize(500, 500);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setMouseTracking(true);
|
||||
|
||||
_heightmap = heightmap;
|
||||
_vertexes = new _VertexInfo[heightmap->resolution_x * heightmap->resolution_z];
|
||||
|
||||
_dirty = true;
|
||||
|
||||
_average_frame_time = 0.0;
|
||||
|
||||
|
@ -22,10 +27,16 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
|
|||
|
||||
_angle_h = 0.0;
|
||||
_angle_v = 0.3;
|
||||
|
||||
_brush_x = 0.0;
|
||||
_brush_z = 0.0;
|
||||
_brush_size = 10.0;
|
||||
_brush_smoothing = 0.5;
|
||||
}
|
||||
|
||||
WidgetHeightMap::~WidgetHeightMap()
|
||||
{
|
||||
delete[] _vertexes;
|
||||
}
|
||||
|
||||
void WidgetHeightMap::setHorizontalViewAngle(double angle_h)
|
||||
|
@ -40,6 +51,22 @@ void WidgetHeightMap::setVerticalViewAngle(double angle_v)
|
|||
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()
|
||||
{
|
||||
TerrainDefinition terrain;
|
||||
|
@ -59,6 +86,7 @@ void WidgetHeightMap::resetToTerrain()
|
|||
}
|
||||
|
||||
terrainDeleteDefinition(&terrain);
|
||||
_dirty = true;
|
||||
updateGL();
|
||||
}
|
||||
|
||||
|
@ -72,6 +100,44 @@ void WidgetHeightMap::mousePressEvent(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)
|
||||
|
@ -82,19 +148,28 @@ 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);
|
||||
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);
|
||||
//glCullFace(GL_BACK);
|
||||
glDisable(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);
|
||||
//glEnable(GL_LINE_SMOOTH);
|
||||
//glLineWidth(1.0);
|
||||
|
||||
glDisable(GL_FOG);
|
||||
|
||||
|
@ -121,6 +196,13 @@ void WidgetHeightMap::paintGL()
|
|||
|
||||
start_time = QTime::currentTime();
|
||||
|
||||
// Update vertex cache
|
||||
if (_dirty)
|
||||
{
|
||||
updateVertexInfo();
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
// Place camera
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
@ -129,18 +211,57 @@ void WidgetHeightMap::paintGL()
|
|||
// Background
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glBegin(GL_POINTS);
|
||||
glColor3d(1.0, 0.0, 0.0);
|
||||
// Height map
|
||||
rx = _heightmap->resolution_x;
|
||||
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++)
|
||||
{
|
||||
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
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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_
|
||||
|
||||
#include <QGLWidget>
|
||||
#include "../lib_paysages/euclid.h"
|
||||
#include "../lib_paysages/heightmap.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Vector3 point;
|
||||
Vector3 normal;
|
||||
} _VertexInfo;
|
||||
|
||||
class WidgetHeightMap : public QGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -13,6 +20,8 @@ public:
|
|||
|
||||
void setHorizontalViewAngle(double angle_h);
|
||||
void setVerticalViewAngle(double angle_v);
|
||||
void setBrushSize(double size);
|
||||
void setBrushSmoothing(double smoothing);
|
||||
|
||||
public slots:
|
||||
void resetToTerrain();
|
||||
|
@ -27,8 +36,14 @@ protected:
|
|||
void resizeGL(int w, int h);
|
||||
void paintGL();
|
||||
|
||||
private:
|
||||
void updateVertexInfo();
|
||||
|
||||
private:
|
||||
HeightMap* _heightmap;
|
||||
_VertexInfo* _vertexes;
|
||||
|
||||
bool _dirty;
|
||||
|
||||
double _average_frame_time;
|
||||
|
||||
|
@ -37,6 +52,11 @@ private:
|
|||
|
||||
double _angle_h;
|
||||
double _angle_v;
|
||||
|
||||
double _brush_x;
|
||||
double _brush_z;
|
||||
double _brush_size;
|
||||
double _brush_smoothing;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue