paysages : Terrain canvas - Height map painting (WIP).

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@392 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2012-07-16 20:34:01 +00:00 committed by ThunderK
parent 62e0ef5859
commit 818b8b7b86
9 changed files with 150 additions and 68 deletions

View file

@ -88,6 +88,15 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog
slider->setRange(0, 1000); slider->setRange(0, 1000);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushSmoothingChanged(int))); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushSmoothingChanged(int)));
panel->layout()->addWidget(slider); panel->layout()->addWidget(slider);
slider->setValue(600);
label = new QLabel(tr("Brush strength"), panel);
panel->layout()->addWidget(label);
slider = new QSlider(Qt::Horizontal, panel);
slider->setRange(0, 1000);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushStrengthChanged(int)));
panel->layout()->addWidget(slider);
slider->setValue(200); slider->setValue(200);
// Buttons layout // Buttons layout
@ -120,11 +129,14 @@ bool DialogHeightMap::editHeightMap(QWidget* parent, HeightMap* heightmap)
void DialogHeightMap::accept() void DialogHeightMap::accept()
{ {
heightmapCopy(&_value_modified, _value_original);
QDialog::accept(); QDialog::accept();
} }
void DialogHeightMap::revert() void DialogHeightMap::revert()
{ {
heightmapCopy(_value_original, &_value_modified);
_3dview->revert();
} }
void DialogHeightMap::angleHChanged(int value) void DialogHeightMap::angleHChanged(int value)
@ -151,3 +163,8 @@ void DialogHeightMap::brushSmoothingChanged(int value)
{ {
_3dview->setBrushSmoothing((double)value / 1000.0); _3dview->setBrushSmoothing((double)value / 1000.0);
} }
void DialogHeightMap::brushStrengthChanged(int value)
{
_3dview->setBrushStrength((double)value / 2000.0);
}

View file

@ -22,6 +22,7 @@ private slots:
void brushModeChanged(int value); void brushModeChanged(int value);
void brushSizeChanged(int value); void brushSizeChanged(int value);
void brushSmoothingChanged(int value); void brushSmoothingChanged(int value);
void brushStrengthChanged(int value);
private: private:
HeightMap* _value_original; HeightMap* _value_original;

View file

