diff --git a/lib_paysages/array.h b/lib_paysages/array.h deleted file mode 100644 index f523a74..0000000 --- a/lib_paysages/array.h +++ /dev/null @@ -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 diff --git a/lib_paysages/shared/types.h b/lib_paysages/shared/types.h index 885895f..74ab338 100644 --- a/lib_paysages/shared/types.h +++ b/lib_paysages/shared/types.h @@ -10,15 +10,6 @@ extern "C" { typedef struct Renderer Renderer; -typedef struct -{ - int length; - int alloc_length; - int item_size; - int dirty; - void* data; -} Array; - typedef struct { int hit; diff --git a/lib_paysages/terrain/painting.c b/lib_paysages/terrain/painting.c index cf71a6d..01e3149 100644 --- a/lib_paysages/terrain/painting.c +++ b/lib_paysages/terrain/painting.c @@ -10,6 +10,226 @@ #include #include "../tools/memory.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) { @@ -17,134 +237,41 @@ TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* terrain) result = malloc(sizeof(TerrainHeightMap)); result->terrain = terrain; - result->fixed_count = 0; - result->fixed_data = malloc(sizeof(TerrainHeightMapChunk)); - result->floating_used = 0; - result->floating_data.data = malloc(sizeof(double)); + _initData(&result->merged_data); + _initData(&result->brush_data); return result; } void terrainHeightmapDelete(TerrainHeightMap* heightmap) { - int i; - for (i = 0; i < heightmap->fixed_count; i++) - { - free(heightmap->fixed_data[i].data); - } - free(heightmap->fixed_data); - free(heightmap->floating_data.data); + _deleteData(&heightmap->merged_data); + _deleteData(&heightmap->brush_data); 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) { - int i; - destination->terrain = source->terrain; - _setFixedCount(destination, source->fixed_count); - - 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; + _copyData(&source->merged_data, &destination->merged_data); + _clearData(&destination->brush_data); } void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap) { - int i, j; - - 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]); - } - } + _saveData(stream, &heightmap->merged_data); } void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap) { - int new_count, i, j; - - 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; + _loadData(stream, &heightmap->merged_data); + _clearData(&heightmap->brush_data); } -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]; 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; } else { return 0; - } + }*/ + return 0; } int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result) { - int i; - - 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); - } - } - } + /* TODO */ + return 0; } 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); } -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) { TerrainHeightMap* heightmap = definition->height_map; size_t result = 0; int i; - if (heightmap->floating_used) + /*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 i; - - 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; - } + return _getDataPointer(&heightmap->brush_data, x, z, NULL, 0) || _getDataPointer(&heightmap->merged_data, x, z, NULL, 0); } 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; double dx, dz, distance, influence; - if (!heightmap->floating_used) - { - return; - } - for (x = brush_rect.xstart; x <= brush_rect.xend; x++) { dx = (double)x; 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); - } - else - { - continue; - } + influence = (1.0 - (distance - brush->hard_radius) / brush->smoothed_size); } 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) { UNUSED(heightmap); + UNUSED(brush); UNUSED(data); + UNUSED(x); + UNUSED(z); + return basevalue + influence * force; } void terrainBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double value) { - _prepareBrushStroke(heightmap, brush); _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) { + UNUSED(data); + 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); @@ -415,19 +436,18 @@ static double _applyBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush void terrainBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double value) { - _prepareBrushStroke(heightmap, brush); _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) { UNUSED(heightmap); + 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) { - _prepareBrushStroke(heightmap, brush); _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) { - _prepareBrushStroke(heightmap, brush); _applyBrush(heightmap, brush, value, NULL, _applyBrushReset); } void terrainEndBrushStroke(TerrainHeightMap* heightmap) { - /* Commit floating data to fixed */ - 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)); - } + /* TODO Merge data */ } diff --git a/lib_paysages/terrain/private.h b/lib_paysages/terrain/private.h index b118500..719dd57 100644 --- a/lib_paysages/terrain/private.h +++ b/lib_paysages/terrain/private.h @@ -13,21 +13,6 @@ typedef struct int zsize; } 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); void terrainHeightmapDelete(TerrainHeightMap* heightmap); void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination); diff --git a/lib_paysages/array.c b/lib_paysages/tools/array.c similarity index 84% rename from lib_paysages/array.c rename to lib_paysages/tools/array.c index a5087d6..b52e65f 100644 --- a/lib_paysages/array.c +++ b/lib_paysages/tools/array.c @@ -1,8 +1,23 @@ #include "array.h" +#include #include #include +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) { array->length = 0; diff --git a/lib_paysages/tools/array.h b/lib_paysages/tools/array.h new file mode 100644 index 0000000..5184ac7 --- /dev/null +++ b/lib_paysages/tools/array.h @@ -0,0 +1,41 @@ +#ifndef _PAYSAGES_TOOLS_ARRAY_H_ +#define _PAYSAGES_TOOLS_ARRAY_H_ + +#include "../shared/types.h" +#include + +#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