paysages : Terrain painting improvements (WIP).

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@553 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2013-04-19 21:51:17 +00:00 committed by ThunderK
parent ae19273d18
commit 306a3fdd0b
5 changed files with 158 additions and 79 deletions

View file

@ -2,13 +2,12 @@
#include <QTime>
#include <QMouseEvent>
#include <QWidget>
#include <math.h>
#include <GL/glu.h>
#include <qt4/QtGui/qwidget.h>
#include "tools.h"
#define HEIGHTMAP_RESOLUTION 256
#define CAMERA_DISTANCE 200.0
WidgetHeightMap::WidgetHeightMap(QWidget *parent, TerrainDefinition* terrain):
QGLWidget(parent)
@ -39,7 +38,8 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, TerrainDefinition* terrain):
_position_x = 0;
_position_z = 0;
_angle_h = 0.0;
_angle_v = 0.8;
_angle_v = 1.4;
_distance = 100.0;
_brush_x = 0.0;
_brush_z = 0.0;
@ -365,7 +365,7 @@ void WidgetHeightMap::paintGL()
// Place camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(CAMERA_DISTANCE * cos(_angle_h) * cos(_angle_v), CAMERA_DISTANCE * sin(_angle_v), -CAMERA_DISTANCE * sin(_angle_h) * cos(_angle_v), 0.0, 0.0, 0.0, -cos(_angle_h) * sin(_angle_v), cos(_angle_v), sin(_angle_h) * sin(_angle_v));
gluLookAt(_distance * cos(_angle_h) * cos(_angle_v), _distance * sin(_angle_v), -_distance * sin(_angle_h) * cos(_angle_v), 0.0, 0.0, 0.0, -cos(_angle_h) * sin(_angle_v), cos(_angle_v), sin(_angle_h) * sin(_angle_v));
// Place lights
GLfloat light_position[] = { 40.0, 40.0, 40.0, 0.0 };

View file

@ -77,6 +77,7 @@ private:
int _position_z;
double _angle_h;
double _angle_v;
double _distance;
double _brush_x;
double _brush_z;

View file