@ -14,6 +14,8 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
setMinimumSize(500, 500); setMinimumSize(500, 500);
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true); setMouseTracking(true);
setCursor(Qt::CrossCursor);
startTimer(100);
_heightmap = heightmap; _heightmap = heightmap;
_vertexes = new _VertexInfo[heightmap->resolution_x * heightmap->resolution_z]; _vertexes = new _VertexInfo[heightmap->resolution_x * heightmap->resolution_z];
@ -22,6 +24,7 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
_average_frame_time = 0.0; _average_frame_time = 0.0;
_last_brush_action = 0;
_last_mouse_x = 0; _last_mouse_x = 0;
_last_mouse_y = 0; _last_mouse_y = 0;
@ -33,6 +36,7 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap):
_brush_mode = HEIGHTMAP_BRUSH_RAISE; _brush_mode = HEIGHTMAP_BRUSH_RAISE;
_brush_size = 10.0; _brush_size = 10.0;
_brush_smoothing = 0.5; _brush_smoothing = 0.5;
_brush_strength = 1.0;
} }
WidgetHeightMap::~WidgetHeightMap() WidgetHeightMap::~WidgetHeightMap()
@ -55,6 +59,9 @@ void WidgetHeightMap::setVerticalViewAngle(double angle_v)
void WidgetHeightMap::setBrushMode(HeightMapBrushMode mode) void WidgetHeightMap::setBrushMode(HeightMapBrushMode mode)
{ {
_brush_mode = mode; _brush_mode = mode;
_brush_x = 0.0;
_brush_z = 0.0;
updateGL();
} }
void WidgetHeightMap::setBrushSize(double size) void WidgetHeightMap::setBrushSize(double size)
@ -73,6 +80,20 @@ void WidgetHeightMap::setBrushSmoothing(double smoothing)
updateGL(); updateGL();
} }
void WidgetHeightMap::setBrushStrength(double strength)
{
_brush_strength = strength;
_brush_x = 0.0;
_brush_z = 0.0;
updateGL();
}
void WidgetHeightMap::revert()
{
_dirty = true;
updateGL();
}
void WidgetHeightMap::resetToTerrain() void WidgetHeightMap::resetToTerrain()
{ {
TerrainDefinition terrain; TerrainDefinition terrain;
@ -92,83 +113,69 @@ void WidgetHeightMap::resetToTerrain()
} }
terrainDeleteDefinition(&terrain); terrainDeleteDefinition(&terrain);
_dirty = true; revert();
updateGL();
}
void WidgetHeightMap::keyPressEvent(QKeyEvent* event)
{
} }
void WidgetHeightMap::mousePressEvent(QMouseEvent* event) void WidgetHeightMap::mousePressEvent(QMouseEvent* event)
{ {
mouseMoveEvent(event); _last_mouse_x = event->x();
_last_mouse_y = event->y();
if (event->buttons() & Qt::LeftButton)
{
_last_brush_action = 1;
}
else if (event->buttons() & Qt::RightButton)
{
_last_brush_action = -1;
}
}
void WidgetHeightMap::mouseReleaseEvent(QMouseEvent* event)
{
_last_brush_action = 0;
} }
void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event) void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event)
{ {
int move_x = event->x() - _last_mouse_x; if (event->buttons() & Qt::MiddleButton)
int move_y = event->y() - _last_mouse_y; {
// Rotate around the turntable
int move_x = event->x() - _last_mouse_x;
int move_y = event->y() - _last_mouse_y;
_angle_h -= (double)move_x * 0.008;
_angle_v += (double)move_y * 0.003;
}
if ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::RightButton)) _last_mouse_x = event->x();
_last_mouse_y = event->y();
updateGL();
}
void WidgetHeightMap::timerEvent(QTimerEvent* event)
{
if (_last_brush_action)
{ {
HeightMapBrush brush; HeightMapBrush brush;
brush.relative_x = (_brush_x + 40.0) / 80.0; brush.relative_x = (_brush_x + 40.0) / 80.0;
brush.relative_z = (_brush_z + 40.0) / 80.0; brush.relative_z = (_brush_z + 40.0) / 80.0;
brush.hard_radius = _brush_size / 80.0 - _brush_smoothing; brush.hard_radius = _brush_size * (1.0 - _brush_smoothing) / 80.0;
brush.smoothed_size = (_brush_size / 80.0) * _brush_smoothing; brush.smoothed_size = _brush_size * _brush_smoothing / 80.0;
switch (_brush_mode) switch (_brush_mode)
{ {
case HEIGHTMAP_BRUSH_RAISE: case HEIGHTMAP_BRUSH_RAISE:
heightmapBrushElevation(_heightmap, &brush, (event->buttons() & Qt::RightButton) ? -0.01 : 0.01); heightmapBrushElevation(_heightmap, &brush, _brush_strength * _last_brush_action);
_dirty = true;
updateGL();
break; break;
default: default:
; return;
} }
}
else if (event->buttons() & Qt::MiddleButton)
{
// Rotate around the turntable
_angle_h -= (double)move_x * 0.008;
_angle_v += (double)move_y * 0.003;
_dirty = true;
updateGL(); 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::initializeGL() void WidgetHeightMap::initializeGL()
@ -230,6 +237,26 @@ void WidgetHeightMap::paintGL()
_dirty = false; _dirty = false;
} }
// Picking mouse position using z-buffer (for brush)
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)_last_mouse_x;
winY = (float)height() - (float)_last_mouse_y;
glReadPixels(_last_mouse_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;
// Place camera // Place camera
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();

View file

@ -29,15 +29,18 @@ public:
void setBrushMode(HeightMapBrushMode mode); void setBrushMode(HeightMapBrushMode mode);
void setBrushSize(double size); void setBrushSize(double size);
void setBrushSmoothing(double smoothing); void setBrushSmoothing(double smoothing);
void setBrushStrength(double smoothing);
public slots: public slots:
void revert();
void resetToTerrain(); void resetToTerrain();
protected: protected:
void keyPressEvent(QKeyEvent* event);
void mousePressEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent* event);
void timerEvent(QTimerEvent* event);
void initializeGL(); void initializeGL();
void resizeGL(int w, int h); void resizeGL(int w, int h);
@ -54,6 +57,7 @@ private:
double _average_frame_time; double _average_frame_time;
int _last_brush_action;
int _last_mouse_x; int _last_mouse_x;
int _last_mouse_y; int _last_mouse_y;
@ -65,6 +69,7 @@ private:
HeightMapBrushMode _brush_mode; HeightMapBrushMode _brush_mode;
double _brush_size; double _brush_size;
double _brush_smoothing; double _brush_smoothing;
double _brush_strength;
}; };
#endif #endif

