From 0ab0bd9475a71026a2058f250db242c2667eaf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Thu, 26 Jul 2012 11:55:19 +0000 Subject: [PATCH] paysages : Heightmap painting - Added smooth brush. git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@400 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- gui_qt/dialogheightmap.cpp | 6 +-- gui_qt/widgetheightmap.cpp | 5 ++- lib_paysages/heightmap.c | 88 +++++++++++++++++++++----------------- lib_paysages/heightmap.h | 1 + 4 files changed, 55 insertions(+), 45 deletions(-) diff --git a/gui_qt/dialogheightmap.cpp b/gui_qt/dialogheightmap.cpp index e69ee7a..b16f90f 100644 --- a/gui_qt/dialogheightmap.cpp +++ b/gui_qt/dialogheightmap.cpp @@ -68,7 +68,7 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog combobox = new QComboBox(panel); combobox->addItem(tr("Raise / lower")); - combobox->addItem(tr("Smooth / add noise")); + combobox->addItem(tr("Add noise / smooth")); connect(combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(brushModeChanged(int))); panel->layout()->addWidget(combobox); @@ -76,10 +76,10 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog panel->layout()->addWidget(label); slider = new QSlider(Qt::Horizontal, panel); - slider->setRange(6, 150); + slider->setRange(6, 300); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushSizeChanged(int))); panel->layout()->addWidget(slider); - slider->setValue(30); + slider->setValue(60); label = new QLabel(tr("Brush smoothing"), panel); panel->layout()->addWidget(label); diff --git a/gui_qt/widgetheightmap.cpp b/gui_qt/widgetheightmap.cpp index 5fac744..50fee3e 100644 --- a/gui_qt/widgetheightmap.cpp +++ b/gui_qt/widgetheightmap.cpp @@ -176,13 +176,14 @@ void WidgetHeightMap::timerEvent(QTimerEvent*) brush.relative_z = (_brush_z + 40.0) / 80.0; brush.hard_radius = _brush_size * (1.0 - _brush_smoothing) / 80.0; brush.smoothed_size = _brush_size * _brush_smoothing / 80.0; + brush.total_radius = brush.hard_radius + brush.smoothed_size; 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 * 20.0); break; case HEIGHTMAP_BRUSH_SMOOTH: if (_last_brush_action < 0) @@ -191,7 +192,7 @@ void WidgetHeightMap::timerEvent(QTimerEvent*) } else { - heightmapBrushAddNoise(_heightmap, &brush, _brush_noise, brush_strength); + heightmapBrushAddNoise(_heightmap, &brush, _brush_noise, brush_strength * 10.0); } break; default: diff --git a/lib_paysages/heightmap.c b/lib_paysages/heightmap.c index 93ff6ec..47b0767 100644 --- a/lib_paysages/heightmap.c +++ b/lib_paysages/heightmap.c @@ -170,45 +170,12 @@ static inline void _getBrushBoundaries(HeightMapBrush* brush, int rx, int rz, in } } -void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) +typedef double (*BrushCallback)(HeightMap* heightmap, HeightMapBrush* brush, double x, double z, double basevalue, double influence, double force, void* data); + +static inline void _applyBrush(HeightMap* heightmap, HeightMapBrush* brush, double force, void* data, BrushCallback callback) { int x, x1, x2, z, z1, z2; - double dx, dz, distance; - - _getBrushBoundaries(brush, heightmap->resolution_x - 1, heightmap->resolution_z - 1, &x1, &x2, &z1, &z2); - - 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) - { - 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; - } - } - } -} - -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; + double dx, dz, distance, influence, brush_size; _getBrushBoundaries(brush, heightmap->resolution_x - 1, heightmap->resolution_z - 1, &x1, &x2, &z1, &z2); brush_size = brush->hard_radius + brush->smoothed_size; @@ -225,7 +192,7 @@ void heightmapBrushAddNoise(HeightMap* heightmap, HeightMapBrush* brush, NoiseGe { if (distance <= brush->hard_radius + brush->smoothed_size) { - factor = (1.0 - (distance - brush->hard_radius) / brush->smoothed_size); + influence = (1.0 - (distance - brush->hard_radius) / brush->smoothed_size); } else { @@ -234,10 +201,51 @@ void heightmapBrushAddNoise(HeightMap* heightmap, HeightMapBrush* brush, NoiseGe } else { - factor = 1.0; + influence = 1.0; } - heightmap->data[z * heightmap->resolution_x + x] += factor * noiseGet2DTotal(generator, dx / brush_size, dz / brush_size) * brush_size; + heightmap->data[z * heightmap->resolution_x + x] = callback(heightmap, brush, dx, dz, heightmap->data[z * heightmap->resolution_x + x], influence, force, data); } } } + +static double _applyBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double x, double z, double basevalue, double influence, double force, void* data) +{ + return basevalue + influence * force * brush->total_radius; +} + +void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) +{ + _applyBrush(heightmap, brush, value, NULL, _applyBrushElevation); +} + +static double _applyBrushSmooth(HeightMap* heightmap, HeightMapBrush* brush, double x, double z, double basevalue, double influence, double force, void* data) +{ + double ideal, factor; + ideal = heightmapGetValue(heightmap, x + brush->total_radius * 0.5, z); + ideal += heightmapGetValue(heightmap, x - brush->total_radius * 0.5, z); + ideal += heightmapGetValue(heightmap, x, z - brush->total_radius * 0.5); + ideal += heightmapGetValue(heightmap, x, z + brush->total_radius * 0.5); + ideal /= 4.0; + factor = influence * force; + if (factor > 1.0) + { + factor = 0.0; + } + return basevalue + (ideal - basevalue) * factor; +} + +void heightmapBrushSmooth(HeightMap* heightmap, HeightMapBrush* brush, double value) +{ + _applyBrush(heightmap, brush, value, NULL, _applyBrushSmooth); +} + +static double _applyBrushAddNoise(HeightMap* heightmap, HeightMapBrush* brush, double x, double z, double basevalue, double influence, double force, void* data) +{ + return basevalue + noiseGet2DTotal((NoiseGenerator*)data, x / brush->total_radius, z / brush->total_radius) * influence * force * brush->total_radius; +} + +void heightmapBrushAddNoise(HeightMap* heightmap, HeightMapBrush* brush, NoiseGenerator* generator, double value) +{ + _applyBrush(heightmap, brush, value, generator, _applyBrushAddNoise); +} diff --git a/lib_paysages/heightmap.h b/lib_paysages/heightmap.h index 53e7d7d..23e070a 100644 --- a/lib_paysages/heightmap.h +++ b/lib_paysages/heightmap.h @@ -23,6 +23,7 @@ typedef struct double relative_z; double hard_radius; double smoothed_size; + double total_radius; } HeightMapBrush; HeightMap heightmapCreate();