From 2d2535deae529b8db835f37d8ea143543c9bcb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Wed, 18 Jul 2012 15:04:23 +0000 Subject: [PATCH] paysages : Terrain canvas - Added bicubic interpolation and integration mask. git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@393 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- gui_qt/formterraincanvas.cpp | 4 +-- lib_paysages/heightmap.c | 25 +++++++++++++++--- lib_paysages/terraincanvas.c | 49 +++++++++++++++++++++++++++++------- lib_paysages/terraincanvas.h | 13 +++++++--- 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/gui_qt/formterraincanvas.cpp b/gui_qt/formterraincanvas.cpp index 6851e49..c925f71 100644 --- a/gui_qt/formterraincanvas.cpp +++ b/gui_qt/formterraincanvas.cpp @@ -13,8 +13,8 @@ FormTerrainCanvas::FormTerrainCanvas(QWidget *parent, Layers* layers): addInputNoise(tr("Detail noise"), _definition->detail_noise); addInputDouble(tr("Detail noise height"), &_definition->detail_height_factor, 0.0, 20.0, 0.1, 1.0); addInputDouble(tr("Detail noise scaling"), &_definition->detail_scaling, 0.0, 20.0, 0.1, 1.0); - addInputEnum(tr("Mask shape"), &_definition->mask_mode, QStringList(tr("Square")) << tr("Circle")); - addInputDouble(tr("Mask smoothing"), &_definition->mask_smoothing, 0.0, 1.0, 0.01, 0.1); + addInputEnum(tr("Mask shape"), &_definition->mask.mode, QStringList(tr("Square")) << tr("Circle")); + addInputDouble(tr("Mask smoothing"), &_definition->mask.smoothing, 0.0, 1.0, 0.01, 0.1); revertConfig(); } diff --git a/lib_paysages/heightmap.c b/lib_paysages/heightmap.c index 24bd555..1b93922 100644 --- a/lib_paysages/heightmap.c +++ b/lib_paysages/heightmap.c @@ -1,4 +1,5 @@ #include "heightmap.h" +#include "tools.h" #include #include @@ -73,8 +74,26 @@ 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))]; + int xmax = heightmap->resolution_x - 1; + int zmax = heightmap->resolution_z - 1; + int xlow = floor(x * xmax); + int zlow = floor(z * zmax); + double stencil[16]; + int ix, iz, cx, cz; + + for (ix = xlow - 1; ix <= xlow + 2; ix++) + { + for (iz = zlow - 1; iz <= zlow + 2; iz++) + { + cx = ix < 0 ? 0 : ix; + cx = cx > xmax ? xmax : cx; + cz = iz < 0 ? 0 : iz; + cz = cz > zmax ? zmax : cz; + stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = heightmap->data[cz * heightmap->resolution_x + cx]; + } + } + + return toolsBicubicInterpolate(stencil, x * xmax - (double)xlow, z * zmax - (double)zlow); } void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) @@ -82,7 +101,7 @@ void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double int x, z; double dx, dz, distance; - // TODO Limit to brush radius + /* TODO Limit to brush radius */ for (x = 0; x < heightmap->resolution_x; x++) { diff --git a/lib_paysages/terraincanvas.c b/lib_paysages/terraincanvas.c index 47f5528..0f27bb2 100644 --- a/lib_paysages/terraincanvas.c +++ b/lib_paysages/terraincanvas.c @@ -19,8 +19,8 @@ TerrainCanvas* terrainCanvasCreate() result->detail_noise = noiseCreateGenerator(); result->detail_height_factor = 0.1; result->detail_scaling = 1.0; - result->mask_mode = TERRAINCANVAS_MASKMODE_SQUARE; - result->mask_smoothing = 0.0; + result->mask.mode = INTEGRATIONMASK_MODE_CIRCLE; + result->mask.smoothing = 0.1; return result; } @@ -41,8 +41,7 @@ void terrainCanvasCopy(TerrainCanvas* source, TerrainCanvas* destination) noiseCopy(source->detail_noise, destination->detail_noise); destination->detail_height_factor = source->detail_height_factor; destination->detail_scaling = source->detail_scaling; - destination->mask_mode = source->mask_mode; - destination->mask_smoothing = source->mask_smoothing; + destination->mask = source->mask; } void terrainCanvasValidate(TerrainCanvas* canvas) @@ -82,8 +81,8 @@ void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas) noiseSaveGenerator(stream, canvas->detail_noise); packWriteDouble(stream, &canvas->detail_height_factor); packWriteDouble(stream, &canvas->detail_scaling); - packWriteInt(stream, &canvas->mask_mode); - packWriteDouble(stream, &canvas->mask_smoothing); + packWriteInt(stream, &canvas->mask.mode); + packWriteDouble(stream, &canvas->mask.smoothing); } void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas) @@ -99,8 +98,8 @@ void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas) noiseLoadGenerator(stream, canvas->detail_noise); packReadDouble(stream, &canvas->detail_height_factor); packReadDouble(stream, &canvas->detail_scaling); - packReadInt(stream, &canvas->mask_mode); - packReadDouble(stream, &canvas->mask_smoothing); + packReadInt(stream, &canvas->mask.mode); + packReadDouble(stream, &canvas->mask.smoothing); } void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked) @@ -114,7 +113,39 @@ Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 location) 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); + double inside_x, inside_z; + double height, distance; + + /* Get height map displacement */ + inside_x = (location.x - canvas->area.location_x) / canvas->area.size_x; + inside_z = (location.z - canvas->area.location_z) / canvas->area.size_z; + height = heightmapGetValue(&canvas->height_map, inside_x, inside_z); + + /* TODO Apply detail noise */ + + /* Apply integration mask */ + inside_x = (inside_x - 0.5) * 2.0; + inside_z = (inside_z - 0.5) * 2.0; + if (canvas->mask.mode == INTEGRATIONMASK_MODE_SQUARE) + { + inside_x = fabs(inside_x); + inside_z = fabs(inside_z); + distance = inside_x > inside_z ? inside_x : inside_z; + } + else + { + distance = sqrt(inside_x * inside_x + inside_z * inside_z); + } + if (distance <= 1.0 - canvas->mask.smoothing) + { + location.y = height; + } + else + { + double influence = (1.0 - distance) / canvas->mask.smoothing; + location.y = influence * height + (1.0 - influence) * location.y; + } + } return location; } diff --git a/lib_paysages/terraincanvas.h b/lib_paysages/terraincanvas.h index 8435827..9d44d75 100644 --- a/lib_paysages/terraincanvas.h +++ b/lib_paysages/terraincanvas.h @@ -22,8 +22,14 @@ typedef struct double size_z; } GeoArea; -#define TERRAINCANVAS_MASKMODE_SQUARE 0 -#define TERRAINCANVAS_MASKMODE_CIRCLE 1 +typedef struct +{ + int mode; + double smoothing; +} IntegrationMask; + +#define INTEGRATIONMASK_MODE_SQUARE 0 +#define INTEGRATIONMASK_MODE_CIRCLE 1 typedef struct { @@ -34,8 +40,7 @@ typedef struct NoiseGenerator* detail_noise; double detail_height_factor; double detail_scaling; - int mask_mode; - double mask_smoothing; + IntegrationMask mask; } TerrainCanvas; TerrainCanvas* terrainCanvasCreate();