View file

@ -50,6 +50,7 @@ void heightmapLoad(PackStream* stream, HeightMap* heightmap)
packReadInt(stream, &heightmap->resolution_x); packReadInt(stream, &heightmap->resolution_x);
packReadInt(stream, &heightmap->resolution_z); packReadInt(stream, &heightmap->resolution_z);
heightmap->data = realloc(heightmap->data, sizeof(double) * heightmap->resolution_x * heightmap->resolution_z);
for (i = 0; i < heightmap->resolution_x * heightmap->resolution_z; i++) for (i = 0; i < heightmap->resolution_x * heightmap->resolution_z; i++)
{ {
packReadDouble(stream, &heightmap->data[i]); packReadDouble(stream, &heightmap->data[i]);
@ -70,6 +71,12 @@ void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resol
} }
} }
double heightmapGetValue(HeightMap* heightmap, double x, double z)
{
// TODO Bicubic interpolation
return heightmap->data[lround(z * (heightmap->resolution_z - 1)) * heightmap->resolution_x + lround(x * (heightmap->resolution_x - 1))];
}
void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value)
{ {
int x, z; int x, z;
@ -89,7 +96,7 @@ void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double
{ {
if (distance <= brush->hard_radius + brush->smoothed_size) if (distance <= brush->hard_radius + brush->smoothed_size)
{ {
heightmap->data[z * heightmap->resolution_x +x] += value * (distance - brush->hard_radius) / brush->smoothed_size; heightmap->data[z * heightmap->resolution_x +x] += value * (1.0 - (distance - brush->hard_radius) / brush->smoothed_size);
} }
} }
else else

View file

@ -33,6 +33,7 @@ void heightmapSave(PackStream* stream, HeightMap* heightmap);
void heightmapLoad(PackStream* stream, HeightMap* heightmap); void heightmapLoad(PackStream* stream, HeightMap* heightmap);
void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resolution_z); void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resolution_z);
double heightmapGetValue(HeightMap* heightmap, double x, double z);
void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value); void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value);

View file

