2012-01-29 17:39:56 +00:00
|
|
|
#include "zone.h"
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
#include <string.h>
|
2011-12-10 13:25:22 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
2012-01-29 17:39:56 +00:00
|
|
|
#include "tools.h"
|
2011-12-10 13:25:22 +00:00
|
|
|
|
|
|
|
#define MAX_CIRCLES 20
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
double value;
|
|
|
|
double centerx;
|
|
|
|
double centerz;
|
|
|
|
double softradius;
|
|
|
|
double hardradius;
|
2011-12-10 13:25:22 +00:00
|
|
|
} Circle;
|
|
|
|
|
|
|
|
struct Zone {
|
2013-09-27 21:28:06 +00:00
|
|
|
int absolute_height;
|
|
|
|
double relative_height_min;
|
|
|
|
double relative_height_middle;
|
|
|
|
double relative_height_max;
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
Curve* value_by_height;
|
|
|
|
Curve* value_by_slope;
|
2011-12-10 13:25:22 +00:00
|
|
|
|
|
|
|
Circle circles_included[MAX_CIRCLES];
|
|
|
|
int circles_included_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
Zone* zoneCreate()
|
|
|
|
{
|
|
|
|
Zone* result;
|
|
|
|
|
|
|
|
result = (Zone*)malloc(sizeof(Zone));
|
2012-07-02 15:35:10 +00:00
|
|
|
result->value_by_height = curveCreate();
|
2013-09-27 21:28:06 +00:00
|
|
|
result->absolute_height = 1;
|
2012-07-02 15:35:10 +00:00
|
|
|
curveSetDefault(result->value_by_height, 1.0);
|
|
|
|
result->value_by_slope = curveCreate();
|
|
|
|
curveSetDefault(result->value_by_slope, 1.0);
|
2011-12-10 13:25:22 +00:00
|
|
|
result->circles_included_count = 0;
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zoneDelete(Zone* zone)
|
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveDelete(zone->value_by_height);
|
|
|
|
curveDelete(zone->value_by_slope);
|
2011-12-10 13:25:22 +00:00
|
|
|
free(zone);
|
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void zoneSave(PackStream* stream, Zone* zone)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
|
|
|
int i;
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2013-09-27 21:28:06 +00:00
|
|
|
packWriteInt(stream, &zone->absolute_height);
|
|
|
|
packWriteDouble(stream, &zone->relative_height_min);
|
|
|
|
packWriteDouble(stream, &zone->relative_height_middle);
|
|
|
|
packWriteDouble(stream, &zone->relative_height_max);
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
curveSave(stream, zone->value_by_height);
|
|
|
|
curveSave(stream, zone->value_by_slope);
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
packWriteInt(stream, &zone->circles_included_count);
|
2012-01-03 15:40:50 +00:00
|
|
|
for (i = 0; i < zone->circles_included_count; i++)
|
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
packWriteDouble(stream, &zone->circles_included[i].value);
|
|
|
|
packWriteDouble(stream, &zone->circles_included[i].centerx);
|
|
|
|
packWriteDouble(stream, &zone->circles_included[i].centerz);
|
|
|
|
packWriteDouble(stream, &zone->circles_included[i].softradius);
|
|
|
|
packWriteDouble(stream, &zone->circles_included[i].hardradius);
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void zoneLoad(PackStream* stream, Zone* zone)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
|
|
|
int i;
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2013-09-27 21:28:06 +00:00
|
|
|
packReadInt(stream, &zone->absolute_height);
|
|
|
|
packReadDouble(stream, &zone->relative_height_min);
|
|
|
|
packReadDouble(stream, &zone->relative_height_middle);
|
|
|
|
packReadDouble(stream, &zone->relative_height_max);
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
curveLoad(stream, zone->value_by_height);
|
|
|
|
curveLoad(stream, zone->value_by_slope);
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
packReadInt(stream, &zone->circles_included_count);
|
2012-01-03 15:40:50 +00:00
|
|
|
for (i = 0; i < zone->circles_included_count; i++)
|
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
packReadDouble(stream, &zone->circles_included[i].value);
|
|
|
|
packReadDouble(stream, &zone->circles_included[i].centerx);
|
|
|
|
packReadDouble(stream, &zone->circles_included[i].centerz);
|
|
|
|
packReadDouble(stream, &zone->circles_included[i].softradius);
|
|
|
|
packReadDouble(stream, &zone->circles_included[i].hardradius);
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void zoneCopy(Zone* source, Zone* destination)
|
|
|
|
{
|
2013-09-27 21:28:06 +00:00
|
|
|
destination->absolute_height = source->absolute_height;
|
|
|
|
destination->relative_height_min = source->relative_height_min;
|
|
|
|
destination->relative_height_middle = source->relative_height_middle;
|
|
|
|
destination->relative_height_max = source->relative_height_max;
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
curveCopy(source->value_by_height, destination->value_by_height);
|
|
|
|
curveCopy(source->value_by_slope, destination->value_by_slope);
|
2013-01-19 22:42:50 +00:00
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
memcpy(destination->circles_included, source->circles_included, sizeof(Circle) * source->circles_included_count);
|
|
|
|
destination->circles_included_count = source->circles_included_count;
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 20:11:29 +00:00
|
|
|
void zoneClear(Zone* zone)
|
|
|
|
{
|
|
|
|
curveClear(zone->value_by_height);
|
|
|
|
curveClear(zone->value_by_slope);
|
|
|
|
zone->circles_included_count = 0;
|
2013-09-27 21:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void zoneSetAbsoluteHeight(Zone* zone)
|
|
|
|
{
|
|
|
|
zone->absolute_height = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zoneSetRelativeHeight(Zone* zone, double min, double middle, double max)
|
|
|
|
{
|
|
|
|
if (max < min)
|
|
|
|
{
|
|
|
|
max = min;
|
|
|
|
}
|
|
|
|
if (middle < min)
|
|
|
|
{
|
|
|
|
middle = min;
|
|
|
|
}
|
|
|
|
if (middle > max)
|
|
|
|
{
|
|
|
|
middle = max;
|
|
|
|
}
|
|
|
|
|
|
|
|
zone->absolute_height = 0;
|
|
|
|
zone->relative_height_min = min;
|
|
|
|
zone->relative_height_middle = middle;
|
|
|
|
zone->relative_height_max = max;
|
2013-04-12 20:11:29 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void zoneIncludeCircleArea(Zone* zone, double value, double centerx, double centerz, double softradius, double hardradius)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
Circle circle = {value, centerx, centerz, softradius, hardradius};
|
|
|
|
|
|
|
|
if (zone->circles_included_count < MAX_CIRCLES)
|
|
|
|
{
|
|
|
|
zone->circles_included[zone->circles_included_count++] = circle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
void zoneGetHeightCurve(Zone* zone, Curve* curve)
|
2012-04-05 20:09:39 +00:00
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveCopy(zone->value_by_height, curve);
|
2012-04-05 20:09:39 +00:00
|
|
|
}
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
void zoneSetHeightCurve(Zone* zone, Curve* curve)
|
2012-04-05 20:09:39 +00:00
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveCopy(curve, zone->value_by_height);
|
2012-04-05 20:09:39 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
void zoneAddHeightRangeQuick(Zone* zone, double value, double hardmin, double softmin, double softmax, double hardmax)
|
2012-04-05 20:09:39 +00:00
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveQuickAddPoint(zone->value_by_height, hardmin, 0.0);
|
|
|
|
curveQuickAddPoint(zone->value_by_height, softmin, value);
|
|
|
|
curveQuickAddPoint(zone->value_by_height, softmax, value);
|
|
|
|
curveQuickAddPoint(zone->value_by_height, hardmax, 0.0);
|
2012-04-05 20:09:39 +00:00
|
|
|
}
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
void zoneGetSlopeCurve(Zone* zone, Curve* curve)
|
2012-04-05 20:09:39 +00:00
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveCopy(zone->value_by_slope, curve);
|
2012-04-05 20:09:39 +00:00
|
|
|
}
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
void zoneSetSlopeCurve(Zone* zone, Curve* curve)
|
2012-04-05 20:09:39 +00:00
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveCopy(curve, zone->value_by_slope);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-07-02 15:35:10 +00:00
|
|
|
void zoneAddSlopeRangeQuick(Zone* zone, double value, double hardmin, double softmin, double softmax, double hardmax)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-07-02 15:35:10 +00:00
|
|
|
curveQuickAddPoint(zone->value_by_slope, hardmin, 0.0);
|
|
|
|
curveQuickAddPoint(zone->value_by_slope, softmin, value);
|
|
|
|
curveQuickAddPoint(zone->value_by_slope, softmax, value);
|
|
|
|
curveQuickAddPoint(zone->value_by_slope, hardmax, 0.0);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
static inline double _getCircleInfluence(Circle circle, Vector3 position)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
double radius, dx, dz;
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
dx = position.x - circle.centerx;
|
|
|
|
dz = position.z - circle.centerz;
|
|
|
|
radius = sqrt(dx * dx + dz * dz);
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
double zoneGetValue(Zone* zone, Vector3 location, Vector3 normal)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
int i;
|
2013-09-27 21:28:06 +00:00
|
|
|
double final_height;
|
2012-06-17 09:40:40 +00:00
|
|
|
double value, value_height, value_steepness, value_circle;
|
2012-01-03 17:43:01 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
if (zone->circles_included_count > 0)
|
|
|
|
{
|
|
|
|
value_circle = 0.0;
|
|
|
|
for (i = 0; i < zone->circles_included_count; i++)
|
|
|
|
{
|
|
|
|
value = _getCircleInfluence(zone->circles_included[i], location);
|
|
|
|
if (value > value_circle)
|
|
|
|
{
|
|
|
|
value_circle = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value_circle = 1.0;
|
|
|
|
}
|
|
|
|
|
2013-09-27 21:28:06 +00:00
|
|
|
if (zone->absolute_height)
|
|
|
|
{
|
|
|
|
final_height = location.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (location.y >= zone->relative_height_max)
|
|
|
|
{
|
|
|
|
final_height = 1.0;
|
|
|
|
}
|
|
|
|
else if (location.y <= zone->relative_height_min)
|
|
|
|
{
|
|
|
|
final_height = 0.0;
|
|
|
|
}
|
|
|
|
else if (location.y <= zone->relative_height_middle)
|
|
|
|
{
|
|
|
|
final_height = 0.5 * (location.y - zone->relative_height_min) / (zone->relative_height_middle - zone->relative_height_min);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
final_height = 0.5 + 0.5 * (location.y - zone->relative_height_middle) / (zone->relative_height_max - zone->relative_height_middle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
value_height = curveGetValue(zone->value_by_height, final_height);
|
2012-07-02 15:35:10 +00:00
|
|
|
value_steepness = curveGetValue(zone->value_by_slope, (1.0 - normal.y));
|
2011-12-10 13:25:22 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|