paysages : Terrain painting improvements (WIP).
git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@551 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
parent
3e14fedbca
commit
82d291d903
6 changed files with 320 additions and 306 deletions
|
@ -1,22 +0,0 @@
|
||||||
#ifndef _PAYSAGES_ARRAY_H_
|
|
||||||
#define _PAYSAGES_ARRAY_H_
|
|
||||||
|
|
||||||
#include "shared/types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void arrayCreate(Array* array, int item_size);
|
|
||||||
void arrayDelete(Array* array);
|
|
||||||
void* arrayAppend(Array* array, void* item);
|
|
||||||
void arrayInsert(Array* array, void* item, int position);
|
|
||||||
void arrayReplace(Array* array, void* item, int position);
|
|
||||||
void arrayLStrip(Array* array, int count);
|
|
||||||
void arrayClear(Array* array);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -10,15 +10,6 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct Renderer Renderer;
|
typedef struct Renderer Renderer;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
int alloc_length;
|
|
||||||
int item_size;
|
|
||||||
int dirty;
|
|
||||||
void* data;
|
|
||||||
} Array;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int hit;
|
int hit;
|
||||||
|
|
|
@ -10,6 +10,226 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "../tools/memory.h"
|
#include "../tools/memory.h"
|
||||||
#include "../tools.h"
|
#include "../tools.h"
|
||||||
|
#include "../tools/array.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int xstart;
|
||||||
|
int xend;
|
||||||
|
double* height;
|
||||||
|
} HeightMapPixelGroup;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int z;
|
||||||
|
int memsize;
|
||||||
|
int pixel_groups_count;
|
||||||
|
HeightMapPixelGroup* pixel_groups;
|
||||||
|
} HeightMapRow;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int memsize;
|
||||||
|
int rows_count;
|
||||||
|
HeightMapRow* rows;
|
||||||
|
} HeightMapData;
|
||||||
|
|
||||||
|
struct TerrainHeightMap
|
||||||
|
{
|
||||||
|
TerrainDefinition* terrain;
|
||||||
|
HeightMapData merged_data;
|
||||||
|
HeightMapData brush_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _initData(HeightMapData* data)
|
||||||
|
{
|
||||||
|
data->rows_count = 0;
|
||||||
|
data->rows = malloc(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _clearData(HeightMapData* data)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for (i = 0; i < data->rows_count; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
|
||||||
|
{
|
||||||
|
free(data->rows[i].pixel_groups[j].height);
|
||||||
|
}
|
||||||
|
free(data->rows[i].pixel_groups);
|
||||||
|
}
|
||||||
|
data->rows_count = 0;
|
||||||
|
data->rows = realloc(data->rows, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _deleteData(HeightMapData* data)
|
||||||
|
{
|
||||||
|
_clearData(data);
|
||||||
|
free(data->rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _copyData(HeightMapData* source, HeightMapData* destination)
|
||||||
|
{
|
||||||
|
_clearData(destination);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _saveData(PackStream* stream, HeightMapData* data)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
packWriteInt(stream, &data->rows_count);
|
||||||
|
for (i = 0; i < data->rows_count; i++)
|
||||||
|
{
|
||||||
|
packWriteInt(stream, &data->rows[i].z);
|
||||||
|
packWriteInt(stream, &data->rows[i].pixel_groups_count);
|
||||||
|
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
|
||||||
|
{
|
||||||
|
packWriteInt(stream, &data->rows[i].pixel_groups[j].xstart);
|
||||||
|
packWriteInt(stream, &data->rows[i].pixel_groups[j].xend);
|
||||||
|
for (k = 0; k < data->rows[i].pixel_groups[j].xend - data->rows[i].pixel_groups[j].xstart; k++)
|
||||||
|
{
|
||||||
|
packWriteDouble(stream, &data->rows[i].pixel_groups[j].height[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _loadData(PackStream* stream, HeightMapData* data)
|
||||||
|
{
|
||||||
|
int i, j, k, n;
|
||||||
|
|
||||||
|
_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++)
|
||||||
|
{
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
packReadDouble(stream, &data->rows[i].pixel_groups[j].height[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a pointer to the data in a heightmap, to a certain location.
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Find row */
|
||||||
|
/* TODO Dichotomic search */
|
||||||
|
HeightMapRow* row;
|
||||||
|
i = 0;
|
||||||
|
while (i < data->rows_count && data->rows[i].z < z)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i < data->rows_count && data->rows[i].z == z)
|
||||||
|
{
|
||||||
|
row = data->rows + i;
|
||||||
|
}
|
||||||
|
else if (grow)
|
||||||
|
{
|
||||||
|
row = naiveArrayInsert((void**)&data->rows, sizeof(HeightMapRow), data->rows_count, i);
|
||||||
|
|
||||||
|
row->z = z;
|
||||||
|
row->pixel_groups_count = 0;
|
||||||
|
row->pixel_groups = malloc(1);
|
||||||
|
|
||||||
|
data->rows_count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find pixel group */
|
||||||
|
HeightMapPixelGroup* pixel_group = NULL;
|
||||||
|
for (i = 0; i < row->pixel_groups_count; i++)
|
||||||
|
{
|
||||||
|
if (x < row->pixel_groups[i].xstart - 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (x >= row->pixel_groups[i].xstart - 1 && x <= row->pixel_groups[i].xend + 1)
|
||||||
|
{
|
||||||
|
pixel_group = row->pixel_groups + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alter pixel group */
|
||||||
|
double* pixel;
|
||||||
|
int added = 1;
|
||||||
|
if (!pixel_group)
|
||||||
|
{
|
||||||
|
if (!grow)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the pixel group with one pixel */
|
||||||
|
pixel_group = naiveArrayInsert((void**)&row->pixel_groups, sizeof(HeightMapPixelGroup), row->pixel_groups_count, i);
|
||||||
|
|
||||||
|
pixel_group->xstart = x;
|
||||||
|
pixel_group->xend = x;
|
||||||
|
pixel_group->height = malloc(sizeof(double));
|
||||||
|
|
||||||
|
pixel = pixel_group->height;
|
||||||
|
|
||||||
|
row->pixel_groups_count++;
|
||||||
|
}
|
||||||
|
else if (x == pixel_group->xstart - 1)
|
||||||
|
{
|
||||||
|
if (!grow)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extend the rowgroup at start */
|
||||||
|
pixel_group->xstart--;
|
||||||
|
pixel = naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, 0);
|
||||||
|
}
|
||||||
|
else if (x == pixel_group->xend + 1)
|
||||||
|
{
|
||||||
|
if (!grow)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(x >= pixel_group->xstart);
|
||||||
|
assert(x <= pixel_group->xend);
|
||||||
|
pixel = pixel_group->height + x - pixel_group->xstart;
|
||||||
|
added = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset pixel if it had been added */
|
||||||
|
if (added && terrain)
|
||||||
|
{
|
||||||
|
*pixel = terrainGetGridHeight(terrain, x, z, 0);
|
||||||
|
}
|
||||||
|
return pixel;
|
||||||
|
}
|
||||||
|
|
||||||
TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* terrain)
|
TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* terrain)
|
||||||
{
|
{
|
||||||
|
@ -17,134 +237,41 @@ TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* terrain)
|
||||||
|
|
||||||
result = malloc(sizeof(TerrainHeightMap));
|
result = malloc(sizeof(TerrainHeightMap));
|
||||||
result->terrain = terrain;
|
result->terrain = terrain;
|
||||||
result->fixed_count = 0;
|
_initData(&result->merged_data);
|
||||||
result->fixed_data = malloc(sizeof(TerrainHeightMapChunk));
|
_initData(&result->brush_data);
|
||||||
result->floating_used = 0;
|
|
||||||
result->floating_data.data = malloc(sizeof(double));
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainHeightmapDelete(TerrainHeightMap* heightmap)
|
void terrainHeightmapDelete(TerrainHeightMap* heightmap)
|
||||||
{
|
{
|
||||||
int i;
|
_deleteData(&heightmap->merged_data);
|
||||||
for (i = 0; i < heightmap->fixed_count; i++)
|
_deleteData(&heightmap->brush_data);
|
||||||
{
|
|
||||||
free(heightmap->fixed_data[i].data);
|
|
||||||
}
|
|
||||||
free(heightmap->fixed_data);
|
|
||||||
free(heightmap->floating_data.data);
|
|
||||||
free(heightmap);
|
free(heightmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _setFixedCount(TerrainHeightMap* heightmap, int new_count)
|
|
||||||
{
|
|
||||||
int old_count = heightmap->fixed_count;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (new_count > old_count)
|
|
||||||
{
|
|
||||||
heightmap->fixed_data = realloc(heightmap->fixed_data, sizeof(TerrainHeightMapChunk) * new_count);
|
|
||||||
for (i = old_count; i < new_count; i++)
|
|
||||||
{
|
|
||||||
heightmap->fixed_data[i].data = malloc(sizeof(double));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (new_count < old_count)
|
|
||||||
{
|
|
||||||
for (i = new_count; i < old_count; i++)
|
|
||||||
{
|
|
||||||
free(heightmap->fixed_data[i].data);
|
|
||||||
}
|
|
||||||
if (new_count > 0)
|
|
||||||
{
|
|
||||||
heightmap->fixed_data = realloc(heightmap->fixed_data, sizeof(TerrainHeightMapChunk) * new_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
heightmap->fixed_count = new_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination)
|
void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
destination->terrain = source->terrain;
|
destination->terrain = source->terrain;
|
||||||
|
|
||||||
_setFixedCount(destination, source->fixed_count);
|
_copyData(&source->merged_data, &destination->merged_data);
|
||||||
|
_clearData(&destination->brush_data);
|
||||||
for (i = 0; i < destination->fixed_count; i++)
|
|
||||||
{
|
|
||||||
TerrainHeightMapChunk* chunk_source = source->fixed_data + i;
|
|
||||||
TerrainHeightMapChunk* chunk_destination = destination->fixed_data + i;
|
|
||||||
size_t mapsize = sizeof(double) * chunk_source->rect.xsize * chunk_source->rect.zsize;
|
|
||||||
|
|
||||||
chunk_destination->rect = chunk_source->rect;
|
|
||||||
if (chunk_source->rect.xsize * chunk_source->rect.zsize > 0)
|
|
||||||
{
|
|
||||||
chunk_destination->data = realloc(chunk_destination->data, mapsize);
|
|
||||||
memcpy(chunk_destination->data, chunk_source->data, mapsize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destination->floating_used = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap)
|
void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap)
|
||||||
{
|
{
|
||||||
int i, j;
|
_saveData(stream, &heightmap->merged_data);
|
||||||
|
|
||||||
packWriteInt(stream, &heightmap->fixed_count);
|
|
||||||
for (i = 0; i < heightmap->fixed_count; i++)
|
|
||||||
{
|
|
||||||
TerrainHeightMapChunk* chunk = heightmap->fixed_data + i;
|
|
||||||
|
|
||||||
packWriteInt(stream, &chunk->rect.xstart);
|
|
||||||
packWriteInt(stream, &chunk->rect.xend);
|
|
||||||
packWriteInt(stream, &chunk->rect.xsize);
|
|
||||||
packWriteInt(stream, &chunk->rect.zstart);
|
|
||||||
packWriteInt(stream, &chunk->rect.zend);
|
|
||||||
packWriteInt(stream, &chunk->rect.zsize);
|
|
||||||
for (j = 0; j < chunk->rect.xsize * chunk->rect.zsize; j++)
|
|
||||||
{
|
|
||||||
packWriteDouble(stream, &chunk->data[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap)
|
void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap)
|
||||||
{
|
{
|
||||||
int new_count, i, j;
|
_loadData(stream, &heightmap->merged_data);
|
||||||
|
_clearData(&heightmap->brush_data);
|
||||||
packReadInt(stream, &new_count);
|
|
||||||
_setFixedCount(heightmap, new_count);
|
|
||||||
|
|
||||||
for (i = 0; i < heightmap->fixed_count; i++)
|
|
||||||
{
|
|
||||||
TerrainHeightMapChunk* chunk = heightmap->fixed_data + i;
|
|
||||||
|
|
||||||
packReadInt(stream, &chunk->rect.xstart);
|
|
||||||
packReadInt(stream, &chunk->rect.xend);
|
|
||||||
packReadInt(stream, &chunk->rect.xsize);
|
|
||||||
packReadInt(stream, &chunk->rect.zstart);
|
|
||||||
packReadInt(stream, &chunk->rect.zend);
|
|
||||||
packReadInt(stream, &chunk->rect.zsize);
|
|
||||||
if (chunk->rect.xsize * chunk->rect.zsize > 0)
|
|
||||||
{
|
|
||||||
chunk->data = realloc(chunk->data, sizeof(double) * chunk->rect.xsize * chunk->rect.zsize);
|
|
||||||
}
|
|
||||||
for (j = 0; j < chunk->rect.xsize * chunk->rect.zsize; j++)
|
|
||||||
{
|
|
||||||
packReadDouble(stream, &chunk->data[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
heightmap->floating_used = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int _checkDataHit(TerrainHeightMapChunk* chunk, double x, double z, double* result)
|
static inline int _getInterpolatedValue(HeightMapData* data, double x, double z, double* result, TerrainDefinition* terrain)
|
||||||
{
|
{
|
||||||
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)
|
/*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 stencil[16];
|
double stencil[16];
|
||||||
int ix, iz, cx, cz;
|
int ix, iz, cx, cz;
|
||||||
|
@ -171,62 +298,24 @@ static inline int _checkDataHit(TerrainHeightMapChunk* chunk, double x, double z
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = toolsBicubicInterpolate(stencil, x - (double)xlow, z - (double)zlow);
|
if (result)
|
||||||
|
{
|
||||||
|
*result = toolsBicubicInterpolate(stencil, x - (double)xlow, z - (double)zlow);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result)
|
int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result)
|
||||||
{
|
{
|
||||||
int i;
|
/* TODO */
|
||||||
|
return 0;
|
||||||
if (heightmap->floating_used && _checkDataHit(&heightmap->floating_data, x, z, result))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = heightmap->fixed_count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (_checkDataHit(heightmap->fixed_data + i, x, z, result))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void _resetRect(TerrainHeightMap* heightmap, int x1, int x2, int z1, int z2)
|
|
||||||
{
|
|
||||||
int i, x, z;
|
|
||||||
double result;
|
|
||||||
|
|
||||||
for (x = x1; x <= x2; x++)
|
|
||||||
{
|
|
||||||
for (z = z1; z <= z2; z++)
|
|
||||||
{
|
|
||||||
/* Search for a previous fixed chunk */
|
|
||||||
for (i = heightmap->fixed_count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (_checkDataHit(heightmap->fixed_data + i, x + heightmap->floating_data.rect.xstart, z + heightmap->floating_data.rect.zstart, &result))
|
|
||||||
{
|
|
||||||
heightmap->floating_data.data[z * heightmap->floating_data.rect.xsize + x] = result;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i < 0)
|
|
||||||
{
|
|
||||||
/* No fixed chunk found */
|
|
||||||
heightmap->floating_data.data[z * heightmap->floating_data.rect.xsize + x] = terrainGetGridHeight(heightmap->terrain, x + heightmap->floating_data.rect.xstart, z + heightmap->floating_data.rect.zstart, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline IntegerRect _getBrushRect(TerrainBrush* brush)
|
static inline IntegerRect _getBrushRect(TerrainBrush* brush)
|
||||||
|
@ -250,90 +339,27 @@ static inline int _isInRect(IntegerRect rect, int x, int z)
|
||||||
return (x >= rect.xstart && x <= rect.xend && z >= rect.zstart && z <= rect.zend);
|
return (x >= rect.xstart && x <= rect.xend && z >= rect.zstart && z <= rect.zend);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _prepareBrushStroke(TerrainHeightMap* heightmap, TerrainBrush* brush)
|
|
||||||
{
|
|
||||||
IntegerRect brush_rect = _getBrushRect(brush);
|
|
||||||
|
|
||||||
/* Prepare floating data */
|
|
||||||
if (heightmap->floating_used)
|
|
||||||
{
|
|
||||||
int gx1 = (brush_rect.xstart < heightmap->floating_data.rect.xstart) ? heightmap->floating_data.rect.xstart - brush_rect.xstart : 0;
|
|
||||||
int gx2 = (brush_rect.xend > heightmap->floating_data.rect.xend) ? brush_rect.xend - heightmap->floating_data.rect.xend : 0;
|
|
||||||
int gz1 = (brush_rect.zstart < heightmap->floating_data.rect.zstart) ? heightmap->floating_data.rect.zstart - brush_rect.zstart : 0;
|
|
||||||
int gz2 = (brush_rect.zend > heightmap->floating_data.rect.zend) ? brush_rect.zend - heightmap->floating_data.rect.zend : 0;
|
|
||||||
if (gx1 || gx2 || gz1 || gz2)
|
|
||||||
{
|
|
||||||
/* Floating area needs growing */
|
|
||||||
int new_width = heightmap->floating_data.rect.xsize + gx1 + gx2;
|
|
||||||
int new_height = heightmap->floating_data.rect.zsize + gz1 + gz2;
|
|
||||||
|
|
||||||
heightmap->floating_data.data = memory2dRealloc(heightmap->floating_data.data, sizeof(double), heightmap->floating_data.rect.xsize, heightmap->floating_data.rect.zsize, new_width, new_height, gx1, gz1);
|
|
||||||
|
|
||||||
heightmap->floating_data.rect.xstart -= gx1;
|
|
||||||
heightmap->floating_data.rect.xend += gx2;
|
|
||||||
heightmap->floating_data.rect.xsize += gx1 + gx2;
|
|
||||||
heightmap->floating_data.rect.zstart -= gz1;
|
|
||||||
heightmap->floating_data.rect.zend += gz2;
|
|
||||||
heightmap->floating_data.rect.zsize += gz1 + gz2;
|
|
||||||
|
|
||||||
_resetRect(heightmap, 0, new_width - 1, 0, gz1 - 1);
|
|
||||||
_resetRect(heightmap, 0, new_width - 1, new_height - gz2, new_height - 1);
|
|
||||||
_resetRect(heightmap, 0, gx1 - 1, gz1, new_height - 1 - gz2);
|
|
||||||
_resetRect(heightmap, new_width - gx2, new_width - 1, gz1, new_height - 1 - gz2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Init floating area */
|
|
||||||
heightmap->floating_data.rect = brush_rect;
|
|
||||||
|
|
||||||
size_t new_size;
|
|
||||||
new_size = sizeof(double) * brush_rect.xsize * brush_rect.zsize;
|
|
||||||
heightmap->floating_data.data = realloc(heightmap->floating_data.data, new_size);
|
|
||||||
|
|
||||||
_resetRect(heightmap, 0, brush_rect.xsize - 1, 0, brush_rect.zsize - 1);
|
|
||||||
|
|
||||||
heightmap->floating_used = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t terrainGetMemoryStats(TerrainDefinition* definition)
|
size_t terrainGetMemoryStats(TerrainDefinition* definition)
|
||||||
{
|
{
|
||||||
TerrainHeightMap* heightmap = definition->height_map;
|
TerrainHeightMap* heightmap = definition->height_map;
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (heightmap->floating_used)
|
/*if (heightmap->floating_used)
|
||||||
{
|
{
|
||||||
result += sizeof(double) * heightmap->floating_data.rect.xsize * heightmap->floating_data.rect.zsize;
|
result += sizeof(double) * heightmap->floating_data.rect.xsize * heightmap->floating_data.rect.zsize;
|
||||||
}
|
}
|
||||||
for (i = 0; i < heightmap->fixed_count; i++)
|
for (i = 0; i < heightmap->fixed_count; i++)
|
||||||
{
|
{
|
||||||
result += sizeof(double) * heightmap->fixed_data[i].rect.xsize * heightmap->fixed_data[i].rect.zsize;
|
result += sizeof(double) * heightmap->fixed_data[i].rect.xsize * heightmap->fixed_data[i].rect.zsize;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int terrainIsPainted(TerrainHeightMap* heightmap, int x, int z)
|
int terrainIsPainted(TerrainHeightMap* heightmap, int x, int z)
|
||||||
{
|
{
|
||||||
int i;
|
return _getDataPointer(&heightmap->brush_data, x, z, NULL, 0) || _getDataPointer(&heightmap->merged_data, x, z, NULL, 0);
|
||||||
|
|
||||||
if (heightmap->floating_used && _isInRect(heightmap->floating_data.rect, x, z))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < heightmap->fixed_count; i++)
|
|
||||||
{
|
|
||||||
if (_isInRect(heightmap->fixed_data[i].rect, x, z))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 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);
|
||||||
|
@ -344,42 +370,32 @@ static inline void _applyBrush(TerrainHeightMap* heightmap, TerrainBrush* brush,
|
||||||
int x, z;
|
int x, z;
|
||||||
double dx, dz, distance, influence;
|
double dx, dz, distance, influence;
|
||||||
|
|
||||||
if (!heightmap->floating_used)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (x = brush_rect.xstart; x <= brush_rect.xend; x++)
|
for (x = brush_rect.xstart; x <= brush_rect.xend; x++)
|
||||||
{
|
{
|
||||||
dx = (double)x;
|
dx = (double)x;
|
||||||
for (z = brush_rect.zstart; z <= brush_rect.zend; z++)
|
for (z = brush_rect.zstart; z <= brush_rect.zend; z++)
|
||||||
{
|
{
|
||||||
if (_isInRect(heightmap->floating_data.rect, x, z)) /* TODO Rect intersection */
|
dz = (double)z;
|
||||||
{
|
distance = sqrt((brush->relative_x - dx) * (brush->relative_x - dx) + (brush->relative_z - dz) * (brush->relative_z - dz));
|
||||||
dz = (double)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)
|
||||||
|
{
|
||||||
|
if (distance <= brush->hard_radius + brush->smoothed_size)
|
||||||
{
|
{
|
||||||
if (distance <= brush->hard_radius + brush->smoothed_size)
|
influence = (1.0 - (distance - brush->hard_radius) / brush->smoothed_size);
|
||||||
{
|
|
||||||
influence = (1.0 - (distance - brush->hard_radius) / brush->smoothed_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
influence = 1.0;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ix = x - heightmap->floating_data.rect.xstart;
|
|
||||||
int iz = z - heightmap->floating_data.rect.zstart;
|
|
||||||
double base_value = heightmap->floating_data.data[iz * heightmap->floating_data.rect.xsize + ix];
|
|
||||||
heightmap->floating_data.data[iz * heightmap->floating_data.rect.xsize + ix] = callback(heightmap, brush, dx, dz, base_value, influence, force, data);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
influence = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double* dpointer = _getDataPointer(&heightmap->brush_data, x, z, heightmap->terrain, 1);
|
||||||
|
*dpointer = callback(heightmap, brush, dx, dz, *dpointer, influence, force, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,18 +403,23 @@ static inline void _applyBrush(TerrainHeightMap* heightmap, TerrainBrush* brush,
|
||||||
static double _applyBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data)
|
static double _applyBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data)
|
||||||
{
|
{
|
||||||
UNUSED(heightmap);
|
UNUSED(heightmap);
|
||||||
|
UNUSED(brush);
|
||||||
UNUSED(data);
|
UNUSED(data);
|
||||||
|
UNUSED(x);
|
||||||
|
UNUSED(z);
|
||||||
|
|
||||||
return basevalue + influence * force;
|
return basevalue + influence * force;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double value)
|
void terrainBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double value)
|
||||||
{
|
{
|
||||||
_prepareBrushStroke(heightmap, brush);
|
|
||||||
_applyBrush(heightmap, brush, value, NULL, _applyBrushElevation);
|
_applyBrush(heightmap, brush, value, NULL, _applyBrushElevation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double _applyBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data)
|
static double _applyBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data)
|
||||||
{
|
{
|
||||||
|
UNUSED(data);
|
||||||
|
|
||||||
double ideal, factor;
|
double ideal, factor;
|
||||||
ideal = terrainGetInterpolatedHeight(heightmap->terrain, x + brush->total_radius * 0.5, z, 1);
|
ideal = terrainGetInterpolatedHeight(heightmap->terrain, x + brush->total_radius * 0.5, z, 1);
|
||||||
ideal += terrainGetInterpolatedHeight(heightmap->terrain, x - brush->total_radius * 0.5, z, 1);
|
ideal += terrainGetInterpolatedHeight(heightmap->terrain, x - brush->total_radius * 0.5, z, 1);
|
||||||
|
@ -415,19 +436,18 @@ static double _applyBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush
|
||||||
|
|
||||||
void terrainBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double value)
|
void terrainBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double value)
|
||||||
{
|
{
|
||||||
_prepareBrushStroke(heightmap, brush);
|
|
||||||
_applyBrush(heightmap, brush, value, NULL, _applyBrushSmooth);
|
_applyBrush(heightmap, brush, value, NULL, _applyBrushSmooth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double _applyBrushAddNoise(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data)
|
static double _applyBrushAddNoise(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data)
|
||||||
{
|
{
|
||||||
UNUSED(heightmap);
|
UNUSED(heightmap);
|
||||||
|
|
||||||
return basevalue + noiseGet2DTotal((NoiseGenerator*)data, x / brush->total_radius, z / brush->total_radius) * influence * force * brush->total_radius;
|
return basevalue + noiseGet2DTotal((NoiseGenerator*)data, x / brush->total_radius, z / brush->total_radius) * influence * force * brush->total_radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainBrushAddNoise(TerrainHeightMap* heightmap, TerrainBrush* brush, NoiseGenerator* generator, double value)
|
void terrainBrushAddNoise(TerrainHeightMap* heightmap, TerrainBrush* brush, NoiseGenerator* generator, double value)
|
||||||
{
|
{
|
||||||
_prepareBrushStroke(heightmap, brush);
|
|
||||||
_applyBrush(heightmap, brush, value, generator, _applyBrushAddNoise);
|
_applyBrush(heightmap, brush, value, generator, _applyBrushAddNoise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,26 +462,10 @@ static double _applyBrushReset(TerrainHeightMap* heightmap, TerrainBrush* brush,
|
||||||
|
|
||||||
void terrainBrushReset(TerrainHeightMap* heightmap, TerrainBrush* brush, double value)
|
void terrainBrushReset(TerrainHeightMap* heightmap, TerrainBrush* brush, double value)
|
||||||
{
|
{
|
||||||
_prepareBrushStroke(heightmap, brush);
|
|
||||||
_applyBrush(heightmap, brush, value, NULL, _applyBrushReset);
|
_applyBrush(heightmap, brush, value, NULL, _applyBrushReset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void terrainEndBrushStroke(TerrainHeightMap* heightmap)
|
void terrainEndBrushStroke(TerrainHeightMap* heightmap)
|
||||||
{
|
{
|
||||||
/* Commit floating data to fixed */
|
/* TODO Merge data */
|
||||||
if (heightmap->floating_used)
|
|
||||||
{
|
|
||||||
/* TODO Find overlapping data and merge with them */
|
|
||||||
|
|
||||||
size_t mapsize = sizeof(double) * heightmap->floating_data.rect.xsize * heightmap->floating_data.rect.zsize;
|
|
||||||
heightmap->fixed_data = realloc(heightmap->fixed_data, sizeof(TerrainHeightMapChunk) * (heightmap->fixed_count + 1));
|
|
||||||
heightmap->fixed_data[heightmap->fixed_count].rect = heightmap->floating_data.rect;
|
|
||||||
heightmap->fixed_data[heightmap->fixed_count].data = malloc(mapsize);
|
|
||||||
memcpy(heightmap->fixed_data[heightmap->fixed_count].data, heightmap->floating_data.data, mapsize);
|
|
||||||
|
|
||||||
heightmap->fixed_count++;
|
|
||||||
|
|
||||||
heightmap->floating_used = 0;
|
|
||||||
heightmap->floating_data.data = realloc(heightmap->floating_data.data, sizeof(double));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,21 +13,6 @@ typedef struct
|
||||||
int zsize;
|
int zsize;
|
||||||
} IntegerRect;
|
} IntegerRect;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
IntegerRect rect;
|
|
||||||
double* data;
|
|
||||||
} TerrainHeightMapChunk;
|
|
||||||
|
|
||||||
struct TerrainHeightMap
|
|
||||||
{
|
|
||||||
TerrainDefinition* terrain;
|
|
||||||
int fixed_count;
|
|
||||||
TerrainHeightMapChunk* fixed_data;
|
|
||||||
int floating_used;
|
|
||||||
TerrainHeightMapChunk floating_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* definition);
|
TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* definition);
|
||||||
void terrainHeightmapDelete(TerrainHeightMap* heightmap);
|
void terrainHeightmapDelete(TerrainHeightMap* heightmap);
|
||||||
void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination);
|
void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination);
|
||||||
|
|
|
@ -1,8 +1,23 @@
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
void* naiveArrayInsert(void** array, size_t item_size, int item_count, int location)
|
||||||
|
{
|
||||||
|
assert(location >= 0);
|
||||||
|
assert(location <= item_count);
|
||||||
|
|
||||||
|
*array = realloc(*array, item_size * (item_count + 1));
|
||||||
|
if (location < item_count)
|
||||||
|
{
|
||||||
|
memmove(*array + item_size * (location + 1), *array + item_size * location, item_size * (item_count - location));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *array + item_size * location;
|
||||||
|
}
|
||||||
|
|
||||||
void arrayCreate(Array* array, int item_size)
|
void arrayCreate(Array* array, int item_size)
|
||||||
{
|
{
|
||||||
array->length = 0;
|
array->length = 0;
|
41
lib_paysages/tools/array.h
Normal file
41
lib_paysages/tools/array.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef _PAYSAGES_TOOLS_ARRAY_H_
|
||||||
|
#define _PAYSAGES_TOOLS_ARRAY_H_
|
||||||
|
|
||||||
|
#include "../shared/types.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**************** Naive methods (basic C arrays) ****************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert an item at a given position, rallocating the array, moving data and returning a pointer to the inserted element.
|
||||||
|
*/
|
||||||
|
void* naiveArrayInsert(void** array, size_t item_size, int item_count, int location);
|
||||||
|
|
||||||
|
/**************** Array object ****************/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
int alloc_length;
|
||||||
|
int item_size;
|
||||||
|
int dirty;
|
||||||
|
void* data;
|
||||||
|
} Array;
|
||||||
|
|
||||||
|
void arrayCreate(Array* array, int item_size);
|
||||||
|
void arrayDelete(Array* array);
|
||||||
|
void* arrayAppend(Array* array, void* item);
|
||||||
|
void arrayInsert(Array* array, void* item, int position);
|
||||||
|
void arrayReplace(Array* array, void* item, int position);
|
||||||
|
void arrayLStrip(Array* array, int count);
|
||||||
|
void arrayClear(Array* array);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue