Merge branch 'master' into quick_ui
This commit is contained in:
commit
0c3a498cae
17 changed files with 874 additions and 848 deletions
342
src/definition/PaintedGrid.cpp
Normal file
342
src/definition/PaintedGrid.cpp
Normal file
|
@ -0,0 +1,342 @@
|
|||
#include "PaintedGrid.h"
|
||||
|
||||
#include <cassert>
|
||||
#include "Memory.h"
|
||||
#include "Interpolation.h"
|
||||
#include "PaintedGridData.h"
|
||||
#include "PaintedGridBrush.h"
|
||||
|
||||
PaintedGrid::PaintedGrid(BaseDefinition *parent):
|
||||
BaseDefinition(parent)
|
||||
{
|
||||
merged_data = new PaintedGridData;
|
||||
brush_data = new PaintedGridData;
|
||||
}
|
||||
|
||||
PaintedGrid::~PaintedGrid()
|
||||
{
|
||||
delete merged_data;
|
||||
delete brush_data;
|
||||
}
|
||||
|
||||
void PaintedGrid::copy(BaseDefinition *_destination) const
|
||||
{
|
||||
PaintedGrid* destination = (PaintedGrid *)_destination;
|
||||
|
||||
merged_data->copy(destination->merged_data);
|
||||
destination->brush_data->clear();
|
||||
}
|
||||
|
||||
void PaintedGrid::save(PackStream *stream) const
|
||||
{
|
||||
merged_data->save(stream);
|
||||
}
|
||||
|
||||
void PaintedGrid::load(PackStream *stream)
|
||||
{
|
||||
merged_data->load(stream);
|
||||
brush_data->clear();
|
||||
}
|
||||
|
||||
bool PaintedGrid::getInterpolatedValue(double x, double y, double *result) const
|
||||
{
|
||||
int ix, iy;
|
||||
int xlow;
|
||||
int ylow;
|
||||
|
||||
xlow = floor(x);
|
||||
ylow = floor(y);
|
||||
|
||||
int hit = 0;
|
||||
for (ix = xlow - 1; ix <= xlow + 2 && !hit; ix++)
|
||||
{
|
||||
for (iy = ylow - 1; iy <= ylow + 2 && !hit; iy++)
|
||||
{
|
||||
if (getDataPointer(brush_data, x, y, NULL, false) || getDataPointer(merged_data, x, y, NULL, false))
|
||||
{
|
||||
hit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hit && result)
|
||||
{
|
||||
double stencil[16];
|
||||
double value;
|
||||
for (ix = xlow - 1; ix <= xlow + 2; ix++)
|
||||
{
|
||||
for (iy = ylow - 1; iy <= ylow + 2; iy++)
|
||||
{
|
||||
if (!getGridValue(ix, iy, &value))
|
||||
{
|
||||
value = getInitialValue(ix, iy);
|
||||
}
|
||||
stencil[(iy - (ylow - 1)) * 4 + ix - (xlow - 1)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
*result = Interpolation::bicubic(stencil, x - (double)xlow, y - (double)ylow);
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool PaintedGrid::getGridValue(int x, int y, double *result) const
|
||||
{
|
||||
double* dpointer;
|
||||
dpointer = getDataPointer(brush_data, x, y, NULL, false);
|
||||
if (dpointer)
|
||||
{
|
||||
*result = *dpointer;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dpointer = getDataPointer(merged_data, x, y, NULL, false);
|
||||
if (dpointer)
|
||||
{
|
||||
*result = *dpointer;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double PaintedGrid::getFinalValue(double x, double y) const
|
||||
{
|
||||
double result;
|
||||
|
||||
if (getInterpolatedValue(x, y, &result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return getInitialValue(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
bool PaintedGrid::isPainted(int x, int y) const
|
||||
{
|
||||
return getDataPointer(brush_data, x, y, NULL, false) || getDataPointer(merged_data, x, y, NULL, false);
|
||||
}
|
||||
|
||||
unsigned long PaintedGrid::getMemoryStats() const
|
||||
{
|
||||
return merged_data->memsize + brush_data->memsize;
|
||||
}
|
||||
|
||||
void PaintedGrid::clearPainting()
|
||||
{
|
||||
merged_data->clear();
|
||||
brush_data->clear();
|
||||
}
|
||||
|
||||
void PaintedGrid::applyBrush(const PaintedGridBrush &brush, double x, double y, double force)
|
||||
{
|
||||
int xstart, xend, ystart, yend;
|
||||
|
||||
brush.getArea(x, y, &xstart, &ystart, &xend, ¥d);
|
||||
|
||||
int ix, iy;
|
||||
double dx, dy, influence;
|
||||
|
||||
for (ix = xstart; ix <= xend; ix++)
|
||||
{
|
||||
dx = (double)ix;
|
||||
for (iy = ystart; iy <= yend; iy++)
|
||||
{
|
||||
dy = (double)iy;
|
||||
|
||||
influence = brush.getInfluence(x - dx, y - dy);
|
||||
|
||||
if (influence > 0.0)
|
||||
{
|
||||
double* dpointer = getDataPointer(brush_data, ix, iy, merged_data, true);
|
||||
*dpointer = brush.getValue(this, dx, dy, *dpointer, influence, force);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintedGrid::endBrushStroke()
|
||||
{
|
||||
int i, j, k;
|
||||
PaintedGridData* data = 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 + 1; k++)
|
||||
{
|
||||
double* dpointer = getDataPointer(merged_data, data->rows[i].pixel_groups[j].xstart + k, data->rows[i].y, NULL, true);
|
||||
*dpointer = data->rows[i].pixel_groups[j].height[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
brush_data->clear();
|
||||
}
|
||||
|
||||
double PaintedGrid::getInitialValue(double, double) const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double *PaintedGrid::getDataPointer(PaintedGridData *data, int x, int y, PaintedGridData *fallback, bool grow) const
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Find row */
|
||||
/* TODO Dichotomic search */
|
||||
PaintedGridData::HeightMapRow* row;
|
||||
i = 0;
|
||||
while (i < data->rows_count && data->rows[i].y < y)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (i < data->rows_count && data->rows[i].y == y)
|
||||
{
|
||||
row = data->rows + i;
|
||||
}
|
||||
else if (grow)
|
||||
{
|
||||
row = (PaintedGridData::HeightMapRow*)Memory::naiveArrayInsert((void**)&data->rows, sizeof(PaintedGridData::HeightMapRow), data->rows_count, i);
|
||||
|
||||
row->y = y;
|
||||
row->pixel_groups_count = 0;
|
||||
row->pixel_groups = (PaintedGridData::HeightMapPixelGroup*)malloc(1);
|
||||
|
||||
data->rows_count++;
|
||||
data->memsize += sizeof(PaintedGridData::HeightMapRow);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Check rows */
|
||||
for (i = 1; i < data->rows_count; i++)
|
||||
{
|
||||
assert(data->rows[i].z > data->rows[i - 1].z);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Find pixel group */
|
||||
PaintedGridData::HeightMapPixelGroup* pixel_group = NULL;
|
||||
for (i = 0; i < row->pixel_groups_count; i++)
|
||||
{
|
||||
if (x < row->pixel_groups[i].xstart - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (x <= row->pixel_groups[i].xend + 1)
|
||||
{
|
||||
if (x == row->pixel_groups[i].xend + 1 && i < row->pixel_groups_count - 1 && x == row->pixel_groups[i + 1].xstart)
|
||||
{
|
||||
/* Choose next group if it already includes the pixel */
|
||||
i++;
|
||||
}
|
||||
pixel_group = row->pixel_groups + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Alter pixel group */
|
||||
double* pixel;
|
||||
int added = 1;
|
||||
if (!pixel_group)
|
||||
{
|
||||
if (!grow)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the pixel group with one pixel */
|
||||
pixel_group = (PaintedGridData::HeightMapPixelGroup*)Memory::naiveArrayInsert((void**)&row->pixel_groups, sizeof(PaintedGridData::HeightMapPixelGroup), row->pixel_groups_count, i);
|
||||
|
||||
pixel_group->xstart = x;
|
||||
pixel_group->xend = x;
|
||||
pixel_group->height = (double*)malloc(sizeof(double));
|
||||
|
||||
pixel = pixel_group->height;
|
||||
|
||||
row->pixel_groups_count++;
|
||||
data->memsize += sizeof(PaintedGridData::HeightMapPixelGroup) + sizeof(double);
|
||||
}
|
||||
else if (x == pixel_group->xstart - 1)
|
||||
{
|
||||
if (!grow)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extend the rowgroup at start */
|
||||
pixel_group->xstart--;
|
||||
pixel = (double*)Memory::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)
|
||||
{
|
||||
if (!grow)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extend the rowgroup at end */
|
||||
pixel_group->xend++;
|
||||
pixel = (double*)Memory::naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, pixel_group->xend - pixel_group->xstart);
|
||||
data->memsize += sizeof(double);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(x >= pixel_group->xstart);
|
||||
assert(x <= pixel_group->xend);
|
||||
pixel = pixel_group->height + x - pixel_group->xstart;
|
||||
added = 0;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Check pixel groups */
|
||||
for (i = 0; i < row->pixel_groups_count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
assert(row->pixel_groups[i].xstart > row->pixel_groups[i - 1].xend);
|
||||
}
|
||||
if (i < row->pixel_groups_count - 1)
|
||||
{
|
||||
assert(row->pixel_groups[i].xend < row->pixel_groups[i + 1].xstart);
|
||||
}
|
||||
assert(row->pixel_groups[i].xend >= row->pixel_groups[i].xstart);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset pixel if it had been added */
|
||||
if (added)
|
||||
{
|
||||
if (fallback)
|
||||
{
|
||||
double* dpointer = getDataPointer(fallback, x, y, NULL, false);
|
||||
if (dpointer)
|
||||
{
|
||||
*pixel = *dpointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixel = getInitialValue(x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixel = getInitialValue(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
return pixel;
|
||||
}
|
90
src/definition/PaintedGrid.h
Normal file
90
src/definition/PaintedGrid.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#ifndef PAINTEDGRID_H
|
||||
#define PAINTEDGRID_H
|
||||
|
||||
#include "definition_global.h"
|
||||
|
||||
#include "BaseDefinition.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
/**
|
||||
* Grid of values that can be painted using a brush.
|
||||
*
|
||||
* This may be useful for terrain altitude, texture presence...
|
||||
*
|
||||
* Grid cells are considered to be 1.0-sized.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGrid: public BaseDefinition
|
||||
{
|
||||
public:
|
||||
PaintedGrid(BaseDefinition *parent=0);
|
||||
virtual ~PaintedGrid();
|
||||
|
||||
virtual void copy(BaseDefinition *destination) const override;
|
||||
virtual void save(PackStream *stream) const override;
|
||||
virtual void load(PackStream *stream) override;
|
||||
|
||||
/**
|
||||
* Get the interpolated value at a given location.
|
||||
*
|
||||
* Returns true if the value is user-specified in the grid, false otherwise.
|
||||
*/
|
||||
bool getInterpolatedValue(double x, double y, double *result) const;
|
||||
|
||||
/**
|
||||
* Get the grid-stored value at a grid point.
|
||||
*
|
||||
* Returns true if the value is user-specified in the grid, false otherwise.
|
||||
*/
|
||||
bool getGridValue(int x, int y, double *result) const;
|
||||
|
||||
/**
|
||||
* Get the final interpolated value, using initial value as fallback.
|
||||
*/
|
||||
double getFinalValue(double x, double y) const;
|
||||
|
||||
/**
|
||||
* Returns true if a grid point is user-specified, false if it's the initial value.
|
||||
*/
|
||||
bool isPainted(int x, int y) const;
|
||||
|
||||
/**
|
||||
* Get the number of bytes used by this grid.
|
||||
*/
|
||||
unsigned long getMemoryStats() const;
|
||||
|
||||
/**
|
||||
* Clear all painting and reset the initial value everywhere.
|
||||
*/
|
||||
void clearPainting();
|
||||
|
||||
/**
|
||||
* Apply a brush stroke at a grid location (locating the brush center).
|
||||
*/
|
||||
void applyBrush(const PaintedGridBrush &brush, double x, double y, double force);
|
||||
|
||||
/**
|
||||
* Commit previous brush strokes.
|
||||
*/
|
||||
void endBrushStroke();
|
||||
|
||||
/**
|
||||
* Virtual method that can be reimplemented to provide the initial value at a grid location.
|
||||
*
|
||||
* By default, the initial value will be 0.0.
|
||||
*/
|
||||
virtual double getInitialValue(double x, double y) const;
|
||||
|
||||
private:
|
||||
double *getDataPointer(PaintedGridData *data, int x, int y, PaintedGridData *fallback, bool grow) const;
|
||||
|
||||
private:
|
||||
PaintedGridData *merged_data;
|
||||
PaintedGridData *brush_data;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PAINTEDGRID_H
|
84
src/definition/PaintedGridBrush.cpp
Normal file
84
src/definition/PaintedGridBrush.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#include "PaintedGridBrush.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "NoiseGenerator.h"
|
||||
#include "PaintedGrid.h"
|
||||
|
||||
PaintedGridBrush::PaintedGridBrush(double hard_radius, double smoothed_size, double total_radius):
|
||||
hard_radius(hard_radius), smoothed_size(smoothed_size), total_radius(total_radius)
|
||||
{
|
||||
}
|
||||
|
||||
void PaintedGridBrush::getArea(double x, double y, int *xstart, int *ystart, int *xend, int *yend) const
|
||||
{
|
||||
double s = smoothed_size + hard_radius;
|
||||
|
||||
*xstart = (int)floor(x - s);
|
||||
*xend = (int)ceil(x + s);
|
||||
*ystart = (int)floor(y - s);
|
||||
*yend = (int)ceil(y + s);
|
||||
}
|
||||
|
||||
double PaintedGridBrush::getInfluence(double dx, double dy) const
|
||||
{
|
||||
double distance = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance > hard_radius)
|
||||
{
|
||||
if (distance <= hard_radius + smoothed_size)
|
||||
{
|
||||
return 1.0 - (distance - hard_radius) / smoothed_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
double PaintedGridBrush::getValue(const PaintedGrid *, double, double, double basevalue, double, double) const
|
||||
{
|
||||
return basevalue;
|
||||
}
|
||||
|
||||
double PaintedGridBrushRaiseLower::getValue(const PaintedGrid *, double, double, double basevalue, double influence, double force) const
|
||||
{
|
||||
return basevalue + influence * force;
|
||||
}
|
||||
|
||||
double PaintedGridBrushSmooth::getValue(const PaintedGrid *grid, double x, double y, double basevalue, double influence, double force) const
|
||||
{
|
||||
double ideal, factor;
|
||||
ideal = grid->getFinalValue((x + total_radius * 0.5), y);
|
||||
ideal += grid->getFinalValue((x - total_radius * 0.5), y);
|
||||
ideal += grid->getFinalValue(x, (y - total_radius * 0.5));
|
||||
ideal += grid->getFinalValue(x, (y + total_radius * 0.5));
|
||||
ideal /= 4.0;
|
||||
factor = influence * force;
|
||||
if (factor > 1.0)
|
||||
{
|
||||
factor = 0.0;
|
||||
}
|
||||
return basevalue + (ideal - basevalue) * factor;
|
||||
}
|
||||
|
||||
double PaintedGridBrushAddNoise::getValue(const PaintedGrid *, double x, double y, double basevalue, double influence, double force) const
|
||||
{
|
||||
return basevalue + generator->get2DTotal(x / total_radius, y / total_radius) * influence * force * total_radius;
|
||||
}
|
||||
|
||||
double PaintedGridBrushReset::getValue(const PaintedGrid *grid, double x, double y, double basevalue, double influence, double force) const
|
||||
{
|
||||
double ideal = grid->getInitialValue(x, y);
|
||||
return basevalue + (ideal - basevalue) * influence * force;
|
||||
}
|
||||
|
||||
double PaintedGridBrushFlatten::getValue(const PaintedGrid *, double, double, double basevalue, double influence, double force) const
|
||||
{
|
||||
double ideal = target;
|
||||
return basevalue + (ideal - basevalue) * influence * force;
|
||||
}
|
95
src/definition/PaintedGridBrush.h
Normal file
95
src/definition/PaintedGridBrush.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef PAINTEDGRIDBRUSH_H
|
||||
#define PAINTEDGRIDBRUSH_H
|
||||
|
||||
#include "definition_global.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
/**
|
||||
* Base class for brushes that can be used to paint values on a PaintedGrid.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGridBrush
|
||||
{
|
||||
public:
|
||||
PaintedGridBrush(double hard_radius, double smoothed_size, double total_radius);
|
||||
|
||||
/**
|
||||
* Get the rectangle area potentially covered by this brush.
|
||||
*/
|
||||
void getArea(double x, double y, int *xstart, int *ystart, int *xend, int *yend) const;
|
||||
|
||||
/**
|
||||
* Get the brush influence for coordinates relative to its center.
|
||||
*/
|
||||
double getInfluence(double dx, double dy) const;
|
||||
|
||||
/**
|
||||
* Abstract method to reimplement to get the final value of a brush stroke at a given point.
|
||||
*/
|
||||
virtual double getValue(const PaintedGrid *grid, double x, double y, double basevalue, double influence, double force) const;
|
||||
|
||||
protected:
|
||||
double hard_radius;
|
||||
double smoothed_size;
|
||||
double total_radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Brush able to raise or lower the grid value.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGridBrushRaiseLower: public PaintedGridBrush
|
||||
{
|
||||
public:
|
||||
PaintedGridBrushRaiseLower(const PaintedGridBrush &brush) : PaintedGridBrush(brush) {}
|
||||
double getValue(const PaintedGrid *grid, double x, double z, double basevalue, double influence, double force) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Brush able to smooth the value in an area.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGridBrushSmooth: public PaintedGridBrush
|
||||
{
|
||||
public:
|
||||
PaintedGridBrushSmooth(const PaintedGridBrush &brush) : PaintedGridBrush(brush) {}
|
||||
double getValue(const PaintedGrid *grid, double x, double z, double basevalue, double influence, double force) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Brush able to add random fractal noise.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGridBrushAddNoise: public PaintedGridBrush
|
||||
{
|
||||
public:
|
||||
PaintedGridBrushAddNoise(const PaintedGridBrush &brush, NoiseGenerator *generator) : PaintedGridBrush(brush), generator(generator) {}
|
||||
double getValue(const PaintedGrid *grid, double x, double z, double basevalue, double influence, double force) const override;
|
||||
private:
|
||||
NoiseGenerator *generator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Brush able to reset to initial value.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGridBrushReset: public PaintedGridBrush
|
||||
{
|
||||
public:
|
||||
PaintedGridBrushReset(const PaintedGridBrush &brush) : PaintedGridBrush(brush) {}
|
||||
double getValue(const PaintedGrid *grid, double x, double z, double basevalue, double influence, double force) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Brush able to flatten to a specific value.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT PaintedGridBrushFlatten: public PaintedGridBrush
|
||||
{
|
||||
public:
|
||||
PaintedGridBrushFlatten(const PaintedGridBrush &brush, double target) : PaintedGridBrush(brush), target(target) {}
|
||||
double getValue(const PaintedGrid *grid, double x, double z, double basevalue, double influence, double force) const override;
|
||||
private:
|
||||
double target;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PAINTEDGRIDBRUSH_H
|
125
src/definition/PaintedGridData.cpp
Normal file
125
src/definition/PaintedGridData.cpp
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include "PaintedGridData.h"
|
||||
|
||||
#include <cstring>
|
||||
#include "PackStream.h"
|
||||
|
||||
PaintedGridData::PaintedGridData()
|
||||
{
|
||||
rows_count = 0;
|
||||
rows = new HeightMapRow[1];
|
||||
memsize = 0;
|
||||
}
|
||||
|
||||
PaintedGridData::~PaintedGridData()
|
||||
{
|
||||
clear();
|
||||
delete[] rows;
|
||||
}
|
||||
|
||||
void PaintedGridData::copy(PaintedGridData *destination) const
|
||||
{
|
||||
int i, j, n;
|
||||
size_t size;
|
||||
|
||||
destination->clear();
|
||||
|
||||
destination->rows_count = this->rows_count;
|
||||
if (destination->rows_count > 0)
|
||||
{
|
||||
size = sizeof(HeightMapRow) * destination->rows_count;
|
||||
destination->rows = (HeightMapRow*)realloc(destination->rows, size);
|
||||
destination->memsize += size;
|
||||
for (i = 0; i < destination->rows_count; i++)
|
||||
{
|
||||
destination->rows[i].y = this->rows[i].y;
|
||||
destination->rows[i].pixel_groups_count = this->rows[i].pixel_groups_count;
|
||||
size = sizeof(HeightMapPixelGroup) * destination->rows[i].pixel_groups_count;
|
||||
destination->rows[i].pixel_groups = (HeightMapPixelGroup*)malloc(size);
|
||||
destination->memsize += size;
|
||||
for (j = 0; j < destination->rows[i].pixel_groups_count; j++)
|
||||
{
|
||||
destination->rows[i].pixel_groups[j].xstart = this->rows[i].pixel_groups[j].xstart;
|
||||
destination->rows[i].pixel_groups[j].xend = this->rows[i].pixel_groups[j].xend;
|
||||
n = destination->rows[i].pixel_groups[j].xend - destination->rows[i].pixel_groups[j].xstart + 1;
|
||||
size = sizeof(double) * n;
|
||||
destination->rows[i].pixel_groups[j].height = (double*)malloc(size);
|
||||
destination->memsize += size;
|
||||
memcpy(destination->rows[i].pixel_groups[j].height, this->rows[i].pixel_groups[j].height, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintedGridData::save(PackStream *stream) const
|
||||
{
|
||||
int i, j, k;
|
||||
stream->write(&rows_count);
|
||||
for (i = 0; i < rows_count; i++)
|
||||
{
|
||||
stream->write(&rows[i].y);
|
||||
stream->write(&rows[i].pixel_groups_count);
|
||||
for (j = 0; j < rows[i].pixel_groups_count; j++)
|
||||
{
|
||||
stream->write(&rows[i].pixel_groups[j].xstart);
|
||||
stream->write(&rows[i].pixel_groups[j].xend);
|
||||
for (k = 0; k < rows[i].pixel_groups[j].xend - rows[i].pixel_groups[j].xstart; k++)
|
||||
{
|
||||
stream->write(&rows[i].pixel_groups[j].height[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintedGridData::load(PackStream *stream)
|
||||
{
|
||||
int i, j, k, n;
|
||||
size_t size;
|
||||
|
||||
clear();
|
||||
|
||||
stream->read(&rows_count);
|
||||
if (rows_count > 0)
|
||||
{
|
||||
size = sizeof(HeightMapRow) * rows_count;
|
||||
rows = (HeightMapRow*)realloc(rows, size);
|
||||
memsize += size;
|
||||
for (i = 0; i < rows_count; i++)
|
||||
{
|
||||
stream->read(&rows[i].y);
|
||||
stream->read(&rows[i].pixel_groups_count);
|
||||
size = sizeof(HeightMapPixelGroup) * rows[i].pixel_groups_count;
|
||||
rows[i].pixel_groups = (HeightMapPixelGroup*)malloc(size);
|
||||
memsize += size;
|
||||
for (j = 0; j < rows[i].pixel_groups_count; j++)
|
||||
{
|
||||
stream->read(&rows[i].pixel_groups[j].xstart);
|
||||
stream->read(&rows[i].pixel_groups[j].xend);
|
||||
n = rows[i].pixel_groups[j].xend - rows[i].pixel_groups[j].xstart;
|
||||
size = sizeof(double) * n;
|
||||
rows[i].pixel_groups[j].height = (double*)malloc(size);
|
||||
memsize += size;
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
stream->read(&rows[i].pixel_groups[j].height[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintedGridData::clear()
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < rows_count; i++)
|
||||
{
|
||||
for (j = 0; j < rows[i].pixel_groups_count; j++)
|
||||
{
|
||||
free(rows[i].pixel_groups[j].height);
|
||||
}
|
||||
free(rows[i].pixel_groups);
|
||||
}
|
||||
rows_count = 0;
|
||||
delete[] rows;
|
||||
rows = new HeightMapRow[1];
|
||||
memsize = 0;
|
||||
}
|
52
src/definition/PaintedGridData.h
Normal file
52
src/definition/PaintedGridData.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef PAINTEDGRIDDATA_H
|
||||
#define PAINTEDGRIDDATA_H
|
||||
|
||||
#include "definition_global.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
/**
|
||||
* Internal storage class to hold data for a PaintedGrid.
|
||||
*/
|
||||
class PaintedGridData
|
||||
{
|
||||
friend class PaintedGrid;
|
||||
|
||||
public:
|
||||
PaintedGridData();
|
||||
~PaintedGridData();
|
||||
|
||||
void copy(PaintedGridData *destination) const;
|
||||
void save(PackStream *stream) const;
|
||||
void load(PackStream *stream);
|
||||
|
||||
/**
|
||||
* Clear all stored data.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private:
|
||||
typedef struct
|
||||
{
|
||||
int xstart;
|
||||
int xend;
|
||||
double* height;
|
||||
} HeightMapPixelGroup;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int y;
|
||||
int pixel_groups_count;
|
||||
HeightMapPixelGroup* pixel_groups;
|
||||
} HeightMapRow;
|
||||
|
||||
int memsize;
|
||||
int rows_count;
|
||||
HeightMapRow* rows;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PAINTEDGRIDDATA_H
|
|
@ -86,7 +86,7 @@ double TerrainDefinition::getGridHeight(int x, int z, int with_painting)
|
|||
{
|
||||
double h;
|
||||
|
||||
if (!with_painting || !height_map->getGridHeight(x, z, &h))
|
||||
if (!with_painting || !height_map->getGridValue(x, z, &h))
|
||||
{
|
||||
h = _height_noise->get2DTotal((double)x, (double)z);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, int scaled,
|
|||
x /= scaling;
|
||||
z /= scaling;
|
||||
|
||||
if (!with_painting || !height_map->getInterpolatedHeight(x, z, &h))
|
||||
if (!with_painting || !height_map->getInterpolatedValue(x, z, &h))
|
||||
{
|
||||
h = _height_noise->get2DTotal(x, z);
|
||||
}
|
||||
|
|
|
@ -1,333 +1,11 @@
|
|||
#include "TerrainHeightMap.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include "PackStream.h"
|
||||
#include "Memory.h"
|
||||
#include "TerrainDefinition.h"
|
||||
#include "TerrainHeightMapBrush.h"
|
||||
#include "Interpolation.h"
|
||||
#include "NoiseGenerator.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int xstart;
|
||||
int xend;
|
||||
double* height;
|
||||
} HeightMapPixelGroup;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int z;
|
||||
int pixel_groups_count;
|
||||
HeightMapPixelGroup* pixel_groups;
|
||||
} HeightMapRow;
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
class TerrainHeightMapData
|
||||
{
|
||||
public:
|
||||
int memsize;
|
||||
int rows_count;
|
||||
HeightMapRow* rows;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static void _initData(TerrainHeightMapData* data)
|
||||
{
|
||||
data->rows_count = 0;
|
||||
data->rows = new HeightMapRow[1];
|
||||
data->memsize = 0;
|
||||
}
|
||||
|
||||
static void _clearData(TerrainHeightMapData* 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;
|
||||
delete[] data->rows;
|
||||
data->rows = new HeightMapRow[1];
|
||||
data->memsize = 0;
|
||||
}
|
||||
|
||||
static void _deleteData(TerrainHeightMapData* data)
|
||||
{
|
||||
_clearData(data);
|
||||
delete[] data->rows;
|
||||
delete data;
|
||||
}
|
||||
|
||||
static void _copyData(TerrainHeightMapData* source, TerrainHeightMapData* destination)
|
||||
{
|
||||
int i, j, n;
|
||||
size_t size;
|
||||
|
||||
_clearData(destination);
|
||||
|
||||
destination->rows_count = source->rows_count;
|
||||
if (destination->rows_count > 0)
|
||||
{
|
||||
size = sizeof(HeightMapRow) * destination->rows_count;
|
||||
destination->rows = (HeightMapRow*)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 = (HeightMapPixelGroup*)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 + 1;
|
||||
size = sizeof(double) * n;
|
||||
destination->rows[i].pixel_groups[j].height = (double*)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, TerrainHeightMapData* data)
|
||||
{
|
||||
int i, j, k;
|
||||
stream->write(&data->rows_count);
|
||||
for (i = 0; i < data->rows_count; i++)
|
||||
{
|
||||
stream->write(&data->rows[i].z);
|
||||
stream->write(&data->rows[i].pixel_groups_count);
|
||||
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
|
||||
{
|
||||
stream->write(&data->rows[i].pixel_groups[j].xstart);
|
||||
stream->write(&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++)
|
||||
{
|
||||
stream->write(&data->rows[i].pixel_groups[j].height[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _loadData(PackStream* stream, TerrainHeightMapData* data)
|
||||
{
|
||||
int i, j, k, n;
|
||||
size_t size;
|
||||
|
||||
_clearData(data);
|
||||
|
||||
stream->read(&data->rows_count);
|
||||
if (data->rows_count > 0)
|
||||
{
|
||||
size = sizeof(HeightMapRow) * data->rows_count;
|
||||
data->rows = (HeightMapRow*)realloc(data->rows, size);
|
||||
data->memsize += size;
|
||||
for (i = 0; i < data->rows_count; i++)
|
||||
{
|
||||
stream->read(&data->rows[i].z);
|
||||
stream->read(&data->rows[i].pixel_groups_count);
|
||||
size = sizeof(HeightMapPixelGroup) * data->rows[i].pixel_groups_count;
|
||||
data->rows[i].pixel_groups = (HeightMapPixelGroup*)malloc(size);
|
||||
data->memsize += size;
|
||||
for (j = 0; j < data->rows[i].pixel_groups_count; j++)
|
||||
{
|
||||
stream->read(&data->rows[i].pixel_groups[j].xstart);
|
||||
stream->read(&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 = (double*)malloc(size);
|
||||
data->memsize += size;
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
stream->read(&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).
|
||||
*/
|
||||
inline double* TerrainHeightMap::getDataPointer(TerrainHeightMapData* data, int x, int z, TerrainHeightMapData* fallback, 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 = (HeightMapRow*)Memory::naiveArrayInsert((void**)&data->rows, sizeof(HeightMapRow), data->rows_count, i);
|
||||
|
||||
row->z = z;
|
||||
row->pixel_groups_count = 0;
|
||||
row->pixel_groups = (HeightMapPixelGroup*)malloc(1);
|
||||
|
||||
data->rows_count++;
|
||||
data->memsize += sizeof(HeightMapRow);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Check rows */
|
||||
for (i = 1; i < data->rows_count; i++)
|
||||
{
|
||||
assert(data->rows[i].z > data->rows[i - 1].z);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
}
|
||||
else if (x <= row->pixel_groups[i].xend + 1)
|
||||
{
|
||||
if (x == row->pixel_groups[i].xend + 1 && i < row->pixel_groups_count - 1 && x == row->pixel_groups[i + 1].xstart)
|
||||
{
|
||||
/* Choose next group if it already includes the pixel */
|
||||
i++;
|
||||
}
|
||||
pixel_group = row->pixel_groups + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Alter pixel group */
|
||||
double* pixel;
|
||||
int added = 1;
|
||||
if (!pixel_group)
|
||||
{
|
||||
if (!grow)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the pixel group with one pixel */
|
||||
pixel_group = (HeightMapPixelGroup*)Memory::naiveArrayInsert((void**)&row->pixel_groups, sizeof(HeightMapPixelGroup), row->pixel_groups_count, i);
|
||||
|
||||
pixel_group->xstart = x;
|
||||
pixel_group->xend = x;
|
||||
pixel_group->height = (double*)malloc(sizeof(double));
|
||||
|
||||
pixel = pixel_group->height;
|
||||
|
||||
row->pixel_groups_count++;
|
||||
data->memsize += sizeof(HeightMapPixelGroup) + sizeof(double);
|
||||
}
|
||||
else if (x == pixel_group->xstart - 1)
|
||||
{
|
||||
if (!grow)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extend the rowgroup at start */
|
||||
pixel_group->xstart--;
|
||||
pixel = (double*)Memory::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)
|
||||
{
|
||||
if (!grow)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extend the rowgroup at end */
|
||||
pixel_group->xend++;
|
||||
pixel = (double*)Memory::naiveArrayInsert((void**)&pixel_group->height, sizeof(double), pixel_group->xend - pixel_group->xstart, pixel_group->xend - pixel_group->xstart);
|
||||
data->memsize += sizeof(double);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(x >= pixel_group->xstart);
|
||||
assert(x <= pixel_group->xend);
|
||||
pixel = pixel_group->height + x - pixel_group->xstart;
|
||||
added = 0;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Check pixel groups */
|
||||
for (i = 0; i < row->pixel_groups_count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
assert(row->pixel_groups[i].xstart > row->pixel_groups[i - 1].xend);
|
||||
}
|
||||
if (i < row->pixel_groups_count - 1)
|
||||
{
|
||||
assert(row->pixel_groups[i].xend < row->pixel_groups[i + 1].xstart);
|
||||
}
|
||||
assert(row->pixel_groups[i].xend >= row->pixel_groups[i].xstart);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset pixel if it had been added */
|
||||
if (added && (terrain || fallback))
|
||||
{
|
||||
if (fallback)
|
||||
{
|
||||
double* dpointer = getDataPointer(fallback, x, z, NULL, terrain, 0);
|
||||
if (dpointer)
|
||||
{
|
||||
*pixel = *dpointer;
|
||||
}
|
||||
else if (terrain)
|
||||
{
|
||||
*pixel = terrain->getGridHeight(x, z, 0);
|
||||
}
|
||||
}
|
||||
else if (terrain)
|
||||
{
|
||||
*pixel = terrain->getGridHeight(x, z, 0);
|
||||
}
|
||||
}
|
||||
return pixel;
|
||||
}
|
||||
#include "PaintedGridBrush.h"
|
||||
|
||||
TerrainHeightMap::TerrainHeightMap(TerrainDefinition* terrain):
|
||||
BaseDefinition(terrain), terrain(terrain)
|
||||
PaintedGrid(terrain), terrain(terrain)
|
||||
{
|
||||
merged_data = new TerrainHeightMapData;
|
||||
brush_data = new TerrainHeightMapData;
|
||||
_initData(merged_data);
|
||||
_initData(brush_data);
|
||||
}
|
||||
|
||||
TerrainHeightMap::~TerrainHeightMap()
|
||||
{
|
||||
_deleteData(merged_data);
|
||||
_deleteData(brush_data);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::copy(BaseDefinition* _destination) const
|
||||
|
@ -336,150 +14,40 @@ void TerrainHeightMap::copy(BaseDefinition* _destination) const
|
|||
|
||||
destination->terrain = terrain;
|
||||
|
||||
_copyData(merged_data, destination->merged_data);
|
||||
_clearData(destination->brush_data);
|
||||
PaintedGrid::copy(destination);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::save(PackStream* stream) const
|
||||
double TerrainHeightMap::getInitialValue(double x, double y) const
|
||||
{
|
||||
_saveData(stream, merged_data);
|
||||
return terrain->getInterpolatedHeight(x * terrain->scaling, y * terrain->scaling, false, false);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::load(PackStream* stream)
|
||||
void TerrainHeightMap::brushElevation(const PaintedGridBrush &brush, double x, double y, double value)
|
||||
{
|
||||
_loadData(stream, merged_data);
|
||||
_clearData(brush_data);
|
||||
PaintedGridBrushRaiseLower sbrush(brush);
|
||||
applyBrush(sbrush, x, y, value / terrain->height);
|
||||
}
|
||||
|
||||
int TerrainHeightMap::getGridHeight(int x, int z, double* result)
|
||||
void TerrainHeightMap::brushFlatten(const PaintedGridBrush &brush, double x, double y, double height, double force)
|
||||
{
|
||||
double* dpointer;
|
||||
dpointer = getDataPointer(brush_data, x, z, NULL, NULL, 0);
|
||||
if (dpointer)
|
||||
{
|
||||
*result = *dpointer;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dpointer = getDataPointer(merged_data, x, z, NULL, NULL, 0);
|
||||
if (dpointer)
|
||||
{
|
||||
*result = *dpointer;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
PaintedGridBrushFlatten sbrush(brush, height);
|
||||
applyBrush(sbrush, x, y, force / terrain->height);
|
||||
}
|
||||
|
||||
int TerrainHeightMap::getInterpolatedHeight(double x, double z, double* result)
|
||||
void TerrainHeightMap::brushSmooth(const PaintedGridBrush &brush, double x, double y, double value)
|
||||
{
|
||||
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(brush_data, x, z, NULL, NULL, 0) || getDataPointer(merged_data, x, z, NULL, NULL, 0))
|
||||
{
|
||||
hit = 1;
|
||||
}
|
||||
}
|
||||
PaintedGridBrushSmooth sbrush(brush);
|
||||
applyBrush(sbrush, x, y, value / terrain->height);
|
||||
}
|
||||
|
||||
if (hit && result)
|
||||
void TerrainHeightMap::brushAddNoise(const PaintedGridBrush &brush, double x, double y, NoiseGenerator* generator, double value)
|
||||
{
|
||||
double stencil[16];
|
||||
double value;
|
||||
for (ix = xlow - 1; ix <= xlow + 2; ix++)
|
||||
{
|
||||
for (iz = zlow - 1; iz <= zlow + 2; iz++)
|
||||
{
|
||||
if (!getGridHeight(ix, iz, &value))
|
||||
{
|
||||
value = terrain->getGridHeight(ix, iz, 0);
|
||||
}
|
||||
stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = value;
|
||||
}
|
||||
PaintedGridBrushAddNoise sbrush(brush, generator);
|
||||
applyBrush(sbrush, x, y, value / terrain->height);
|
||||
}
|
||||
|
||||
*result = Interpolation::bicubic(stencil, x - (double)xlow, z - (double)zlow);
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
unsigned long TerrainHeightMap::getMemoryStats() const
|
||||
void TerrainHeightMap::brushReset(const PaintedGridBrush &brush, double x, double y, double value)
|
||||
{
|
||||
return merged_data->memsize + brush_data->memsize;
|
||||
}
|
||||
|
||||
bool TerrainHeightMap::isPainted(int x, int z)
|
||||
{
|
||||
return getDataPointer(brush_data, x, z, NULL, NULL, 0) || getDataPointer(merged_data, x, z, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::clearPainting()
|
||||
{
|
||||
_clearData(merged_data);
|
||||
_clearData(brush_data);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushElevation(const TerrainHeightMapBrush &brush, double value)
|
||||
{
|
||||
TerrainHeightMapBrushElevation sbrush(brush);
|
||||
sbrush.apply(this, value);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushFlatten(const TerrainHeightMapBrush &brush, double height, double force)
|
||||
{
|
||||
TerrainHeightMapBrushFlatten sbrush(brush, height);
|
||||
sbrush.apply(this, force);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushSmooth(const TerrainHeightMapBrush &brush, double value)
|
||||
{
|
||||
TerrainHeightMapBrushSmooth sbrush(brush);
|
||||
sbrush.apply(this, value);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushAddNoise(const TerrainHeightMapBrush &brush, NoiseGenerator* generator, double value)
|
||||
{
|
||||
TerrainHeightMapBrushAddNoise sbrush(brush, generator);
|
||||
sbrush.apply(this, value);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushReset(const TerrainHeightMapBrush &brush, double value)
|
||||
{
|
||||
TerrainHeightMapBrushReset sbrush(brush);
|
||||
sbrush.apply(this, value);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::endBrushStroke()
|
||||
{
|
||||
int i, j, k;
|
||||
TerrainHeightMapData* data = 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 + 1; k++)
|
||||
{
|
||||
double* dpointer = getDataPointer(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(brush_data);
|
||||
PaintedGridBrushReset sbrush(brush);
|
||||
applyBrush(sbrush, x, y, value / terrain->height);
|
||||
}
|
||||
|
|
|
@ -3,49 +3,30 @@
|
|||
|
||||
#include "definition_global.h"
|
||||
|
||||
#include "BaseDefinition.h"
|
||||
#include "PaintedGrid.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
class TerrainHeightMapData;
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMap : public BaseDefinition
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMap : public PaintedGrid
|
||||
{
|
||||
public:
|
||||
TerrainHeightMap(TerrainDefinition *terrain);
|
||||
virtual ~TerrainHeightMap();
|
||||
|
||||
virtual void copy(BaseDefinition *destination) const override;
|
||||
virtual void save(PackStream* stream) const override;
|
||||
virtual void load(PackStream* stream) override;
|
||||
|
||||
inline TerrainDefinition* getTerrain() const {return terrain;}
|
||||
int getInterpolatedHeight(double x, double z, double* result);
|
||||
int getGridHeight(int x, int z, double* result);
|
||||
|
||||
bool isPainted(int x, int z);
|
||||
unsigned long getMemoryStats() const;
|
||||
virtual double getInitialValue(double x, double y) const override;
|
||||
|
||||
void clearPainting();
|
||||
void brushElevation(const TerrainHeightMapBrush &brush, double value);
|
||||
void brushSmooth(const TerrainHeightMapBrush &brush, double value);
|
||||
void brushAddNoise(const TerrainHeightMapBrush &brush, NoiseGenerator* generator, double value);
|
||||
void brushReset(const TerrainHeightMapBrush &brush, double value);
|
||||
void brushFlatten(const TerrainHeightMapBrush &brush, double height, double force);
|
||||
void endBrushStroke();
|
||||
|
||||
friend class TerrainHeightMapBrush;
|
||||
friend class TerrainHeightMapBrushSmooth;
|
||||
friend class TerrainHeightMapBrushReset;
|
||||
|
||||
protected:
|
||||
double* getDataPointer(TerrainHeightMapData* data, int x, int z, TerrainHeightMapData* fallback, TerrainDefinition* terrain, int grow);
|
||||
void brushElevation(const PaintedGridBrush &brush, double x, double y, double value);
|
||||
void brushSmooth(const PaintedGridBrush &brush, double x, double y, double value);
|
||||
void brushAddNoise(const PaintedGridBrush &brush, double x, double y, NoiseGenerator* generator, double value);
|
||||
void brushReset(const PaintedGridBrush &brush, double x, double y, double value);
|
||||
void brushFlatten(const PaintedGridBrush &brush, double x, double y, double height, double force);
|
||||
|
||||
private:
|
||||
TerrainDefinition* terrain;
|
||||
TerrainHeightMapData* merged_data;
|
||||
TerrainHeightMapData* brush_data;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
#include "TerrainHeightMapBrush.h"
|
||||
|
||||
#include "TerrainDefinition.h"
|
||||
#include "TerrainHeightMap.h"
|
||||
#include "NoiseGenerator.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int xstart;
|
||||
int xend;
|
||||
int xsize;
|
||||
int zstart;
|
||||
int zend;
|
||||
int zsize;
|
||||
} IntegerRect;
|
||||
|
||||
static inline IntegerRect _getBrushRect(TerrainHeightMapBrush* brush)
|
||||
{
|
||||
IntegerRect result;
|
||||
double s = brush->smoothed_size + brush->hard_radius;
|
||||
|
||||
result.xstart = (int)floor(brush->relative_x - s);
|
||||
result.xend = (int)ceil(brush->relative_x + s);
|
||||
result.zstart = (int)floor(brush->relative_z - s);
|
||||
result.zend = (int)ceil(brush->relative_z + s);
|
||||
|
||||
result.xsize = result.xend - result.xstart + 1;
|
||||
result.zsize = result.zend - result.zstart + 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int _isInRect(const IntegerRect &rect, int x, int z)
|
||||
{
|
||||
return (x >= rect.xstart && x <= rect.xend && z >= rect.zstart && z <= rect.zend);
|
||||
}
|
||||
|
||||
void TerrainHeightMapBrush::apply(TerrainHeightMap* heightmap, double force)
|
||||
{
|
||||
IntegerRect brush_rect = _getBrushRect(this);
|
||||
int x, z;
|
||||
double dx, dz, distance, influence;
|
||||
|
||||
force /= heightmap->terrain->height;
|
||||
|
||||
for (x = brush_rect.xstart; x <= brush_rect.xend; x++)
|
||||
{
|
||||
dx = (double)x;
|
||||
for (z = brush_rect.zstart; z <= brush_rect.zend; z++)
|
||||
{
|
||||
dz = (double)z;
|
||||
distance = sqrt((relative_x - dx) * (relative_x - dx) + (relative_z - dz) * (relative_z - dz));
|
||||
|
||||
if (distance > hard_radius)
|
||||
{
|
||||
if (distance <= hard_radius + smoothed_size)
|
||||
{
|
||||
influence = (1.0 - (distance - hard_radius) / smoothed_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
influence = 1.0;
|
||||
}
|
||||
|
||||
double* dpointer = heightmap->getDataPointer(heightmap->brush_data, x, z, heightmap->merged_data, heightmap->terrain, 1);
|
||||
*dpointer = getBrushValue(heightmap, dx, dz, *dpointer, influence, force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double TerrainHeightMapBrush::getBrushValue(TerrainHeightMap*, double, double, double basevalue, double, double) const
|
||||
{
|
||||
return basevalue;
|
||||
}
|
||||
|
||||
double TerrainHeightMapBrushElevation::getBrushValue(TerrainHeightMap*, double, double, double basevalue, double influence, double force) const
|
||||
{
|
||||
return basevalue + influence * force;
|
||||
}
|
||||
|
||||
double TerrainHeightMapBrushSmooth::getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const
|
||||
{
|
||||
TerrainDefinition* terrain = heightmap->terrain;
|
||||
double ideal, factor;
|
||||
ideal = terrain->getInterpolatedHeight((x + total_radius * 0.5) * terrain->scaling, z * terrain->scaling, 0, 1);
|
||||
ideal += terrain->getInterpolatedHeight((x - total_radius * 0.5) * terrain->scaling, z * terrain->scaling, 0, 1);
|
||||
ideal += terrain->getInterpolatedHeight(x * terrain->scaling, (z - total_radius * 0.5) * terrain->scaling, 0, 1);
|
||||
ideal += terrain->getInterpolatedHeight(x * terrain->scaling, (z + total_radius * 0.5) * terrain->scaling, 0, 1);
|
||||
ideal /= 4.0;
|
||||
factor = influence * force;
|
||||
if (factor > 1.0)
|
||||
{
|
||||
factor = 0.0;
|
||||
}
|
||||
return basevalue + (ideal - basevalue) * factor;
|
||||
}
|
||||
|
||||
double TerrainHeightMapBrushAddNoise::getBrushValue(TerrainHeightMap*, double x, double z, double basevalue, double influence, double force) const
|
||||
{
|
||||
return basevalue + generator->get2DTotal(x / total_radius, z / total_radius) * influence * force * total_radius;
|
||||
}
|
||||
|
||||
double TerrainHeightMapBrushReset::getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const
|
||||
{
|
||||
TerrainDefinition* terrain = heightmap->terrain;
|
||||
double ideal = terrain->getInterpolatedHeight(x * terrain->scaling, z * terrain->scaling, 0, 0);
|
||||
return basevalue + (ideal - basevalue) * influence * force;
|
||||
}
|
||||
|
||||
double TerrainHeightMapBrushFlatten::getBrushValue(TerrainHeightMap*, double, double, double basevalue, double influence, double force) const
|
||||
{
|
||||
double ideal = height;
|
||||
return basevalue + (ideal - basevalue) * influence * force;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#ifndef TERRAINHEIGHTMAPBRUSH_H
|
||||
#define TERRAINHEIGHTMAPBRUSH_H
|
||||
|
||||
#include "definition_global.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMapBrush
|
||||
{
|
||||
public:
|
||||
TerrainHeightMapBrush() {}
|
||||
TerrainHeightMapBrush(double relative_x, double relative_z, double hard_radius, double smoothed_size, double total_radius):
|
||||
relative_x(relative_x), relative_z(relative_z), hard_radius(hard_radius), smoothed_size(smoothed_size), total_radius(total_radius) {}
|
||||
|
||||
void apply(TerrainHeightMap* heightmap, double force);
|
||||
|
||||
protected:
|
||||
virtual double getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const;
|
||||
|
||||
public:
|
||||
double relative_x;
|
||||
double relative_z;
|
||||
double hard_radius;
|
||||
double smoothed_size;
|
||||
double total_radius;
|
||||
};
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMapBrushElevation: public TerrainHeightMapBrush
|
||||
{
|
||||
public:
|
||||
TerrainHeightMapBrushElevation(const TerrainHeightMapBrush& brush) : TerrainHeightMapBrush(brush) {}
|
||||
protected:
|
||||
double getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const override;
|
||||
};
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMapBrushSmooth: public TerrainHeightMapBrush
|
||||
{
|
||||
public:
|
||||
TerrainHeightMapBrushSmooth(const TerrainHeightMapBrush& brush) : TerrainHeightMapBrush(brush) {}
|
||||
protected:
|
||||
double getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const override;
|
||||
};
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMapBrushAddNoise: public TerrainHeightMapBrush
|
||||
{
|
||||
public:
|
||||
TerrainHeightMapBrushAddNoise(NoiseGenerator* generator) : generator(generator) {}
|
||||
TerrainHeightMapBrushAddNoise(const TerrainHeightMapBrush& brush, NoiseGenerator* generator) : TerrainHeightMapBrush(brush), generator(generator) {}
|
||||
protected:
|
||||
double getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const override;
|
||||
private:
|
||||
NoiseGenerator* generator;
|
||||
};
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMapBrushReset: public TerrainHeightMapBrush
|
||||
{
|
||||
public:
|
||||
TerrainHeightMapBrushReset(const TerrainHeightMapBrush& brush) : TerrainHeightMapBrush(brush) {}
|
||||
protected:
|
||||
double getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const override;
|
||||
};
|
||||
|
||||
class DEFINITIONSHARED_EXPORT TerrainHeightMapBrushFlatten: public TerrainHeightMapBrush
|
||||
{
|
||||
public:
|
||||
TerrainHeightMapBrushFlatten(double height) : height(height) {}
|
||||
TerrainHeightMapBrushFlatten(const TerrainHeightMapBrush& brush, double height) : TerrainHeightMapBrush(brush), height(height) {}
|
||||
protected:
|
||||
double getBrushValue(TerrainHeightMap* heightmap, double x, double z, double basevalue, double influence, double force) const override;
|
||||
private:
|
||||
double height;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TERRAINHEIGHTMAPBRUSH_H
|
|
@ -5,22 +5,6 @@
|
|||
#include "PackStream.h"
|
||||
#include "Vector3.h"
|
||||
|
||||
#define MAX_CIRCLES 10
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
class Circle
|
||||
{
|
||||
public:
|
||||
double value;
|
||||
double centerx;
|
||||
double centerz;
|
||||
double softradius;
|
||||
double hardradius;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Zone::Zone(BaseDefinition *parent):
|
||||
BaseDefinition(parent)
|
||||
{
|
||||
|
@ -29,21 +13,16 @@ Zone::Zone(BaseDefinition *parent):
|
|||
value_by_height->setDefault(1.0);
|
||||
value_by_slope = new Curve;
|
||||
value_by_slope->setDefault(1.0);
|
||||
circles_included_count = 0;
|
||||
circles_included = new Circle[MAX_CIRCLES];
|
||||
}
|
||||
|
||||
Zone::~Zone()
|
||||
{
|
||||
delete value_by_height;
|
||||
delete value_by_slope;
|
||||
delete circles_included;
|
||||
}
|
||||
|
||||
void Zone::save(PackStream* stream) const
|
||||
{
|
||||
int i;
|
||||
|
||||
stream->write(&absolute_height);
|
||||
stream->write(&relative_height_min);
|
||||
stream->write(&relative_height_middle);
|
||||
|
@ -51,22 +30,10 @@ void Zone::save(PackStream* stream) const
|
|||
|
||||
value_by_height->save(stream);
|
||||
value_by_slope->save(stream);
|
||||
|
||||
stream->write(&circles_included_count);
|
||||
for (i = 0; i < circles_included_count; i++)
|
||||
{
|
||||
stream->write(&circles_included[i].value);
|
||||
stream->write(&circles_included[i].centerx);
|
||||
stream->write(&circles_included[i].centerz);
|
||||
stream->write(&circles_included[i].softradius);
|
||||
stream->write(&circles_included[i].hardradius);
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::load(PackStream* stream)
|
||||
{
|
||||
int i;
|
||||
|
||||
stream->read(&absolute_height);
|
||||
stream->read(&relative_height_min);
|
||||
stream->read(&relative_height_middle);
|
||||
|
@ -74,16 +41,6 @@ void Zone::load(PackStream* stream)
|
|||
|
||||
value_by_height->load(stream);
|
||||
value_by_slope->load(stream);
|
||||
|
||||
stream->read(&circles_included_count);
|
||||
for (i = 0; i < circles_included_count; i++)
|
||||
{
|
||||
stream->read(&circles_included[i].value);
|
||||
stream->read(&circles_included[i].centerx);
|
||||
stream->read(&circles_included[i].centerz);
|
||||
stream->read(&circles_included[i].softradius);
|
||||
stream->read(&circles_included[i].hardradius);
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::copy(BaseDefinition* _destination) const
|
||||
|
@ -97,16 +54,12 @@ void Zone::copy(BaseDefinition* _destination) const
|
|||
|
||||
value_by_height->copy(destination->value_by_height);
|
||||
value_by_slope->copy(destination->value_by_slope);
|
||||
|
||||
memcpy(destination->circles_included, circles_included, sizeof(Circle) * circles_included_count);
|
||||
destination->circles_included_count = circles_included_count;
|
||||
}
|
||||
|
||||
void Zone::clear()
|
||||
{
|
||||
value_by_height->clear();
|
||||
value_by_slope->clear();
|
||||
circles_included_count = 0;
|
||||
}
|
||||
|
||||
void Zone::setAbsoluteHeight()
|
||||
|
@ -135,16 +88,6 @@ void Zone::setRelativeHeight(double min, double middle, double max)
|
|||
relative_height_max = max;
|
||||
}
|
||||
|
||||
void Zone::includeCircleArea(double value, double centerx, double centerz, double softradius, double hardradius)
|
||||
{
|
||||
Circle circle = {value, centerx, centerz, softradius, hardradius};
|
||||
|
||||
if (circles_included_count < MAX_CIRCLES)
|
||||
{
|
||||
circles_included[circles_included_count++] = circle;
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::getHeightCurve(Curve* curve) const
|
||||
{
|
||||
value_by_height->copy(curve);
|
||||
|
@ -181,50 +124,10 @@ void Zone::addSlopeRangeQuick(double value, double hardmin, double softmin, doub
|
|||
value_by_slope->addPoint(hardmax, 0.0);
|
||||
}
|
||||
|
||||
static inline double _getCircleInfluence(const Circle &circle, const Vector3 &position)
|
||||
{
|
||||
double radius, dx, dz;
|
||||
|
||||
dx = position.x - circle.centerx;
|
||||
dz = position.z - circle.centerz;
|
||||
radius = sqrt(dx * dx + dz * dz);
|
||||
|
||||
if (radius > circle.hardradius)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
else if (radius < circle.softradius)
|
||||
{
|
||||
return circle.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return circle.value * (circle.hardradius - radius) / (circle.hardradius - circle.softradius);
|
||||
}
|
||||
}
|
||||
|
||||
double Zone::getValue(const Vector3 &location, const Vector3 &normal) const
|
||||
{
|
||||
int i;
|
||||
double final_height;
|
||||
double value, value_height, value_steepness, value_circle;
|
||||
|
||||
if (circles_included_count > 0)
|
||||
{
|
||||
value_circle = 0.0;
|
||||
for (i = 0; i < circles_included_count; i++)
|
||||
{
|
||||
value = _getCircleInfluence(circles_included[i], location);
|
||||
if (value > value_circle)
|
||||
{
|
||||
value_circle = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value_circle = 1.0;
|
||||
}
|
||||
double value_height, value_steepness;
|
||||
|
||||
if (absolute_height)
|
||||
{
|
||||
|
@ -254,26 +157,12 @@ double Zone::getValue(const Vector3 &location, const Vector3 &normal) const
|
|||
value_steepness = value_by_slope->getValue(1.0 - normal.y);
|
||||
|
||||
if (value_steepness < value_height)
|
||||
{
|
||||
if (value_circle < value_steepness)
|
||||
{
|
||||
return value_circle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value_steepness;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value_circle < value_height)
|
||||
{
|
||||
return value_circle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
class Circle;
|
||||
|
||||
class DEFINITIONSHARED_EXPORT Zone : public BaseDefinition
|
||||
{
|
||||
public:
|
||||
|
@ -26,9 +24,6 @@ public:
|
|||
void setAbsoluteHeight();
|
||||
void setRelativeHeight(double min, double middle, double max);
|
||||
|
||||
void includeCircleArea(double value, double centerx, double centerz, double softradius, double hardradius);
|
||||
void excludeCircleArea(double centerx, double centerz, double softradius, double hardradius);
|
||||
|
||||
void getHeightCurve(Curve* curve) const;
|
||||
void setHeightCurve(Curve* curve);
|
||||
void addHeightRangeQuick(double value, double hardmin, double softmin, double softmax, double hardmax);
|
||||
|
@ -47,9 +42,6 @@ private:
|
|||
|
||||
Curve* value_by_height;
|
||||
Curve* value_by_slope;
|
||||
|
||||
Circle* circles_included;
|
||||
int circles_included_count;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -27,8 +27,10 @@ SOURCES += \
|
|||
Zone.cpp \
|
||||
TerrainDefinition.cpp \
|
||||
TerrainHeightMap.cpp \
|
||||
TerrainHeightMapBrush.cpp \
|
||||
Scenery.cpp
|
||||
Scenery.cpp \
|
||||
PaintedGrid.cpp \
|
||||
PaintedGridBrush.cpp \
|
||||
PaintedGridData.cpp
|
||||
|
||||
HEADERS +=\
|
||||
definition_global.h \
|
||||
|
@ -45,8 +47,10 @@ HEADERS +=\
|
|||
Zone.h \
|
||||
TerrainDefinition.h \
|
||||
TerrainHeightMap.h \
|
||||
TerrainHeightMapBrush.h \
|
||||
Scenery.h
|
||||
Scenery.h \
|
||||
PaintedGrid.h \
|
||||
PaintedGridBrush.h \
|
||||
PaintedGridData.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
|
|
@ -27,12 +27,14 @@ namespace definition {
|
|||
class TextureLayerDefinition;
|
||||
class TerrainDefinition;
|
||||
class TerrainHeightMap;
|
||||
class TerrainHeightMapBrush;
|
||||
class TerrainHeightMapBrushElevation;
|
||||
class TerrainHeightMapBrushSmooth;
|
||||
class TerrainHeightMapBrushAddNoise;
|
||||
class TerrainHeightMapBrushReset;
|
||||
class TerrainHeightMapBrushFlatten;
|
||||
class PaintedGrid;
|
||||
class PaintedGridData;
|
||||
class PaintedGridBrush;
|
||||
class PaintedGridBrushRaiseLower;
|
||||
class PaintedGridBrushSmooth;
|
||||
class PaintedGridBrushAddNoise;
|
||||
class PaintedGridBrushReset;
|
||||
class PaintedGridBrushFlatten;
|
||||
}
|
||||
}
|
||||
using namespace paysages::definition;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "NoiseGenerator.h"
|
||||
#include "TerrainDefinition.h"
|
||||
#include "TerrainHeightMap.h"
|
||||
#include "TerrainHeightMapBrush.h"
|
||||
#include "PaintedGridBrush.h"
|
||||
|
||||
PaintingBrush::PaintingBrush()
|
||||
{
|
||||
|
@ -104,13 +104,12 @@ QString PaintingBrush::getHelpText()
|
|||
void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double z, double duration, bool reverse)
|
||||
{
|
||||
double brush_strength;
|
||||
TerrainHeightMapBrush brush;
|
||||
|
||||
brush.relative_x = x;
|
||||
brush.relative_z = z;
|
||||
brush.hard_radius = _size * (1.0 - _smoothing);
|
||||
brush.smoothed_size = _size * _smoothing;
|
||||
brush.total_radius = brush.hard_radius + brush.smoothed_size;
|
||||
double hard_radius = _size * (1.0 - _smoothing);
|
||||
double smoothed_size = _size * _smoothing;
|
||||
double total_radius = hard_radius + smoothed_size;
|
||||
|
||||
PaintedGridBrush brush(hard_radius, smoothed_size, total_radius);
|
||||
|
||||
brush_strength = 0.5 * _strength * duration / 0.1;
|
||||
|
||||
|
@ -121,16 +120,16 @@ void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double
|
|||
{
|
||||
brush_strength = -brush_strength;
|
||||
}
|
||||
terrain->height_map->brushElevation(brush, brush_strength * 2.0);
|
||||
terrain->height_map->brushElevation(brush, x, z, brush_strength * 2.0);
|
||||
break;
|
||||
case PAINTING_BRUSH_SMOOTH:
|
||||
if (reverse)
|
||||
{
|
||||
terrain->height_map->brushSmooth(brush, brush_strength * 30.0);
|
||||
terrain->height_map->brushSmooth(brush, x, z, brush_strength * 30.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
terrain->height_map->brushAddNoise(brush, _noise, brush_strength * 0.3);
|
||||
terrain->height_map->brushAddNoise(brush, x, z, _noise, brush_strength * 0.3);
|
||||
}
|
||||
break;
|
||||
case PAINTING_BRUSH_FLATTEN:
|
||||
|
@ -140,11 +139,11 @@ void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double
|
|||
}
|
||||
else
|
||||
{
|
||||
terrain->height_map->brushFlatten(brush, _height, brush_strength * 30.0);
|
||||
terrain->height_map->brushFlatten(brush, x, z, _height, brush_strength * 30.0);
|
||||
}
|
||||
break;
|
||||
case PAINTING_BRUSH_RESTORE:
|
||||
terrain->height_map->brushReset(brush, brush_strength * 30.0);
|
||||
terrain->height_map->brushReset(brush, x, z, brush_strength * 30.0);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "NoiseGenerator.h"
|
||||
#include "TerrainDefinition.h"
|
||||
#include "TerrainHeightMap.h"
|
||||
#include "TerrainHeightMapBrush.h"
|
||||
#include "PaintedGridBrush.h"
|
||||
|
||||
/* Noise sin period is defined at 20.0 */
|
||||
#define X_FACTOR (M_PI / 10.0)
|
||||
|
@ -90,7 +90,7 @@ TEST_F(TerrainPainting_Test, grid)
|
|||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(3, 0, 1, 0), 6.0 * sin(1.5 * X_FACTOR));
|
||||
}
|
||||
|
||||
static void _checkBrushResultSides(TerrainDefinition* terrain, TerrainHeightMapBrush*, double center, double midhard, double hard, double midsoft, double soft, double exter, double neg_midhard, double neg_hard, double neg_midsoft, double neg_soft, double neg_exter)
|
||||
static void _checkBrushResultSides(TerrainDefinition* terrain, PaintedGridBrush*, double center, double midhard, double hard, double midsoft, double soft, double exter, double neg_midhard, double neg_hard, double neg_midsoft, double neg_soft, double neg_exter)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(terrain->getGridHeight(0, 0, 1), center);
|
||||
|
||||
|
@ -107,7 +107,7 @@ static void _checkBrushResultSides(TerrainDefinition* terrain, TerrainHeightMapB
|
|||
EXPECT_DOUBLE_EQ(terrain->getGridHeight(-5, 0, 1), neg_exter);
|
||||
}
|
||||
|
||||
static void _checkBrushResult(TerrainDefinition* terrain, TerrainHeightMapBrush* brush, double center, double midhard, double hard, double midsoft, double soft, double exter, int mirror)
|
||||
static void _checkBrushResult(TerrainDefinition* terrain, PaintedGridBrush* brush, double center, double midhard, double hard, double midsoft, double soft, double exter, int mirror)
|
||||
{
|
||||
if (mirror)
|
||||
{
|
||||
|
@ -122,31 +122,31 @@ static void _checkBrushResult(TerrainDefinition* terrain, TerrainHeightMapBrush*
|
|||
TEST_F(TerrainPainting_Test, brush_flatten)
|
||||
{
|
||||
/* Set up */
|
||||
TerrainHeightMapBrush brush(0.0, 0.0, 2.0, 2.0, 4.0);
|
||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||
terrain->height = 1.0;
|
||||
terrain->scaling = 1.0;
|
||||
terrain->_height_noise->forceValue(0.0);
|
||||
|
||||
/* Test flattening center at 0.5 */
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||
terrain->height_map->brushFlatten(brush, 0.5, 1.0);
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 0.5, 0.5, 0.5, 0.25, 0.0, 0.0, 0);
|
||||
|
||||
/* Test brush strength */
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||
terrain->height_map->brushFlatten(brush, 0.5, 0.01);
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 0.01);
|
||||
_checkBrushResult(terrain, &brush, 0.005, 0.005, 0.005, 0.0025, 0.0, 0.0, 0);
|
||||
|
||||
/* Test cumulative effect */
|
||||
terrain->height_map->brushFlatten(brush, 0.5, 0.01);
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 0.01);
|
||||
_checkBrushResult(terrain, &brush, 0.00995, 0.00995, 0.00995, 0.0049875, 0.0, 0.0, 0);
|
||||
|
||||
/* Test with height modifier */
|
||||
terrain->height = 10.0;
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||
terrain->height_map->brushFlatten(brush, 0.5, 1.0);
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
||||
|
||||
/* Test with scaling modifier */
|
||||
|
@ -154,45 +154,45 @@ TEST_F(TerrainPainting_Test, brush_flatten)
|
|||
terrain->scaling = 2.0;
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||
terrain->height_map->brushFlatten(brush, 0.5, 1.0);
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
||||
}
|
||||
|
||||
TEST_F(TerrainPainting_Test, brush_reset)
|
||||
{
|
||||
/* Set up */
|
||||
TerrainHeightMapBrush brush(0.0, 0.0, 2.0, 2.0, 4.0);
|
||||
TerrainHeightMapBrush brush_full(0.0, 0.0, 4.0, 0.0, 4.0);
|
||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
||||
terrain->height = 1.0;
|
||||
terrain->scaling = 1.0;
|
||||
terrain->_height_noise->forceValue(1.0);
|
||||
|
||||
/* Test resetting at center */
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
||||
terrain->height_map->brushFlatten(brush_full, 2.0, 1.0);
|
||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 0);
|
||||
terrain->height_map->brushReset(brush, 1.0);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.5, 2.0, 1.0, 0);
|
||||
|
||||
/* Test brush strength */
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
||||
terrain->height_map->brushFlatten(brush_full, 2.0, 1.0);
|
||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 0);
|
||||
terrain->height_map->brushReset(brush, 0.1);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
||||
_checkBrushResult(terrain, &brush, 1.9, 1.9, 1.9, 1.95, 2.0, 1.0, 0);
|
||||
|
||||
/* Test cumulative effect */
|
||||
terrain->height_map->brushReset(brush, 0.1);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
||||
_checkBrushResult(terrain, &brush, 1.81, 1.81, 1.81, 1.9025, 2.0, 1.0, 0);
|
||||
|
||||
/* Test with height modifier */
|
||||
terrain->height = 10.0;
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
||||
terrain->height_map->brushFlatten(brush_full, 2.0, 1.0);
|
||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 1.1, 1.1, 1.1, 1.1, 1.1, 1.0, 0);
|
||||
terrain->height_map->brushReset(brush, 0.1);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
||||
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
||||
|
||||
/* Test with scaling modifier */
|
||||
|
@ -200,17 +200,17 @@ TEST_F(TerrainPainting_Test, brush_reset)
|
|||
terrain->scaling = 2.0;
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
||||
terrain->height_map->brushFlatten(brush_full, 2.0, 1.0);
|
||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
||||
_checkBrushResult(terrain, &brush, 1.1, 1.1, 1.1, 1.1, 1.1, 1.0, 0);
|
||||
terrain->height_map->brushReset(brush, 0.1);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
||||
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
||||
}
|
||||
|
||||
TEST_F(TerrainPainting_Test, brush_reset_basevalue)
|
||||
{
|
||||
/* Set up */
|
||||
TerrainHeightMapBrush brush(0.0, 0.0, 2.0, 2.0, 4.0);
|
||||
TerrainHeightMapBrush brush_full(0.0, 0.0, 4.0, 0.0, 4.0);
|
||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
||||
terrain->height = 1.0;
|
||||
terrain->scaling = 1.0;
|
||||
|
||||
|
@ -218,8 +218,8 @@ TEST_F(TerrainPainting_Test, brush_reset_basevalue)
|
|||
terrain->height = 1.0;
|
||||
terrain->scaling = 2.0;
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.309016994375, 0.587785252292, 0.809016994375, 0.951056516295, 1.0, 1);
|
||||
terrain->height_map->brushFlatten(brush_full, 2.0, 1.0);
|
||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
||||
_checkBrushResultSides(terrain, &brush, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, -1.0);
|
||||
terrain->height_map->brushReset(brush, 1.0);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 1.0);
|
||||
_checkBrushResultSides(terrain, &brush, 0.0, 0.309016994375, 0.587785252292, 2.0 - (2.0 - 0.809016994375) * 0.5, 2.0, 1.0, -0.309016994375, -0.587785252292, 2.0 - (2.0 + 0.809016994375) * 0.5, 2.0, -1.0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue