2012-01-22 18:39:42 +00:00
|
|
|
#include "clouds.h"
|
|
|
|
|
2012-01-18 18:47:46 +00:00
|
|
|
#include <string.h>
|
2011-12-10 13:25:22 +00:00
|
|
|
#include <math.h>
|
|
|
|
|
2012-01-22 18:39:42 +00:00
|
|
|
#include "lighting.h"
|
2011-12-10 13:25:22 +00:00
|
|
|
#include "shared/types.h"
|
|
|
|
#include "shared/functions.h"
|
|
|
|
#include "shared/constants.h"
|
|
|
|
#include "shared/globals.h"
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
Vector3 start;
|
|
|
|
Vector3 end;
|
|
|
|
double length;
|
|
|
|
} CloudSegment;
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
static CloudsLayerDefinition NULL_LAYER;
|
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
void cloudsInit()
|
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
NULL_LAYER.noise = noiseCreateGenerator();
|
|
|
|
NULL_LAYER.coverage = 0.0;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsSave(FILE* f, CloudsDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
int i;
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsLayerDefinition* layer;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
toolsSaveInt(f, definition->nblayers);
|
|
|
|
for (i = 0; i < definition->nblayers; i++)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
layer = definition->layers + i;
|
2011-12-10 13:25:22 +00:00
|
|
|
toolsSaveDouble(f, layer->ycenter);
|
|
|
|
toolsSaveDouble(f, layer->ymin);
|
|
|
|
toolsSaveDouble(f, layer->ymax);
|
|
|
|
noiseSave(layer->noise, f);
|
|
|
|
colorSave(layer->color, f);
|
|
|
|
toolsSaveDouble(f, layer->scaling);
|
|
|
|
toolsSaveDouble(f, layer->coverage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsLoad(FILE* f, CloudsDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-18 18:47:46 +00:00
|
|
|
int i, n;
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsLayerDefinition* layer;
|
2012-01-08 10:31:01 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
while (definition->nblayers > 0)
|
2012-01-18 18:47:46 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
cloudsDeleteLayer(definition, 0);
|
2012-01-18 18:47:46 +00:00
|
|
|
}
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2012-01-18 18:47:46 +00:00
|
|
|
n = toolsLoadInt(f);
|
|
|
|
for (i = 0; i < n; i++)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
layer = definition->layers + cloudsAddLayer(definition);
|
2012-01-18 18:47:46 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
layer->ycenter = toolsLoadDouble(f);
|
|
|
|
layer->ymin = toolsLoadDouble(f);
|
|
|
|
layer->ymax = toolsLoadDouble(f);
|
|
|
|
noiseLoad(layer->noise, f);
|
|
|
|
layer->color = colorLoad(f);
|
|
|
|
layer->scaling = toolsLoadDouble(f);
|
|
|
|
layer->coverage = toolsLoadDouble(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsDefinition cloudsCreateDefinition()
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsDefinition result;
|
|
|
|
|
|
|
|
result.nblayers = 0;
|
|
|
|
|
|
|
|
return result;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsDeleteDefinition(CloudsDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
while (definition->nblayers > 0)
|
2012-01-18 18:47:46 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
cloudsDeleteLayer(definition, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cloudsCopyDefinition(CloudsDefinition* source, CloudsDefinition* destination)
|
|
|
|
{
|
|
|
|
CloudsLayerDefinition* layer;
|
|
|
|
int i;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
while (destination->nblayers > 0)
|
|
|
|
{
|
|
|
|
cloudsDeleteLayer(destination, 0);
|
2012-01-18 18:47:46 +00:00
|
|
|
}
|
2012-01-23 23:45:33 +00:00
|
|
|
for (i = 0; i < source->nblayers; i++)
|
2012-01-18 18:47:46 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
layer = cloudsGetLayer(destination, cloudsAddLayer(destination));
|
|
|
|
cloudsLayerCopyDefinition(source->layers + i, layer);
|
2012-01-18 18:47:46 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsValidateDefinition(CloudsDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < definition->nblayers; i++)
|
2012-01-18 18:47:46 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
cloudsLayerValidateDefinition(&definition->layers[i]);
|
2012-01-18 18:47:46 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsLayerDefinition cloudsLayerCreateDefinition()
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsLayerDefinition result;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
result.color = COLOR_BLACK;
|
2011-12-10 13:25:22 +00:00
|
|
|
result.coverage = 0.0;
|
|
|
|
result.noise = noiseCreateGenerator();
|
|
|
|
result.scaling = 1.0;
|
|
|
|
result.ymin = 0.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
result.ycenter = 0.5;
|
|
|
|
result.ymax = 1.0;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsLayerDeleteDefinition(CloudsLayerDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
noiseDeleteGenerator(definition->noise);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsLayerCopyDefinition(CloudsLayerDefinition* source, CloudsLayerDefinition* destination)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
NoiseGenerator* noise;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
noise = destination->noise;
|
2012-01-23 23:45:33 +00:00
|
|
|
*destination = *source;
|
2011-12-10 13:25:22 +00:00
|
|
|
destination->noise = noise;
|
2012-01-23 23:45:33 +00:00
|
|
|
noiseCopy(source->noise, destination->noise);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
if (definition->coverage < 0.5)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
noiseNormalizeHeight(definition->noise, -1.0, definition->coverage * 2.0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
noiseNormalizeHeight(definition->noise, -(1.0 - definition->coverage) * 2.0, 1.0, 0);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
int cloudsGetLayerCount(CloudsDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
return definition->nblayers;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsLayerDefinition* cloudsGetLayer(CloudsDefinition* definition, int layer)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
if (layer >= 0 && layer < definition->nblayers)
|
|
|
|
{
|
|
|
|
return definition->layers + layer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return &NULL_LAYER;
|
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
int cloudsAddLayer(CloudsDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
CloudsLayerDefinition* layer;
|
|
|
|
|
|
|
|
if (definition->nblayers < CLOUDS_MAX_LAYERS)
|
|
|
|
{
|
|
|
|
layer = definition->layers + definition->nblayers;
|
|
|
|
layer->noise = noiseCreateGenerator();
|
|
|
|
layer->coverage = 0.0;
|
|
|
|
|
|
|
|
return definition->nblayers++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cloudsDeleteLayer(CloudsDefinition* definition, int layer)
|
|
|
|
{
|
|
|
|
if (layer >= 0 && layer < definition->nblayers)
|
|
|
|
{
|
|
|
|
cloudsLayerDeleteDefinition(definition->layers + layer);
|
|
|
|
if (definition->nblayers > 1 && layer < definition->nblayers - 1)
|
|
|
|
{
|
|
|
|
memmove(definition->layers + layer, definition->layers + layer + 1, sizeof(CloudsLayerDefinition) * (definition->nblayers - layer - 1));
|
|
|
|
}
|
|
|
|
definition->nblayers--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline double _getDistanceToBorder(CloudsLayerDefinition* layer, Vector3 position, double detail)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
double val, min;
|
|
|
|
|
|
|
|
if (position.y > layer->ycenter)
|
|
|
|
{
|
|
|
|
min = (position.y - layer->ycenter) / (layer->ymax - layer->ycenter);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
min = (layer->ycenter - position.y) / (layer->ycenter - layer->ymin);
|
|
|
|
}
|
|
|
|
|
|
|
|
val = noiseGet3DDetail(layer->noise, position.x, position.y, position.z, detail);
|
|
|
|
|
|
|
|
return (val - min) * layer->scaling;
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
static inline Vector3 _getNormal(CloudsLayerDefinition* layer, Vector3 position, double detail)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
Vector3 result = {0.0, 0.0, 0.0};
|
|
|
|
double val, dval;
|
|
|
|
|
|
|
|
val = noiseGet3DDetail(layer->noise, position.x, position.y, position.z, detail);
|
|
|
|
|
|
|
|
dval = val - noiseGet3DDetail(layer->noise, position.x + detail, position.y, position.z, detail);
|
|
|
|
result.x += dval;
|
|
|
|
|
|
|
|
dval = val - noiseGet3DDetail(layer->noise, position.x - detail, position.y, position.z, detail);
|
|
|
|
result.x -= dval;
|
|
|
|
|
|
|
|
dval = val - noiseGet3DDetail(layer->noise, position.x, position.y + detail, position.z, detail);
|
|
|
|
result.y += dval;
|
|
|
|
|
|
|
|
dval = val - noiseGet3DDetail(layer->noise, position.x, position.y - detail, position.z, detail);
|
|
|
|
result.y -= dval;
|
|
|
|
|
|
|
|
dval = val - noiseGet3DDetail(layer->noise, position.x, position.y, position.z + detail, detail);
|
|
|
|
result.z += dval;
|
|
|
|
|
|
|
|
dval = val - noiseGet3DDetail(layer->noise, position.x, position.y, position.z - detail, detail);
|
|
|
|
result.z -= dval;
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
return v3Normalize(result);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Optimize the search limits in a layer.
|
2011-12-17 15:54:10 +00:00
|
|
|
*
|
2011-12-10 13:25:22 +00:00
|
|
|
* @param layer The cloud layer
|
|
|
|
* @param start Start of the search to optimize
|
|
|
|
* @param end End of the search to optimize
|
|
|
|
* @return 0 if the search is useless
|
|
|
|
*/
|
2012-01-23 23:45:33 +00:00
|
|
|
static int _optimizeSearchLimits(CloudsLayerDefinition* layer, Vector3* start, Vector3* end)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
Vector3 diff;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
if (start->y > layer->ymax)
|
|
|
|
{
|
|
|
|
if (end->y >= layer->ymax)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
diff = v3Sub(*end, *start);
|
|
|
|
*start = v3Add(*start, v3Scale(diff, (layer->ymax - start->y) / diff.y));
|
|
|
|
if (end->y < layer->ymin)
|
|
|
|
{
|
|
|
|
*end = v3Add(*end, v3Scale(diff, (layer->ymin - end->y) / diff.y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (start->y < layer->ymin)
|
|
|
|
{
|
|
|
|
if (end->y <= layer->ymin)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
diff = v3Sub(*end, *start);
|
|
|
|
*start = v3Add(*start, v3Scale(diff, (layer->ymin - start->y) / diff.y));
|
|
|
|
if (end->y > layer->ymax)
|
|
|
|
{
|
|
|
|
*end = v3Add(*end, v3Scale(diff, (layer->ymax - end->y) / diff.y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* start is inside layer */
|
|
|
|
{
|
|
|
|
diff = v3Sub(*end, *start);
|
|
|
|
if (end->y > layer->ymax)
|
|
|
|
{
|
|
|
|
*end = v3Add(*start, v3Scale(diff, (layer->ymax - start->y) / diff.y));
|
|
|
|
}
|
|
|
|
else if (end->y < layer->ymin)
|
|
|
|
{
|
|
|
|
*end = v3Add(*start, v3Scale(diff, (layer->ymin - start->y) / diff.y));
|
|
|
|
}
|
|
|
|
}
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
/* TODO Limit the search length */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Go through the cloud layer to find segments (parts of the lookup that are inside the cloud).
|
2011-12-17 15:54:10 +00:00
|
|
|
*
|
2011-12-10 13:25:22 +00:00
|
|
|
* @param definition The cloud layer
|
2012-01-23 23:45:33 +00:00
|
|
|
* @param renderer The renderer environment
|
2011-12-10 13:25:22 +00:00
|
|
|
* @param start Start position of the lookup (already optimized)
|
|
|
|
* @param direction Normalized direction of the lookup
|
|
|
|
* @param detail Level of noise detail required
|
|
|
|
* @param max_segments Maximum number of segments to collect
|
|
|
|
* @param max_inside_length Maximum length to spend inside the cloud
|
|
|
|
* @param max_total_length Maximum lookup length
|
|
|
|
* @param inside_length Resulting length inside cloud (sum of all segments length)
|
|
|
|
* @param total_length Resulting lookup length
|
|
|
|
* @param out_segments Allocated space to fill found segments
|
|
|
|
* @return Number of segments found
|
|
|
|
*/
|
2012-01-23 23:45:33 +00:00
|
|
|
static int _findSegments(CloudsLayerDefinition* definition, Renderer* renderer, Vector3 start, Vector3 direction, double detail, int max_segments, double max_inside_length, double max_total_length, double* inside_length, double* total_length, CloudSegment* out_segments)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
int inside, segment_count;
|
|
|
|
double current_total_length, current_inside_length;
|
|
|
|
double step_length, segment_length, remaining_length;
|
|
|
|
double noise_distance, last_noise_distance;
|
|
|
|
Vector3 walker, step, segment_start;
|
2012-01-23 23:45:33 +00:00
|
|
|
double render_precision;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
if (max_segments <= 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
render_precision = 3.3 - 0.3 * (double)renderer->render_quality;
|
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
segment_count = 0;
|
|
|
|
current_total_length = 0.0;
|
|
|
|
current_inside_length = 0.0;
|
|
|
|
segment_length = 0.0;
|
|
|
|
walker = start;
|
2012-01-23 23:45:33 +00:00
|
|
|
noise_distance = _getDistanceToBorder(definition, start, detail) * render_precision;
|
2011-12-10 13:25:22 +00:00
|
|
|
inside = (noise_distance > 0.0) ? 1 : 0;
|
2012-01-23 23:45:33 +00:00
|
|
|
step = v3Scale(direction, render_precision);
|
2011-12-10 13:25:22 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
walker = v3Add(walker, step);
|
|
|
|
step_length = v3Norm(step);
|
|
|
|
last_noise_distance = noise_distance;
|
2012-01-23 23:45:33 +00:00
|
|
|
noise_distance = _getDistanceToBorder(definition, walker, detail) * render_precision;
|
2011-12-10 13:25:22 +00:00
|
|
|
current_total_length += step_length;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
if (noise_distance > 0.0)
|
|
|
|
{
|
|
|
|
if (inside)
|
|
|
|
{
|
|
|
|
// inside the cloud
|
|
|
|
segment_length += step_length;
|
|
|
|
current_inside_length += step_length;
|
2012-01-23 23:45:33 +00:00
|
|
|
step = v3Scale(direction, (noise_distance < render_precision) ? render_precision : noise_distance);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// entering the cloud
|
|
|
|
inside = 1;
|
|
|
|
segment_length = step_length * noise_distance / (noise_distance - last_noise_distance);
|
|
|
|
segment_start = v3Add(walker, v3Scale(direction, -segment_length));
|
|
|
|
current_inside_length += segment_length;
|
2012-01-23 23:45:33 +00:00
|
|
|
step = v3Scale(direction, render_precision);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (inside)
|
|
|
|
{
|
|
|
|
// exiting the cloud
|
|
|
|
remaining_length = step_length * last_noise_distance / (last_noise_distance - noise_distance);
|
|
|
|
segment_length += remaining_length;
|
|
|
|
current_inside_length += remaining_length;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
out_segments->start = segment_start;
|
|
|
|
out_segments->end = v3Add(walker, v3Scale(direction, remaining_length - step_length));
|
|
|
|
out_segments->length = segment_length;
|
|
|
|
out_segments++;
|
|
|
|
if (++segment_count >= max_segments)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
inside = 0;
|
2012-01-23 23:45:33 +00:00
|
|
|
step = v3Scale(direction, render_precision);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// searching for a cloud
|
2012-01-23 23:45:33 +00:00
|
|
|
step = v3Scale(direction, (noise_distance > -render_precision) ? render_precision : -noise_distance);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (inside || (walker.y <= definition->ymax + 0.001 && walker.y >= definition->ymin - 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length));
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
*total_length = current_total_length;
|
|
|
|
*inside_length = current_inside_length;
|
|
|
|
return segment_count;
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
static Color _applyLayerLighting(CloudsLayerDefinition* definition, Renderer* renderer, Vector3 position, Color base, double detail)
|
2012-01-22 18:39:42 +00:00
|
|
|
{
|
2012-01-24 13:59:54 +00:00
|
|
|
Vector3 normal;
|
|
|
|
SurfaceMaterial material;
|
2012-01-22 18:39:42 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
normal = v3Scale(_getNormal(definition, position, 1.0), 0.25);
|
|
|
|
normal = v3Add(normal, v3Scale(_getNormal(definition, position, 0.5), 0.25));
|
|
|
|
normal = v3Add(normal, v3Scale(_getNormal(definition, position, 0.2), 0.25));
|
|
|
|
normal = v3Add(normal, v3Scale(_getNormal(definition, position, 0.1), 0.25));
|
2012-01-24 13:59:54 +00:00
|
|
|
normal = v3Scale(v3Normalize(normal), 0.1);
|
2012-01-22 18:39:42 +00:00
|
|
|
|
|
|
|
material.base = base;
|
|
|
|
material.reflection = 0.3;
|
|
|
|
material.shininess = 0.1;
|
|
|
|
|
2012-01-24 13:59:54 +00:00
|
|
|
return renderer->applyLightingToSurface(renderer, position, normal, material);
|
2012-01-22 18:39:42 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
Color cloudsGetLayerColor(CloudsLayerDefinition* definition, Renderer* renderer, Vector3 start, Vector3 end)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
int i, segment_count;
|
|
|
|
double max_length, detail, total_length, inside_length;
|
|
|
|
Vector3 direction;
|
|
|
|
Color result, col;
|
|
|
|
CloudSegment segments[20];
|
|
|
|
|
|
|
|
if (!_optimizeSearchLimits(definition, &start, &end))
|
|
|
|
{
|
|
|
|
return COLOR_TRANSPARENT;
|
|
|
|
}
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
direction = v3Sub(end, start);
|
|
|
|
max_length = v3Norm(direction);
|
|
|
|
direction = v3Normalize(direction);
|
|
|
|
result = COLOR_TRANSPARENT;
|
|
|
|
|
2012-01-24 13:16:20 +00:00
|
|
|
detail = renderer->getPrecision(renderer, start) / definition->scaling;
|
2011-12-17 15:54:10 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
segment_count = _findSegments(definition, renderer, start, direction, detail, 20, 60.0, max_length, &inside_length, &total_length, segments);
|
2011-12-10 13:25:22 +00:00
|
|
|
for (i = 0; i < segment_count; i++)
|
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
col = _applyLayerLighting(definition, renderer, segments[i].start, definition->color, detail);
|
2011-12-10 13:25:22 +00:00
|
|
|
col.a = (segments[i].length >= 50.0) ? 1.0 : (segments[i].length / 50.0);
|
|
|
|
colorMask(&result, &col);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
Color cloudsGetColor(CloudsDefinition* definition, Renderer* renderer, Vector3 start, Vector3 end)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Color layer_color, result;
|
|
|
|
|
|
|
|
if (end.y < start.y)
|
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
return cloudsGetColor(definition, renderer, end, start);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
if (definition->nblayers < 1 || end.y - start.y < 0.001)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
return COLOR_TRANSPARENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = COLOR_TRANSPARENT;
|
2012-01-23 23:45:33 +00:00
|
|
|
for (i = 0; i < definition->nblayers; i++)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
layer_color = cloudsGetLayerColor(definition->layers + i, renderer, start, end);
|
2011-12-10 13:25:22 +00:00
|
|
|
if (layer_color.a > 0.0)
|
|
|
|
{
|
|
|
|
colorMask(&result, &layer_color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2012-01-24 13:59:54 +00:00
|
|
|
|
|
|
|
Color cloudsLayerFilterLight(CloudsLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light)
|
|
|
|
{
|
|
|
|
double inside_depth, total_depth;
|
|
|
|
CloudSegment segments[20];
|
|
|
|
|
|
|
|
_optimizeSearchLimits(definition, &location, &light_location);
|
|
|
|
|
|
|
|
_findSegments(definition, renderer, location, direction_to_light, 0.1, 20, 50.0, v3Norm(v3Sub(light_location, location)), &inside_depth, &total_depth, segments);
|
|
|
|
|
|
|
|
inside_depth *= 0.02;
|
|
|
|
if (inside_depth > 1.0)
|
|
|
|
{
|
|
|
|
inside_depth = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
light.r = light.r * (1.0 - 0.2 * inside_depth);
|
|
|
|
light.g = light.g * (1.0 - 0.2 * inside_depth);
|
|
|
|
light.b = light.b * (1.0 - 0.2 * inside_depth);
|
|
|
|
|
|
|
|
return light;
|
|
|
|
}
|
|
|
|
|
|
|
|
Color cloudsFilterLight(CloudsDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < definition->nblayers; i++)
|
|
|
|
{
|
|
|
|
light = cloudsLayerFilterLight(definition->layers + i, renderer, light, location, light_location, direction_to_light);
|
|
|
|
}
|
|
|
|
return light;
|
|
|
|
}
|