From a16c5dd975a14883e3baf8dc7ecce4aa0dd7f441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Jul 2012 14:59:06 +0000 Subject: [PATCH] paysages : Heightmap painting - Added noise brush. git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@399 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- gui_qt/widgetheightmap.cpp | 30 ++++++++++++-- gui_qt/widgetheightmap.h | 3 ++ lib_paysages/heightmap.c | 84 +++++++++++++++++++++++++++++++++++--- lib_paysages/heightmap.h | 3 ++ 4 files changed, 111 insertions(+), 9 deletions(-) diff --git a/gui_qt/widgetheightmap.cpp b/gui_qt/widgetheightmap.cpp index 26fd766..5fac744 100644 --- a/gui_qt/widgetheightmap.cpp +++ b/gui_qt/widgetheightmap.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "tools.h" #include "../lib_paysages/terrain.h" #include "../lib_paysages/scenery.h" @@ -27,6 +28,7 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap): _last_brush_action = 0; _last_mouse_x = 0; _last_mouse_y = 0; + _last_time = QDateTime::currentDateTime(); _mouse_moved = false; _angle_h = 0.0; @@ -38,10 +40,14 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap): _brush_size = 10.0; _brush_smoothing = 0.5; _brush_strength = 1.0; + _brush_noise = noiseCreateGenerator(); + noiseGenerateBaseNoise(_brush_noise, 102400); + noiseAddLevelsSimple(_brush_noise, 6, 1.0, 1.0); } WidgetHeightMap::~WidgetHeightMap() { + noiseDeleteGenerator(_brush_noise); delete[] _vertexes; } @@ -155,10 +161,15 @@ void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event) updateGL(); } -void WidgetHeightMap::timerEvent(QTimerEvent* event) +void WidgetHeightMap::timerEvent(QTimerEvent*) { - if (_last_brush_action) + QDateTime new_time = QDateTime::currentDateTime(); + double duration = 0.001 * (double)_last_time.msecsTo(new_time); + _last_time = new_time; + + if (_last_brush_action != 0) { + double brush_strength; HeightMapBrush brush; brush.relative_x = (_brush_x + 40.0) / 80.0; @@ -166,15 +177,28 @@ void WidgetHeightMap::timerEvent(QTimerEvent* event) brush.hard_radius = _brush_size * (1.0 - _brush_smoothing) / 80.0; brush.smoothed_size = _brush_size * _brush_smoothing / 80.0; + brush_strength = _brush_strength * duration / 0.1; + switch (_brush_mode) { case HEIGHTMAP_BRUSH_RAISE: - heightmapBrushElevation(_heightmap, &brush, _brush_strength * _last_brush_action); + heightmapBrushElevation(_heightmap, &brush, brush_strength * _last_brush_action); + break; + case HEIGHTMAP_BRUSH_SMOOTH: + if (_last_brush_action < 0) + { + heightmapBrushSmooth(_heightmap, &brush, brush_strength); + } + else + { + heightmapBrushAddNoise(_heightmap, &brush, _brush_noise, brush_strength); + } break; default: return; } + // TODO Only mark dirty the updated area _dirty = true; updateGL(); } diff --git a/gui_qt/widgetheightmap.h b/gui_qt/widgetheightmap.h index 89879ab..a954eae 100644 --- a/gui_qt/widgetheightmap.h +++ b/gui_qt/widgetheightmap.h @@ -2,6 +2,7 @@ #define _PAYSAGES_QT_WIDGETHEIGHTMAP_H_ #include +#include #include "../lib_paysages/euclid.h" #include "../lib_paysages/heightmap.h" @@ -60,6 +61,7 @@ private: int _last_brush_action; int _last_mouse_x; int _last_mouse_y; + QDateTime _last_time; bool _mouse_moved; double _angle_h; @@ -71,6 +73,7 @@ private: double _brush_size; double _brush_smoothing; double _brush_strength; + NoiseGenerator* _brush_noise; }; #endif diff --git a/lib_paysages/heightmap.c b/lib_paysages/heightmap.c index 1a98c16..93ff6ec 100644 --- a/lib_paysages/heightmap.c +++ b/lib_paysages/heightmap.c @@ -1,6 +1,7 @@ #include "heightmap.h" #include "tools.h" #include "system.h" +#include "noise.h" #include #include @@ -140,17 +141,46 @@ double heightmapGetValue(HeightMap* heightmap, double x, double z) return toolsBicubicInterpolate(stencil, x * xmax - (double)xlow, z * zmax - (double)zlow); } +static inline void _getBrushBoundaries(HeightMapBrush* brush, int rx, int rz, int* x1, int* x2, int* z1, int* z2) +{ + double cx = brush->relative_x * rx; + double cz = brush->relative_z * rz; + double s = brush->smoothed_size + brush->hard_radius; + double sx = s * rx; + double sz = s * rz; + *x1 = (int)floor(cx - sx); + *x2 = (int)ceil(cx + sx); + *z1 = (int)floor(cz - sz); + *z2 = (int)ceil(cz + sz); + if (*x1 < 0) + { + *x1 = 0; + } + if (*x1 > rx) + { + *x1 = rx; + } + if (*z1 < 0) + { + *z1 = 0; + } + if (*z1 > rz) + { + *z1 = rz; + } +} + void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) { - int x, z; + int x, x1, x2, z, z1, z2; double dx, dz, distance; - /* TODO Limit to brush radius */ + _getBrushBoundaries(brush, heightmap->resolution_x - 1, heightmap->resolution_z - 1, &x1, &x2, &z1, &z2); - for (x = 0; x < heightmap->resolution_x; x++) + for (x = x1; x <= x2; x++) { dx = (double)x / (double)heightmap->resolution_x; - for (z = 0; z < heightmap->resolution_z; z++) + for (z = z1; z <= z2; z++) { dz = (double)z / (double)heightmap->resolution_z; distance = sqrt((brush->relative_x - dx) * (brush->relative_x - dx) + (brush->relative_z - dz) * (brush->relative_z - dz)); @@ -159,13 +189,55 @@ void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double { if (distance <= brush->hard_radius + brush->smoothed_size) { - heightmap->data[z * heightmap->resolution_x +x] += value * (1.0 - (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 { - heightmap->data[z * heightmap->resolution_x +x] += value; + heightmap->data[z * heightmap->resolution_x + x] += value; } } } } + +void heightmapBrushSmooth(HeightMap* heightmap, HeightMapBrush* brush, double value) +{ + /* TODO */ +} + +void heightmapBrushAddNoise(HeightMap* heightmap, HeightMapBrush* brush, NoiseGenerator* generator, double value) +{ + int x, x1, x2, z, z1, z2; + double dx, dz, distance, factor, brush_size; + + _getBrushBoundaries(brush, heightmap->resolution_x - 1, heightmap->resolution_z - 1, &x1, &x2, &z1, &z2); + brush_size = brush->hard_radius + brush->smoothed_size; + + for (x = x1; x <= x2; x++) + { + dx = (double)x / (double)heightmap->resolution_x; + for (z = z1; z <= z2; z++) + { + dz = (double)z / (double)heightmap->resolution_z; + distance = sqrt((brush->relative_x - dx) * (brush->relative_x - dx) + (brush->relative_z - dz) * (brush->relative_z - dz)); + + if (distance > brush->hard_radius) + { + if (distance <= brush->hard_radius + brush->smoothed_size) + { + factor = (1.0 - (distance - brush->hard_radius) / brush->smoothed_size); + } + else + { + continue; + } + } + else + { + factor = 1.0; + } + + heightmap->data[z * heightmap->resolution_x + x] += factor * noiseGet2DTotal(generator, dx / brush_size, dz / brush_size) * brush_size; + } + } +} diff --git a/lib_paysages/heightmap.h b/lib_paysages/heightmap.h index 2683119..53e7d7d 100644 --- a/lib_paysages/heightmap.h +++ b/lib_paysages/heightmap.h @@ -4,6 +4,7 @@ /* Height map for terrain */ #include "pack.h" +#include "noise.h" #ifdef __cplusplus extern "C" { @@ -40,6 +41,8 @@ void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resol void heightmapImportFromPicture(HeightMap* heightmap, const char* picturepath); void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value); +void heightmapBrushSmooth(HeightMap* heightmap, HeightMapBrush* brush, double value); +void heightmapBrushAddNoise(HeightMap* heightmap, HeightMapBrush* brush, NoiseGenerator* generator, double value); #ifdef __cplusplus }