@ -375,7 +375,7 @@ double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int wit
{
double height;
if (!with_painting || !terrainHeightmapGetHeight(definition->height_map, (double)x, (double)z, &height))
if (!with_painting || !terrainHeightmapGetGridHeight(definition->height_map, x, z, &height))
{
height = noiseGet2DTotal(definition->_height_noise, (double)x, (double)z);
}
@ -389,7 +389,7 @@ double terrainGetInterpolatedHeight(TerrainDefinition* definition, double x, dou
x /= definition->scaling;
z /= definition->scaling;
if (!with_painting || !terrainHeightmapGetHeight(definition->height_map, x, z, &height))
if (!with_painting || !terrainHeightmapGetInterpolatedHeight(definition->height_map, x, z, &height))
{
height = noiseGet2DTotal(definition->_height_noise, x, z);
}

View file

@ -22,7 +22,6 @@ typedef struct
typedef struct
{
int z;
int memsize;
int pixel_groups_count;
HeightMapPixelGroup* pixel_groups;
} HeightMapRow;
@ -45,6 +44,7 @@ static void _initData(HeightMapData* data)
{
data->rows_count = 0;
data->rows = malloc(1);
data->memsize = 0;
}
static void _clearData(HeightMapData* data)
@ -60,6 +60,7 @@ static void _clearData(HeightMapData* data)
}
data->rows_count = 0;
data->rows = realloc(data->rows, 1);
data->memsize = 0;
}
static void _deleteData(HeightMapData* data)
@ -70,9 +71,36 @@ static void _deleteData(HeightMapData* data)
static void _copyData(HeightMapData* source, HeightMapData* destination)
{
int i, j, n;
size_t size;
_clearData(destination);
/* TODO */
destination->rows_count = source->rows_count;
if (destination->rows_count > 0)
{
size = sizeof(HeightMapRow) * destination->rows_count;
destination->rows = realloc(destination->rows, size);
destination->memsize += size;
for (i = 0; i < destination->rows_count; i++)
{
destination->rows[i].z = source->rows[i].z;
destination->rows[i].pixel_groups_count = source->rows[i].pixel_groups_count;
size = sizeof(HeightMapPixelGroup) * destination->rows[i].pixel_groups_count;
destination->rows[i].pixel_groups = malloc(size);
destination->memsize += size;
for (j = 0; j < destination->rows[i].pixel_groups_count; j++)
{
destination->rows[i].pixel_groups[j].xstart = source->rows[i].pixel_groups[j].xstart;
destination->rows[i].pixel_groups[j].xend = source->rows[i].pixel_groups[j].xend;
n = destination->rows[i].pixel_groups[j].xend - destination->rows[i].pixel_groups[j].xstart;
size = sizeof(double) * n;
destination->rows[i].pixel_groups[j].height = malloc(size);
destination->memsize += size;
memcpy(destination->rows[i].pixel_groups[j].height, source->rows[i].pixel_groups[j].height, size);
}
}
}
}
static void _saveData(PackStream* stream, HeightMapData* data)
@ -98,25 +126,35 @@ static void _saveData(PackStream* stream, HeightMapData* data)
static void _loadData(PackStream* stream, HeightMapData* data)
{
int i, j, k, n;
size_t size;
_clearData(data);
packReadInt(stream, &data->rows_count);
data->rows = realloc(data->rows, sizeof(HeightMapRow) * data->rows_count);
for (i = 0; i < data->rows_count; i++)
if (data->rows_count > 0)
{
packReadInt(stream, &data->rows[i].z);
packReadInt(stream, &data->rows[i].pixel_groups_count);
data->rows[i].pixel_groups = malloc(sizeof(HeightMapPixelGroup) * data->rows[i].pixel_groups_count);
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
size = sizeof(HeightMapRow) * data->rows_count;
data->rows = realloc(data->rows, size);
data->memsize += size;
for (i = 0; i < data->rows_count; i++)
{
packReadInt(stream, &data->rows[i].pixel_groups[j].xstart);
packReadInt(stream, &data->rows[i].pixel_groups[j].xend);
n = data->rows[i].pixel_groups[j].xend - data->rows[i].pixel_groups[j].xstart;
data->rows[i].pixel_groups[j].height = malloc(sizeof(double) * n);
for (k = 0; k < n; k++)
packReadInt(stream, &data->rows[i].z);
packReadInt(stream, &data->rows[i].pixel_groups_count);
size = sizeof(HeightMapPixelGroup) * data->rows[i].pixel_groups_count;
data->rows[i].pixel_groups = malloc(size);
data->memsize += size;
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
{
packReadDouble(stream, &data->rows[i].pixel_groups[j].height[k]);
packReadInt(stream, &data->rows[i].pixel_groups[j].xstart);
packReadInt(stream, &data->rows[i].pixel_groups[j].xend);
n = data->rows[i].pixel_groups[j].xend - data->rows[i].pixel_groups[j].xstart;
size = sizeof(double) * n;
data->rows[i].pixel_groups[j].height = malloc(size);
data->memsize += size;
for (k = 0; k < n; k++)
{
packReadDouble(stream, &data->rows[i].pixel_groups[j].height[k]);
}
}
}
}
@ -127,7 +165,7 @@ static void _loadData(PackStream* stream, HeightMapData* data)
* If the location is not already in the heightmap, it is initialized with the terrain height.
* This method will grow the heightmap as necessary (if 'grow' is set to false, NULL will be returned on missing pixels).
*/
static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinition* terrain, int grow)
static double* _getDataPointer(HeightMapData* data, int x, int z, HeightMapData* fallback, TerrainDefinition* terrain, int grow)
{
int i;
@ -152,6 +190,7 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
row->pixel_groups = malloc(1);
data->rows_count++;
data->memsize += sizeof(HeightMapRow);
}
else
{
@ -192,6 +231,7 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
pixel = pixel_group->height;
row->pixel_groups_count++;
data->memsize += sizeof(HeightMapPixelGroup) + sizeof(double);
}
else if (x == pixel_group->xstart - 1)
{
@ -203,6 +243,7 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
/* Extend the rowgroup at start */
pixel_group->xstart--;
pixel = naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, 0);
data->memsize += sizeof(double);
}
else if (x == pixel_group->xend + 1)
{
@ -214,6 +255,7 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
/* Extend the rowgroup at end */
pixel_group->xend++;
pixel = naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, pixel_group->xend - pixel_group->xstart);
data->memsize += sizeof(double);
}
else
{
@ -224,9 +266,24 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
}
/* Reset pixel if it had been added */
if (added && terrain)
if (added && (terrain || fallback))
{
*pixel = terrainGetGridHeight(terrain, x, z, 0);
if (fallback)
{
double* dpointer = _getDataPointer(fallback, x, z, NULL, terrain, 0);
if (dpointer)
{
*pixel = *dpointer;
}
else
{
*pixel = terrainGetGridHeight(terrain, x, z, 0);
}
}
else
{
*pixel = terrainGetGridHeight(terrain, x, z, 0);
}
}
return pixel;
}
@ -269,53 +326,71 @@ void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap)
_clearData(&heightmap->brush_data);
}
static inline int _getInterpolatedValue(HeightMapData* data, double x, double z, double* result, TerrainDefinition* terrain)
int terrainHeightmapGetGridHeight(TerrainHeightMap* heightmap, int x, int z, double* result)
{
/*if ((int)floor(x) >= chunk->rect.xstart && (int)floor(x) <= chunk->rect.xend && (int)floor(z) >= (double)chunk->rect.zstart && (int)floor(z) <= (double)chunk->rect.zend)
double* dpointer;
dpointer = _getDataPointer(&heightmap->brush_data, x, z, NULL, NULL, 0);
if (dpointer)
{
double stencil[16];
int ix, iz, cx, cz;
int xmax = chunk->rect.xsize - 1;
int zmax = chunk->rect.zsize - 1;
int xlow;
int zlow;
x -= chunk->rect.xstart;
z -= chunk->rect.zstart;
xlow = floor(x);
zlow = floor(z);
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)] = chunk->data[cz * chunk->rect.xsize + cx];
}
}
if (result)
{
*result = toolsBicubicInterpolate(stencil, x - (double)xlow, z - (double)zlow);
}
*result = *dpointer;
return 1;
}
else
{
return 0;
}*/
return 0;
dpointer = _getDataPointer(&heightmap->merged_data, x, z, NULL, NULL, 0);
if (dpointer)
{
*result = *dpointer;
return 1;
}
else
{
return 0;
}
}
}
int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result)
int terrainHeightmapGetInterpolatedHeight(TerrainHeightMap* heightmap, double x, double z, double* result)
{
/* TODO */
return 0;
int ix, iz;
int xlow;
int zlow;
xlow = floor(x);
zlow = floor(z);
int hit = 0;
for (ix = xlow - 1; ix <= xlow + 2 && !hit; ix++)
{
for (iz = zlow - 1; iz <= zlow + 2 && !hit; iz++)
{
if (_getDataPointer(&heightmap->brush_data, x, z, NULL, NULL, 0) || _getDataPointer(&heightmap->merged_data, x, z, NULL, NULL, 0))
{
hit = 1;
}
}
}
if (hit && result)
{
double stencil[16];
double value;
for (ix = xlow - 1; ix <= xlow + 2; ix++)
{
for (iz = zlow - 1; iz <= zlow + 2; iz++)
{
if (!terrainHeightmapGetGridHeight(heightmap, ix, iz, &value))
{
value = terrainGetGridHeight(heightmap->terrain, ix, iz, 0);
}
stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = value;
}
}
*result = toolsBicubicInterpolate(stencil, x - (double)xlow, z - (double)zlow);
}
return hit;
}
static inline IntegerRect _getBrushRect(TerrainBrush* brush)
@ -341,25 +416,12 @@ static inline int _isInRect(IntegerRect rect, int x, int z)
size_t terrainGetMemoryStats(TerrainDefinition* definition)
{
TerrainHeightMap* heightmap = definition->height_map;
size_t result = 0;
int i;
/*if (heightmap->floating_used)
{
result += sizeof(double) * heightmap->floating_data.rect.xsize * heightmap->floating_data.rect.zsize;
}
for (i = 0; i < heightmap->fixed_count; i++)
{
result += sizeof(double) * heightmap->fixed_data[i].rect.xsize * heightmap->fixed_data[i].rect.zsize;
}*/
return result;
return definition->height_map->merged_data.memsize + definition->height_map->brush_data.memsize;
}
int terrainIsPainted(TerrainHeightMap* heightmap, int x, int z)
{
return _getDataPointer(&heightmap->brush_data, x, z, NULL, 0) || _getDataPointer(&heightmap->merged_data, x, z, NULL, 0);
return _getDataPointer(&heightmap->brush_data, x, z, NULL, NULL, 0) || _getDataPointer(&heightmap->merged_data, x, z, NULL, NULL, 0);
}
typedef double (*BrushCallback)(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data);
@ -394,7 +456,7 @@ static inline void _applyBrush(TerrainHeightMap* heightmap, TerrainBrush* brush,
influence = 1.0;
}
double* dpointer = _getDataPointer(&heightmap->brush_data, x, z, heightmap->terrain, 1);
double* dpointer = _getDataPointer(&heightmap->brush_data, x, z, &heightmap->merged_data, heightmap->terrain, 1);
*dpointer = callback(heightmap, brush, dx, dz, *dpointer, influence, force, data);
}
}
@ -467,5 +529,20 @@ void terrainBrushReset(TerrainHeightMap* heightmap, TerrainBrush* brush, double
void terrainEndBrushStroke(TerrainHeightMap* heightmap)
{
/* TODO Merge data */
int i, j, k;
HeightMapData* data = &heightmap->brush_data;
for (i = 0; i < data->rows_count; i++)
{
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
{
for (k = 0; k < data->rows[i].pixel_groups[j].xend - data->rows[i].pixel_groups[j].xstart; k++)
{
double* dpointer = _getDataPointer(&heightmap->merged_data, data->rows[i].pixel_groups[j].xstart + k, data->rows[i].z, NULL, NULL, 1);
*dpointer = data->rows[i].pixel_groups[j].height[k];
}
}
}
_clearData(&heightmap->brush_data);
}

View file

@ -18,6 +18,7 @@ void terrainHeightmapDelete(TerrainHeightMap* heightmap);
void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination);
void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap);
void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap);
int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result);
int terrainHeightmapGetInterpolatedHeight(TerrainHeightMap* heightmap, double x, double z, double* result);
int terrainHeightmapGetGridHeight(TerrainHeightMap* heightmap, int x, int z, double* result);
#endif