279 lines
6.5 KiB
C++
279 lines
6.5 KiB
C++
|
#include "Zone.h"
|
||
|
|
||
|
#include "Curve.h"
|
||
|
#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)
|
||
|
{
|
||
|
value_by_height = new Curve;
|
||
|
absolute_height = 1;
|
||
|
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);
|
||
|
stream->write(&relative_height_max);
|
||
|
|
||
|
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);
|
||
|
stream->read(&relative_height_max);
|
||
|
|
||
|
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
|
||
|
{
|
||
|
Zone* destination = (Zone*)_destination;
|
||
|
|
||
|
destination->absolute_height = absolute_height;
|
||
|
destination->relative_height_min = relative_height_min;
|
||
|
destination->relative_height_middle = relative_height_middle;
|
||
|
destination->relative_height_max = relative_height_max;
|
||
|
|
||
|
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()
|
||
|
{
|
||
|
absolute_height = 1;
|
||
|
}
|
||
|
|
||
|
void Zone::setRelativeHeight(double min, double middle, double max)
|
||
|
{
|
||
|
if (max < min)
|
||
|
{
|
||
|
max = min;
|
||
|
}
|
||
|
if (middle < min)
|
||
|
{
|
||
|
middle = min;
|
||
|
}
|
||
|
if (middle > max)
|
||
|
{
|
||
|
middle = max;
|
||
|
}
|
||
|
|
||
|
absolute_height = 0;
|
||
|
relative_height_min = min;
|
||
|
relative_height_middle = middle;
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
void Zone::setHeightCurve(Curve* curve)
|
||
|
{
|
||
|
curve->copy(value_by_height);
|
||
|
}
|
||
|
|
||
|
void Zone::addHeightRangeQuick(double value, double hardmin, double softmin, double softmax, double hardmax)
|
||
|
{
|
||
|
value_by_height->addPoint(hardmin, 0.0);
|
||
|
value_by_height->addPoint(softmin, value);
|
||
|
value_by_height->addPoint(softmax, value);
|
||
|
value_by_height->addPoint(hardmax, 0.0);
|
||
|
}
|
||
|
|
||
|
void Zone::getSlopeCurve(Curve* curve) const
|
||
|
{
|
||
|
value_by_slope->copy(curve);
|
||
|
}
|
||
|
|
||
|
void Zone::setSlopeCurve(Curve* curve)
|
||
|
{
|
||
|
curve->copy(value_by_slope);
|
||
|
}
|
||
|
|
||
|
void Zone::addSlopeRangeQuick(double value, double hardmin, double softmin, double softmax, double hardmax)
|
||
|
{
|
||
|
value_by_slope->addPoint(hardmin, 0.0);
|
||
|
value_by_slope->addPoint(softmin, value);
|
||
|
value_by_slope->addPoint(softmax, value);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if (absolute_height)
|
||
|
{
|
||
|
final_height = location.y;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (location.y >= relative_height_max)
|
||
|
{
|
||
|
final_height = 1.0;
|
||
|
}
|
||
|
else if (location.y <= relative_height_min)
|
||
|
{
|
||
|
final_height = 0.0;
|
||
|
}
|
||
|
else if (location.y <= relative_height_middle)
|
||
|
{
|
||
|
final_height = 0.5 * (location.y - relative_height_min) / (relative_height_middle - relative_height_min);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
final_height = 0.5 + 0.5 * (location.y - relative_height_middle) / (relative_height_max - relative_height_middle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
value_height = value_by_height->getValue(final_height);
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|