@ -19,7 +19,7 @@ void terrainSave(PackStream* stream, TerrainDefinition* definition)
noiseSaveGenerator(stream, definition->height_noise); noiseSaveGenerator(stream, definition->height_noise);
packWriteDouble(stream, &definition->height_factor); packWriteDouble(stream, &definition->height_factor);
packWriteDouble(stream, &definition->scaling); packWriteDouble(stream, &definition->scaling);
layersSave(stream, &definition->canvases); layersSave(stream, definition->canvases);
packWriteDouble(stream, &definition->shadow_smoothing); packWriteDouble(stream, &definition->shadow_smoothing);
} }
@ -28,7 +28,7 @@ void terrainLoad(PackStream* stream, TerrainDefinition* definition)
noiseLoadGenerator(stream, definition->height_noise); noiseLoadGenerator(stream, definition->height_noise);
packReadDouble(stream, &definition->height_factor); packReadDouble(stream, &definition->height_factor);
packReadDouble(stream, &definition->scaling); packReadDouble(stream, &definition->scaling);
layersLoad(stream, &definition->canvases); layersLoad(stream, definition->canvases);
packReadDouble(stream, &definition->shadow_smoothing); packReadDouble(stream, &definition->shadow_smoothing);
terrainValidateDefinition(definition); terrainValidateDefinition(definition);
@ -81,28 +81,44 @@ void terrainValidateDefinition(TerrainDefinition* definition)
static inline double _getHeight(TerrainDefinition* definition, double x, double z) static inline double _getHeight(TerrainDefinition* definition, double x, double z)
{ {
TerrainCanvas* canvas;
Vector3 location; Vector3 location;
int i; int i, n;
location.x = x; location.x = x;
location.y = noiseGet2DTotal(definition->height_noise, x / definition->scaling, z / definition->scaling) * definition->height_factor; location.y = noiseGet2DTotal(definition->height_noise, x / definition->scaling, z / definition->scaling) * definition->height_factor;
location.z = z; location.z = z;
n = layersCount(definition->canvases);
for (i = 0; i < n; i++)
{
canvas = layersGetLayer(definition->canvases, i);
location = terrainCanvasApply(canvas, location);
}
/* TODO Apply canvases and modifiers */ /* TODO Apply modifiers */
return location.y; return location.y;
} }
static inline double _getHeightDetail(TerrainDefinition* definition, double x, double z, double detail) static inline double _getHeightDetail(TerrainDefinition* definition, double x, double z, double detail)
{ {
TerrainCanvas* canvas;
Vector3 location; Vector3 location;
int i; int i, n;
location.x = x; location.x = x;
location.y = noiseGet2DDetail(definition->height_noise, x / definition->scaling, z / definition->scaling, detail / definition->height_factor) * definition->height_factor; location.y = noiseGet2DDetail(definition->height_noise, x / definition->scaling, z / definition->scaling, detail / definition->height_factor) * definition->height_factor;
location.z = z; location.z = z;
/* TODO Apply canvases and modifiers */ n = layersCount(definition->canvases);
for (i = 0; i < n; i++)
{
canvas = layersGetLayer(definition->canvases, i);
location = terrainCanvasApply(canvas, location);
}
/* TODO Apply modifiers */
return location.y; return location.y;
} }

View file

@ -8,10 +8,10 @@ TerrainCanvas* terrainCanvasCreate()
TerrainCanvas* result = malloc(sizeof(TerrainCanvas)); TerrainCanvas* result = malloc(sizeof(TerrainCanvas));
result->area.bounded = 1; result->area.bounded = 1;
result->area.location_x = 0.0; result->area.location_x = -40.0;
result->area.location_z = 0.0; result->area.location_z = -40.0;
result->area.size_x = 1.0; result->area.size_x = 80.0;
result->area.size_z = 1.0; result->area.size_z = 80.0;
result->offset_z = 0.0; result->offset_z = 0.0;
result->height_map = heightmapCreate(); result->height_map = heightmapCreate();
heightmapChangeResolution(&result->height_map, 256, 256); heightmapChangeResolution(&result->height_map, 256, 256);
@ -107,6 +107,14 @@ void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terr
{ {
} }
Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 position) Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 location)
{ {
if (location.x >= canvas->area.location_x &&
location.z >= canvas->area.location_z &&
location.x <= canvas->area.location_x + canvas->area.size_x &&
location.z <= canvas->area.location_z + canvas->area.size_z)
{
location.y = heightmapGetValue(&canvas->height_map, (location.x - canvas->area.location_x) / canvas->area.size_x, (location.z - canvas->area.location_z) / canvas->area.size_z);
}
return location;
} }

View file

@ -48,7 +48,7 @@ void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas);
void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas); void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas);
void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked); void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked);
Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 position); Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 location);
#ifdef __cplusplus #ifdef __cplusplus
} }