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
This commit is contained in:
parent
818b8b7b86
commit
2d2535deae
4 changed files with 73 additions and 18 deletions
|
@ -13,8 +13,8 @@ FormTerrainCanvas::FormTerrainCanvas(QWidget *parent, Layers* layers):
|
||||||
addInputNoise(tr("Detail noise"), _definition->detail_noise);
|
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 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);
|
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"));
|
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);
|
addInputDouble(tr("Mask smoothing"), &_definition->mask.smoothing, 0.0, 1.0, 0.01, 0.1);
|
||||||
|
|
||||||
revertConfig();
|
revertConfig();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "heightmap.h"
|
#include "heightmap.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -73,8 +74,26 @@ void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resol
|
||||||
|
|
||||||
double heightmapGetValue(HeightMap* heightmap, double x, double z)
|
double heightmapGetValue(HeightMap* heightmap, double x, double z)
|
||||||
{
|
{
|
||||||
// TODO Bicubic interpolation
|
int xmax = heightmap->resolution_x - 1;
|
||||||
return heightmap->data[lround(z * (heightmap->resolution_z - 1)) * heightmap->resolution_x + lround(x * (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)
|
void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value)
|
||||||
|
@ -82,7 +101,7 @@ void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double
|
||||||
int x, z;
|
int x, z;
|
||||||
double dx, dz, distance;
|
double dx, dz, distance;
|
||||||
|
|
||||||
// TODO Limit to brush radius
|
/* TODO Limit to brush radius */
|
||||||
|
|
||||||
for (x = 0; x < heightmap->resolution_x; x++)
|
for (x = 0; x < heightmap->resolution_x; x++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,8 +19,8 @@ TerrainCanvas* terrainCanvasCreate()
|
||||||
result->detail_noise = noiseCreateGenerator();
|
result->detail_noise = noiseCreateGenerator();
|
||||||
result->detail_height_factor = 0.1;
|
result->detail_height_factor = 0.1;
|
||||||
result->detail_scaling = 1.0;
|
result->detail_scaling = 1.0;
|
||||||
result->mask_mode = TERRAINCANVAS_MASKMODE_SQUARE;
|
result->mask.mode = INTEGRATIONMASK_MODE_CIRCLE;
|
||||||
result->mask_smoothing = 0.0;
|
result->mask.smoothing = 0.1;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,7 @@ void terrainCanvasCopy(TerrainCanvas* source, TerrainCanvas* destination)
|
||||||
noiseCopy(source->detail_noise, destination->detail_noise);
|
noiseCopy(source->detail_noise, destination->detail_noise);
|
||||||
destination->detail_height_factor = source->detail_height_factor;
|
destination->detail_height_factor = source->detail_height_factor;
|
||||||
destination->detail_scaling = source->detail_scaling;
|
destination->detail_scaling = source->detail_scaling;
|
||||||
destination->mask_mode = source->mask_mode;
|
destination->mask = source->mask;
|
||||||
destination->mask_smoothing = source->mask_smoothing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainCanvasValidate(TerrainCanvas* canvas)
|
void terrainCanvasValidate(TerrainCanvas* canvas)
|
||||||
|
@ -82,8 +81,8 @@ void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas)
|
||||||
noiseSaveGenerator(stream, canvas->detail_noise);
|
noiseSaveGenerator(stream, canvas->detail_noise);
|
||||||
packWriteDouble(stream, &canvas->detail_height_factor);
|
packWriteDouble(stream, &canvas->detail_height_factor);
|
||||||
packWriteDouble(stream, &canvas->detail_scaling);
|
packWriteDouble(stream, &canvas->detail_scaling);
|
||||||
packWriteInt(stream, &canvas->mask_mode);
|
packWriteInt(stream, &canvas->mask.mode);
|
||||||
packWriteDouble(stream, &canvas->mask_smoothing);
|
packWriteDouble(stream, &canvas->mask.smoothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas)
|
void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas)
|
||||||
|
@ -99,8 +98,8 @@ void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas)
|
||||||
noiseLoadGenerator(stream, canvas->detail_noise);
|
noiseLoadGenerator(stream, canvas->detail_noise);
|
||||||
packReadDouble(stream, &canvas->detail_height_factor);
|
packReadDouble(stream, &canvas->detail_height_factor);
|
||||||
packReadDouble(stream, &canvas->detail_scaling);
|
packReadDouble(stream, &canvas->detail_scaling);
|
||||||
packReadInt(stream, &canvas->mask_mode);
|
packReadInt(stream, &canvas->mask.mode);
|
||||||
packReadDouble(stream, &canvas->mask_smoothing);
|
packReadDouble(stream, &canvas->mask.smoothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked)
|
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.x <= canvas->area.location_x + canvas->area.size_x &&
|
||||||
location.z <= canvas->area.location_z + canvas->area.size_z)
|
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;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,14 @@ typedef struct
|
||||||
double size_z;
|
double size_z;
|
||||||
} GeoArea;
|
} GeoArea;
|
||||||
|
|
||||||
#define TERRAINCANVAS_MASKMODE_SQUARE 0
|
typedef struct
|
||||||
#define TERRAINCANVAS_MASKMODE_CIRCLE 1
|
{
|
||||||
|
int mode;
|
||||||
|
double smoothing;
|
||||||
|
} IntegrationMask;
|
||||||
|
|
||||||
|
#define INTEGRATIONMASK_MODE_SQUARE 0
|
||||||
|
#define INTEGRATIONMASK_MODE_CIRCLE 1
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -34,8 +40,7 @@ typedef struct
|
||||||
NoiseGenerator* detail_noise;
|
NoiseGenerator* detail_noise;
|
||||||
double detail_height_factor;
|
double detail_height_factor;
|
||||||
double detail_scaling;
|
double detail_scaling;
|
||||||
int mask_mode;
|
IntegrationMask mask;
|
||||||
double mask_smoothing;
|
|
||||||
} TerrainCanvas;
|
} TerrainCanvas;
|
||||||
|
|
||||||
TerrainCanvas* terrainCanvasCreate();
|
TerrainCanvas* terrainCanvasCreate();
|
||||||
|
|
Loading…
Reference in a new issue