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

View file

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

View file

@ -375,7 +375,7 @@ double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int wit
{ {
double height; 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); height = noiseGet2DTotal(definition->_height_noise, (double)x, (double)z);
} }
@ -389,7 +389,7 @@ double terrainGetInterpolatedHeight(TerrainDefinition* definition, double x, dou
x /= definition->scaling; x /= definition->scaling;
z /= 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); height = noiseGet2DTotal(definition->_height_noise, x, z);
} }

View file

@ -22,7 +22,6 @@ typedef struct
typedef struct typedef struct
{ {
int z; int z;
int memsize;
int pixel_groups_count; int pixel_groups_count;
HeightMapPixelGroup* pixel_groups; HeightMapPixelGroup* pixel_groups;
} HeightMapRow; } HeightMapRow;
@ -45,6 +44,7 @@ static void _initData(HeightMapData* data)
{ {
data->rows_count = 0; data->rows_count = 0;
data->rows = malloc(1); data->rows = malloc(1);
data->memsize = 0;
} }
static void _clearData(HeightMapData* data) static void _clearData(HeightMapData* data)
@ -60,6 +60,7 @@ static void _clearData(HeightMapData* data)
} }
data->rows_count = 0; data->rows_count = 0;
data->rows = realloc(data->rows, 1); data->rows = realloc(data->rows, 1);
data->memsize = 0;
} }
static void _deleteData(HeightMapData* data) static void _deleteData(HeightMapData* data)
@ -70,9 +71,36 @@ static void _deleteData(HeightMapData* data)
static void _copyData(HeightMapData* source, HeightMapData* destination) static void _copyData(HeightMapData* source, HeightMapData* destination)
{ {
int i, j, n;
size_t size;
_clearData(destination); _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) 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) static void _loadData(PackStream* stream, HeightMapData* data)
{ {
int i, j, k, n; int i, j, k, n;
size_t size;
_clearData(data); _clearData(data);
packReadInt(stream, &data->rows_count); packReadInt(stream, &data->rows_count);
data->rows = realloc(data->rows, sizeof(HeightMapRow) * data->rows_count); if (data->rows_count > 0)
for (i = 0; i < data->rows_count; i++)
{ {
packReadInt(stream, &data->rows[i].z); size = sizeof(HeightMapRow) * data->rows_count;
packReadInt(stream, &data->rows[i].pixel_groups_count); data->rows = realloc(data->rows, size);
data->rows[i].pixel_groups = malloc(sizeof(HeightMapPixelGroup) * data->rows[i].pixel_groups_count); data->memsize += size;
for (j = 0; j < data->rows[i].pixel_groups_count; j++) for (i = 0; i < data->rows_count; i++)
{ {
packReadInt(stream, &data->rows[i].pixel_groups[j].xstart); packReadInt(stream, &data->rows[i].z);
packReadInt(stream, &data->rows[i].pixel_groups[j].xend); packReadInt(stream, &data->rows[i].pixel_groups_count);
n = data->rows[i].pixel_groups[j].xend - data->rows[i].pixel_groups[j].xstart; size = sizeof(HeightMapPixelGroup) * data->rows[i].pixel_groups_count;
data->rows[i].pixel_groups[j].height = malloc(sizeof(double) * n); data->rows[i].pixel_groups = malloc(size);
for (k = 0; k < n; k++) 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. * 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). * 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; int i;
@ -152,6 +190,7 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
row->pixel_groups = malloc(1); row->pixel_groups = malloc(1);
data->rows_count++; data->rows_count++;
data->memsize += sizeof(HeightMapRow);
} }
else else
{ {
@ -192,6 +231,7 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
pixel = pixel_group->height; pixel = pixel_group->height;
row->pixel_groups_count++; row->pixel_groups_count++;
data->memsize += sizeof(HeightMapPixelGroup) + sizeof(double);
} }
else if (x == pixel_group->xstart - 1) 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 */ /* Extend the rowgroup at start */
pixel_group->xstart--; pixel_group->xstart--;
pixel = naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, 0); 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) 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 */ /* Extend the rowgroup at end */
pixel_group->xend++; pixel_group->xend++;
pixel = naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, pixel_group->xend - pixel_group->xstart); 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 else
{ {
@ -224,9 +266,24 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, TerrainDefinit
} }
/* Reset pixel if it had been added */ /* 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; return pixel;
} }
@ -269,53 +326,71 @@ void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap)
_clearData(&heightmap->brush_data); _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]; *result = *dpointer;
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);
}
return 1; return 1;
} }
else else
{ {
return 0; dpointer = _getDataPointer(&heightmap->merged_data, x, z, NULL, NULL, 0);
}*/ if (dpointer)
return 0; {
*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 */ int ix, iz;
return 0; 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) 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) size_t terrainGetMemoryStats(TerrainDefinition* definition)
{ {
TerrainHeightMap* heightmap = definition->height_map; return definition->height_map->merged_data.memsize + definition->height_map->brush_data.memsize;
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;
} }
int terrainIsPainted(TerrainHeightMap* heightmap, int x, int z) 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); 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; 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); *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) 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 terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination);
void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap); void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap);
void terrainHeightmapLoad(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 #endif