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;
|
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);
|
h = _height_noise->get2DTotal((double)x, (double)z);
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, int scaled,
|
||||||
x /= scaling;
|
x /= scaling;
|
||||||
z /= 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);
|
h = _height_noise->get2DTotal(x, z);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,333 +1,11 @@
|
||||||
#include "TerrainHeightMap.h"
|
#include "TerrainHeightMap.h"
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstring>
|
|
||||||
#include "PackStream.h"
|
|
||||||
#include "Memory.h"
|
|
||||||
#include "TerrainDefinition.h"
|
#include "TerrainDefinition.h"
|
||||||
#include "TerrainHeightMapBrush.h"
|
#include "PaintedGridBrush.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
TerrainHeightMap::TerrainHeightMap(TerrainDefinition* terrain):
|
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
|
void TerrainHeightMap::copy(BaseDefinition* _destination) const
|
||||||
|
@ -336,150 +14,40 @@ void TerrainHeightMap::copy(BaseDefinition* _destination) const
|
||||||
|
|
||||||
destination->terrain = terrain;
|
destination->terrain = terrain;
|
||||||
|
|
||||||
_copyData(merged_data, destination->merged_data);
|
PaintedGrid::copy(destination);
|
||||||
_clearData(destination->brush_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
PaintedGridBrushRaiseLower sbrush(brush);
|
||||||
_clearData(brush_data);
|
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;
|
PaintedGridBrushFlatten sbrush(brush, height);
|
||||||
dpointer = getDataPointer(brush_data, x, z, NULL, NULL, 0);
|
applyBrush(sbrush, x, y, force / terrain->height);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int TerrainHeightMap::getInterpolatedHeight(double x, double z, double* result)
|
void TerrainHeightMap::brushSmooth(const PaintedGridBrush &brush, double x, double y, double value)
|
||||||
{
|
{
|
||||||
int ix, iz;
|
PaintedGridBrushSmooth sbrush(brush);
|
||||||
int xlow;
|
applyBrush(sbrush, x, y, value / terrain->height);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit && result)
|
|
||||||
{
|
|
||||||
double stencil[16];
|
|
||||||
double value;
|
|
||||||
for (ix = xlow - 1; ix <= xlow + 2; ix++)
|
|
||||||
{
|
|
||||||
for (iz = zlow - 1; iz <= zlow + 2; iz++)
|
|
||||||
{
|
|
||||||
if (!getGridHeight(ix, iz, &value))
|
|
||||||
{
|
|
||||||
value = terrain->getGridHeight(ix, iz, 0);
|
|
||||||
}
|
|
||||||
stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*result = Interpolation::bicubic(stencil, x - (double)xlow, z - (double)zlow);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long TerrainHeightMap::getMemoryStats() const
|
void TerrainHeightMap::brushAddNoise(const PaintedGridBrush &brush, double x, double y, NoiseGenerator* generator, double value)
|
||||||
{
|
{
|
||||||
return merged_data->memsize + brush_data->memsize;
|
PaintedGridBrushAddNoise sbrush(brush, generator);
|
||||||
|
applyBrush(sbrush, x, y, value / terrain->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TerrainHeightMap::isPainted(int x, int z)
|
void TerrainHeightMap::brushReset(const PaintedGridBrush &brush, double x, double y, double value)
|
||||||
{
|
{
|
||||||
return getDataPointer(brush_data, x, z, NULL, NULL, 0) || getDataPointer(merged_data, x, z, NULL, NULL, 0);
|
PaintedGridBrushReset sbrush(brush);
|
||||||
}
|
applyBrush(sbrush, x, y, value / terrain->height);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,49 +3,30 @@
|
||||||
|
|
||||||
#include "definition_global.h"
|
#include "definition_global.h"
|
||||||
|
|
||||||
#include "BaseDefinition.h"
|
#include "PaintedGrid.h"
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace definition {
|
namespace definition {
|
||||||
|
|
||||||
class TerrainHeightMapData;
|
class DEFINITIONSHARED_EXPORT TerrainHeightMap : public PaintedGrid
|
||||||
|
|
||||||
class DEFINITIONSHARED_EXPORT TerrainHeightMap : public BaseDefinition
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TerrainHeightMap(TerrainDefinition* terrain);
|
TerrainHeightMap(TerrainDefinition *terrain);
|
||||||
virtual ~TerrainHeightMap();
|
|
||||||
|
|
||||||
virtual void copy(BaseDefinition* destination) const override;
|
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;}
|
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);
|
virtual double getInitialValue(double x, double y) const override;
|
||||||
unsigned long getMemoryStats() const;
|
|
||||||
|
|
||||||
void clearPainting();
|
void brushElevation(const PaintedGridBrush &brush, double x, double y, double value);
|
||||||
void brushElevation(const TerrainHeightMapBrush &brush, double value);
|
void brushSmooth(const PaintedGridBrush &brush, double x, double y, double value);
|
||||||
void brushSmooth(const TerrainHeightMapBrush &brush, double value);
|
void brushAddNoise(const PaintedGridBrush &brush, double x, double y, NoiseGenerator* generator, double value);
|
||||||
void brushAddNoise(const TerrainHeightMapBrush &brush, NoiseGenerator* generator, double value);
|
void brushReset(const PaintedGridBrush &brush, double x, double y, double value);
|
||||||
void brushReset(const TerrainHeightMapBrush &brush, double value);
|
void brushFlatten(const PaintedGridBrush &brush, double x, double y, double height, double force);
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TerrainDefinition* terrain;
|
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 "PackStream.h"
|
||||||
#include "Vector3.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):
|
Zone::Zone(BaseDefinition *parent):
|
||||||
BaseDefinition(parent)
|
BaseDefinition(parent)
|
||||||
{
|
{
|
||||||
|
@ -29,21 +13,16 @@ Zone::Zone(BaseDefinition *parent):
|
||||||
value_by_height->setDefault(1.0);
|
value_by_height->setDefault(1.0);
|
||||||
value_by_slope = new Curve;
|
value_by_slope = new Curve;
|
||||||
value_by_slope->setDefault(1.0);
|
value_by_slope->setDefault(1.0);
|
||||||
circles_included_count = 0;
|
|
||||||
circles_included = new Circle[MAX_CIRCLES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Zone::~Zone()
|
Zone::~Zone()
|
||||||
{
|
{
|
||||||
delete value_by_height;
|
delete value_by_height;
|
||||||
delete value_by_slope;
|
delete value_by_slope;
|
||||||
delete circles_included;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zone::save(PackStream* stream) const
|
void Zone::save(PackStream* stream) const
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
stream->write(&absolute_height);
|
stream->write(&absolute_height);
|
||||||
stream->write(&relative_height_min);
|
stream->write(&relative_height_min);
|
||||||
stream->write(&relative_height_middle);
|
stream->write(&relative_height_middle);
|
||||||
|
@ -51,22 +30,10 @@ void Zone::save(PackStream* stream) const
|
||||||
|
|
||||||
value_by_height->save(stream);
|
value_by_height->save(stream);
|
||||||
value_by_slope->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)
|
void Zone::load(PackStream* stream)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
stream->read(&absolute_height);
|
stream->read(&absolute_height);
|
||||||
stream->read(&relative_height_min);
|
stream->read(&relative_height_min);
|
||||||
stream->read(&relative_height_middle);
|
stream->read(&relative_height_middle);
|
||||||
|
@ -74,16 +41,6 @@ void Zone::load(PackStream* stream)
|
||||||
|
|
||||||
value_by_height->load(stream);
|
value_by_height->load(stream);
|
||||||
value_by_slope->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
|
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_height->copy(destination->value_by_height);
|
||||||
value_by_slope->copy(destination->value_by_slope);
|
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()
|
void Zone::clear()
|
||||||
{
|
{
|
||||||
value_by_height->clear();
|
value_by_height->clear();
|
||||||
value_by_slope->clear();
|
value_by_slope->clear();
|
||||||
circles_included_count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zone::setAbsoluteHeight()
|
void Zone::setAbsoluteHeight()
|
||||||
|
@ -135,16 +88,6 @@ void Zone::setRelativeHeight(double min, double middle, double max)
|
||||||
relative_height_max = 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
|
void Zone::getHeightCurve(Curve* curve) const
|
||||||
{
|
{
|
||||||
value_by_height->copy(curve);
|
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);
|
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
|
double Zone::getValue(const Vector3 &location, const Vector3 &normal) const
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
double final_height;
|
double final_height;
|
||||||
double value, value_height, value_steepness, value_circle;
|
double value_height, value_steepness;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (absolute_height)
|
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);
|
value_steepness = value_by_slope->getValue(1.0 - normal.y);
|
||||||
|
|
||||||
if (value_steepness < value_height)
|
if (value_steepness < value_height)
|
||||||
{
|
|
||||||
if (value_circle < value_steepness)
|
|
||||||
{
|
|
||||||
return value_circle;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return value_steepness;
|
return value_steepness;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (value_circle < value_height)
|
|
||||||
{
|
|
||||||
return value_circle;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return value_height;
|
return value_height;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace definition {
|
namespace definition {
|
||||||
|
|
||||||
class Circle;
|
|
||||||
|
|
||||||
class DEFINITIONSHARED_EXPORT Zone : public BaseDefinition
|
class DEFINITIONSHARED_EXPORT Zone : public BaseDefinition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -26,9 +24,6 @@ public:
|
||||||
void setAbsoluteHeight();
|
void setAbsoluteHeight();
|
||||||
void setRelativeHeight(double min, double middle, double max);
|
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 getHeightCurve(Curve* curve) const;
|
||||||
void setHeightCurve(Curve* curve);
|
void setHeightCurve(Curve* curve);
|
||||||
void addHeightRangeQuick(double value, double hardmin, double softmin, double softmax, double hardmax);
|
void addHeightRangeQuick(double value, double hardmin, double softmin, double softmax, double hardmax);
|
||||||
|
@ -47,9 +42,6 @@ private:
|
||||||
|
|
||||||
Curve* value_by_height;
|
Curve* value_by_height;
|
||||||
Curve* value_by_slope;
|
Curve* value_by_slope;
|
||||||
|
|
||||||
Circle* circles_included;
|
|
||||||
int circles_included_count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,10 @@ SOURCES += \
|
||||||
Zone.cpp \
|
Zone.cpp \
|
||||||
TerrainDefinition.cpp \
|
TerrainDefinition.cpp \
|
||||||
TerrainHeightMap.cpp \
|
TerrainHeightMap.cpp \
|
||||||
TerrainHeightMapBrush.cpp \
|
Scenery.cpp \
|
||||||
Scenery.cpp
|
PaintedGrid.cpp \
|
||||||
|
PaintedGridBrush.cpp \
|
||||||
|
PaintedGridData.cpp
|
||||||
|
|
||||||
HEADERS +=\
|
HEADERS +=\
|
||||||
definition_global.h \
|
definition_global.h \
|
||||||
|
@ -45,8 +47,10 @@ HEADERS +=\
|
||||||
Zone.h \
|
Zone.h \
|
||||||
TerrainDefinition.h \
|
TerrainDefinition.h \
|
||||||
TerrainHeightMap.h \
|
TerrainHeightMap.h \
|
||||||
TerrainHeightMapBrush.h \
|
Scenery.h \
|
||||||
Scenery.h
|
PaintedGrid.h \
|
||||||
|
PaintedGridBrush.h \
|
||||||
|
PaintedGridData.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
maemo5 {
|
maemo5 {
|
||||||
|
|
|
@ -27,12 +27,14 @@ namespace definition {
|
||||||
class TextureLayerDefinition;
|
class TextureLayerDefinition;
|
||||||
class TerrainDefinition;
|
class TerrainDefinition;
|
||||||
class TerrainHeightMap;
|
class TerrainHeightMap;
|
||||||
class TerrainHeightMapBrush;
|
class PaintedGrid;
|
||||||
class TerrainHeightMapBrushElevation;
|
class PaintedGridData;
|
||||||
class TerrainHeightMapBrushSmooth;
|
class PaintedGridBrush;
|
||||||
class TerrainHeightMapBrushAddNoise;
|
class PaintedGridBrushRaiseLower;
|
||||||
class TerrainHeightMapBrushReset;
|
class PaintedGridBrushSmooth;
|
||||||
class TerrainHeightMapBrushFlatten;
|
class PaintedGridBrushAddNoise;
|
||||||
|
class PaintedGridBrushReset;
|
||||||
|
class PaintedGridBrushFlatten;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using namespace paysages::definition;
|
using namespace paysages::definition;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "NoiseGenerator.h"
|
#include "NoiseGenerator.h"
|
||||||
#include "TerrainDefinition.h"
|
#include "TerrainDefinition.h"
|
||||||
#include "TerrainHeightMap.h"
|
#include "TerrainHeightMap.h"
|
||||||
#include "TerrainHeightMapBrush.h"
|
#include "PaintedGridBrush.h"
|
||||||
|
|
||||||
PaintingBrush::PaintingBrush()
|
PaintingBrush::PaintingBrush()
|
||||||
{
|
{
|
||||||
|
@ -104,13 +104,12 @@ QString PaintingBrush::getHelpText()
|
||||||
void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double z, double duration, bool reverse)
|
void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double z, double duration, bool reverse)
|
||||||
{
|
{
|
||||||
double brush_strength;
|
double brush_strength;
|
||||||
TerrainHeightMapBrush brush;
|
|
||||||
|
|
||||||
brush.relative_x = x;
|
double hard_radius = _size * (1.0 - _smoothing);
|
||||||
brush.relative_z = z;
|
double smoothed_size = _size * _smoothing;
|
||||||
brush.hard_radius = _size * (1.0 - _smoothing);
|
double total_radius = hard_radius + smoothed_size;
|
||||||
brush.smoothed_size = _size * _smoothing;
|
|
||||||
brush.total_radius = brush.hard_radius + brush.smoothed_size;
|
PaintedGridBrush brush(hard_radius, smoothed_size, total_radius);
|
||||||
|
|
||||||
brush_strength = 0.5 * _strength * duration / 0.1;
|
brush_strength = 0.5 * _strength * duration / 0.1;
|
||||||
|
|
||||||
|
@ -121,16 +120,16 @@ void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double
|
||||||
{
|
{
|
||||||
brush_strength = -brush_strength;
|
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;
|
break;
|
||||||
case PAINTING_BRUSH_SMOOTH:
|
case PAINTING_BRUSH_SMOOTH:
|
||||||
if (reverse)
|
if (reverse)
|
||||||
{
|
{
|
||||||
terrain->height_map->brushSmooth(brush, brush_strength * 30.0);
|
terrain->height_map->brushSmooth(brush, x, z, brush_strength * 30.0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
terrain->height_map->brushAddNoise(brush, _noise, brush_strength * 0.3);
|
terrain->height_map->brushAddNoise(brush, x, z, _noise, brush_strength * 0.3);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PAINTING_BRUSH_FLATTEN:
|
case PAINTING_BRUSH_FLATTEN:
|
||||||
|
@ -140,11 +139,11 @@ void PaintingBrush::applyToTerrain(TerrainDefinition* terrain, double x, double
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
terrain->height_map->brushFlatten(brush, _height, brush_strength * 30.0);
|
terrain->height_map->brushFlatten(brush, x, z, _height, brush_strength * 30.0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PAINTING_BRUSH_RESTORE:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "NoiseGenerator.h"
|
#include "NoiseGenerator.h"
|
||||||
#include "TerrainDefinition.h"
|
#include "TerrainDefinition.h"
|
||||||
#include "TerrainHeightMap.h"
|
#include "TerrainHeightMap.h"
|
||||||
#include "TerrainHeightMapBrush.h"
|
#include "PaintedGridBrush.h"
|
||||||
|
|
||||||
/* Noise sin period is defined at 20.0 */
|
/* Noise sin period is defined at 20.0 */
|
||||||
#define X_FACTOR (M_PI / 10.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));
|
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);
|
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);
|
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)
|
if (mirror)
|
||||||
{
|
{
|
||||||
|
@ -122,31 +122,31 @@ static void _checkBrushResult(TerrainDefinition* terrain, TerrainHeightMapBrush*
|
||||||
TEST_F(TerrainPainting_Test, brush_flatten)
|
TEST_F(TerrainPainting_Test, brush_flatten)
|
||||||
{
|
{
|
||||||
/* Set up */
|
/* 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->height = 1.0;
|
||||||
terrain->scaling = 1.0;
|
terrain->scaling = 1.0;
|
||||||
terrain->_height_noise->forceValue(0.0);
|
terrain->_height_noise->forceValue(0.0);
|
||||||
|
|
||||||
/* Test flattening center at 0.5 */
|
/* Test flattening center at 0.5 */
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
_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);
|
_checkBrushResult(terrain, &brush, 0.5, 0.5, 0.5, 0.25, 0.0, 0.0, 0);
|
||||||
|
|
||||||
/* Test brush strength */
|
/* Test brush strength */
|
||||||
terrain->height_map->clearPainting();
|
terrain->height_map->clearPainting();
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
_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);
|
_checkBrushResult(terrain, &brush, 0.005, 0.005, 0.005, 0.0025, 0.0, 0.0, 0);
|
||||||
|
|
||||||
/* Test cumulative effect */
|
/* 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);
|
_checkBrushResult(terrain, &brush, 0.00995, 0.00995, 0.00995, 0.0049875, 0.0, 0.0, 0);
|
||||||
|
|
||||||
/* Test with height modifier */
|
/* Test with height modifier */
|
||||||
terrain->height = 10.0;
|
terrain->height = 10.0;
|
||||||
terrain->height_map->clearPainting();
|
terrain->height_map->clearPainting();
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
_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);
|
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
||||||
|
|
||||||
/* Test with scaling modifier */
|
/* Test with scaling modifier */
|
||||||
|
@ -154,45 +154,45 @@ TEST_F(TerrainPainting_Test, brush_flatten)
|
||||||
terrain->scaling = 2.0;
|
terrain->scaling = 2.0;
|
||||||
terrain->height_map->clearPainting();
|
terrain->height_map->clearPainting();
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
_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);
|
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TerrainPainting_Test, brush_reset)
|
TEST_F(TerrainPainting_Test, brush_reset)
|
||||||
{
|
{
|
||||||
/* Set up */
|
/* Set up */
|
||||||
TerrainHeightMapBrush brush(0.0, 0.0, 2.0, 2.0, 4.0);
|
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||||
TerrainHeightMapBrush brush_full(0.0, 0.0, 4.0, 0.0, 4.0);
|
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
||||||
terrain->height = 1.0;
|
terrain->height = 1.0;
|
||||||
terrain->scaling = 1.0;
|
terrain->scaling = 1.0;
|
||||||
terrain->_height_noise->forceValue(1.0);
|
terrain->_height_noise->forceValue(1.0);
|
||||||
|
|
||||||
/* Test resetting at center */
|
/* Test resetting at center */
|
||||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
_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);
|
_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);
|
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.5, 2.0, 1.0, 0);
|
||||||
|
|
||||||
/* Test brush strength */
|
/* Test brush strength */
|
||||||
terrain->height_map->clearPainting();
|
terrain->height_map->clearPainting();
|
||||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
_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);
|
_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);
|
_checkBrushResult(terrain, &brush, 1.9, 1.9, 1.9, 1.95, 2.0, 1.0, 0);
|
||||||
|
|
||||||
/* Test cumulative effect */
|
/* 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);
|
_checkBrushResult(terrain, &brush, 1.81, 1.81, 1.81, 1.9025, 2.0, 1.0, 0);
|
||||||
|
|
||||||
/* Test with height modifier */
|
/* Test with height modifier */
|
||||||
terrain->height = 10.0;
|
terrain->height = 10.0;
|
||||||
terrain->height_map->clearPainting();
|
terrain->height_map->clearPainting();
|
||||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
_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);
|
_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);
|
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
||||||
|
|
||||||
/* Test with scaling modifier */
|
/* Test with scaling modifier */
|
||||||
|
@ -200,17 +200,17 @@ TEST_F(TerrainPainting_Test, brush_reset)
|
||||||
terrain->scaling = 2.0;
|
terrain->scaling = 2.0;
|
||||||
terrain->height_map->clearPainting();
|
terrain->height_map->clearPainting();
|
||||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
_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);
|
_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);
|
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TerrainPainting_Test, brush_reset_basevalue)
|
TEST_F(TerrainPainting_Test, brush_reset_basevalue)
|
||||||
{
|
{
|
||||||
/* Set up */
|
/* Set up */
|
||||||
TerrainHeightMapBrush brush(0.0, 0.0, 2.0, 2.0, 4.0);
|
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||||
TerrainHeightMapBrush brush_full(0.0, 0.0, 4.0, 0.0, 4.0);
|
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
||||||
terrain->height = 1.0;
|
terrain->height = 1.0;
|
||||||
terrain->scaling = 1.0;
|
terrain->scaling = 1.0;
|
||||||
|
|
||||||
|
@ -218,8 +218,8 @@ TEST_F(TerrainPainting_Test, brush_reset_basevalue)
|
||||||
terrain->height = 1.0;
|
terrain->height = 1.0;
|
||||||
terrain->scaling = 2.0;
|
terrain->scaling = 2.0;
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.309016994375, 0.587785252292, 0.809016994375, 0.951056516295, 1.0, 1);
|
_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);
|
_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);
|
_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