Merge branch 'clouds_walking'
This commit is contained in:
commit
6355de2e5e
11 changed files with 648 additions and 323 deletions
2
TODO
2
TODO
|
@ -1,4 +1,5 @@
|
|||
Technology Preview 2 :
|
||||
- Implement perspective correction for coordinate mapping of rasterized polygons.
|
||||
- Finalize terrain editor.
|
||||
=> Add a generation dialog for base noise (overwriting changes).
|
||||
- Get rid of noise dialogs, for simpler settings.
|
||||
|
@ -15,6 +16,7 @@ Technology Preview 2 :
|
|||
|
||||
Technlogy Preview 3 :
|
||||
- Start an undo/redo system ?
|
||||
- Alter aerial perspective using estimation of the amount of light left after cloud layers traversal.
|
||||
- Add a map preview to terrain editor.
|
||||
- Better time selection widget for atmosphere.
|
||||
- Clouds should keep distance to ground.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "formclouds.h"
|
||||
|
||||
#include "rendering/clouds/clo_preview.h"
|
||||
#include "rendering/tools/color.h"
|
||||
#include "rendering/tools/euclid.h"
|
||||
#include "rendering/scenery.h"
|
||||
|
@ -12,24 +13,22 @@ class PreviewCloudsCoverage:public BasePreview
|
|||
public:
|
||||
PreviewCloudsCoverage(QWidget* parent, CloudsLayerDefinition* layer):BasePreview(parent)
|
||||
{
|
||||
_renderer = cloudsCreatePreviewCoverageRenderer();
|
||||
_renderer = cloudsPreviewCoverageCreateRenderer();
|
||||
_3d = true;
|
||||
|
||||
_original_layer = layer;
|
||||
_preview_definition = (CloudsDefinition*)CloudsDefinitionClass.create();
|
||||
|
||||
addToggle("3d", tr("Perspective"), true);
|
||||
configScaling(100.0, 1000.0, 20.0, 200.0);
|
||||
}
|
||||
~PreviewCloudsCoverage()
|
||||
{
|
||||
CloudsDefinitionClass.destroy(_preview_definition);
|
||||
rendererDelete(_renderer);
|
||||
}
|
||||
protected:
|
||||
Color getColor(double x, double y)
|
||||
{
|
||||
return cloudsGetPreviewCoverage(_renderer, x, y, scaling, _3d);
|
||||
return cloudsPreviewCoverageGetPixel(_renderer, x, y, scaling, _3d);
|
||||
}
|
||||
virtual void toggleChangeEvent(QString key, bool value)
|
||||
{
|
||||
|
@ -41,15 +40,12 @@ protected:
|
|||
}
|
||||
void updateData()
|
||||
{
|
||||
layersDeleteLayer(_preview_definition->layers, 0);
|
||||
layersAddLayer(_preview_definition->layers, _original_layer);
|
||||
CloudsRendererClass.bind(_renderer, _preview_definition);
|
||||
cloudsPreviewCoverageBindLayer(_renderer, _original_layer);
|
||||
}
|
||||
|
||||
private:
|
||||
Renderer* _renderer;
|
||||
CloudsLayerDefinition* _original_layer;
|
||||
CloudsDefinition* _preview_definition;
|
||||
bool _3d;
|
||||
};
|
||||
|
||||
|
@ -59,27 +55,28 @@ public:
|
|||
PreviewCloudsColor(QWidget* parent, CloudsLayerDefinition* layer):BasePreview(parent)
|
||||
{
|
||||
_original_layer = layer;
|
||||
_preview_definition = (CloudsDefinition*)CloudsDefinitionClass.create();
|
||||
|
||||
_renderer = cloudsCreatePreviewColorRenderer();
|
||||
_renderer = cloudsPreviewMaterialCreateRenderer();
|
||||
|
||||
configScaling(0.5, 2.0, 0.1, 2.0);
|
||||
}
|
||||
|
||||
~PreviewCloudsColor()
|
||||
{
|
||||
rendererDelete(_renderer);
|
||||
}
|
||||
protected:
|
||||
Color getColor(double x, double y)
|
||||
{
|
||||
return cloudsGetPreviewColor(_renderer, x, y);
|
||||
return cloudsPreviewMaterialGetPixel(_renderer, x, y);
|
||||
}
|
||||
void updateData()
|
||||
{
|
||||
layersDeleteLayer(_preview_definition->layers, 0);
|
||||
layersAddLayer(_preview_definition->layers, _original_layer);
|
||||
CloudsRendererClass.bind(_renderer, _preview_definition);
|
||||
cloudsPreviewMaterialBindLayer(_renderer, _original_layer);
|
||||
}
|
||||
private:
|
||||
Renderer* _renderer;
|
||||
CloudsLayerDefinition* _original_layer;
|
||||
CloudsDefinition* _preview_definition;
|
||||
};
|
||||
|
||||
/**************** Form ****************/
|
||||
|
|
|
@ -18,7 +18,7 @@ Color _fakeApplyLightingToSurface(Renderer* renderer, Vector3 location, Vector3
|
|||
return COLOR_WHITE;
|
||||
}
|
||||
|
||||
Renderer* cloudsCreatePreviewCoverageRenderer()
|
||||
Renderer* cloudsPreviewCoverageCreateRenderer()
|
||||
{
|
||||
Renderer* result = rendererCreate();
|
||||
result->render_quality = 5;
|
||||
|
@ -26,7 +26,15 @@ Renderer* cloudsCreatePreviewCoverageRenderer()
|
|||
return result;
|
||||
}
|
||||
|
||||
Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling, int perspective)
|
||||
void cloudsPreviewCoverageBindLayer(Renderer* renderer, CloudsLayerDefinition* layer)
|
||||
{
|
||||
CloudsDefinition* definition = (CloudsDefinition*)CloudsDefinitionClass.create();
|
||||
layersAddLayer(definition->layers, layer);
|
||||
CloudsRendererClass.bind(renderer, definition);
|
||||
CloudsDefinitionClass.destroy(definition);
|
||||
}
|
||||
|
||||
Color cloudsPreviewCoverageGetPixel(Renderer* renderer, double x, double y, double scaling, int perspective)
|
||||
{
|
||||
if (perspective)
|
||||
{
|
||||
|
@ -55,25 +63,91 @@ Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double sc
|
|||
}
|
||||
}
|
||||
|
||||
Renderer* cloudsCreatePreviewColorRenderer()
|
||||
static void _getLightingStatus(Renderer* renderer, LightStatus* status, Vector3 normal, int opaque)
|
||||
{
|
||||
LightDefinition light;
|
||||
|
||||
UNUSED(renderer);
|
||||
UNUSED(normal);
|
||||
UNUSED(opaque);
|
||||
|
||||
light.color.r = 1.0;
|
||||
light.color.g = 1.0;
|
||||
light.color.b = 1.0;
|
||||
light.direction.x = -1.0;
|
||||
light.direction.y = -0.5;
|
||||
light.direction.z = 1.0;
|
||||
light.direction = v3Normalize(light.direction);
|
||||
light.altered = 1;
|
||||
light.reflection = 0.0;
|
||||
lightingPushLight(status, &light);
|
||||
|
||||
light.color.r = 0.2;
|
||||
light.color.g = 0.2;
|
||||
light.color.b = 0.2;
|
||||
light.direction.x = 1.0;
|
||||
light.direction.y = -0.5;
|
||||
light.direction.z = -1.0;
|
||||
light.direction = v3Normalize(light.direction);
|
||||
light.altered = 0;
|
||||
light.reflection = 0.0;
|
||||
lightingPushLight(status, &light);
|
||||
}
|
||||
|
||||
Renderer* cloudsPreviewMaterialCreateRenderer()
|
||||
{
|
||||
Renderer* result = rendererCreate();
|
||||
result->render_quality = 8;
|
||||
result->atmosphere->getLightingStatus = _getLightingStatus;
|
||||
return result;
|
||||
}
|
||||
|
||||
Color cloudsGetPreviewColor(Renderer* renderer, double x, double y)
|
||||
static double _getDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location)
|
||||
{
|
||||
UNUSED(renderer);
|
||||
UNUSED(layer);
|
||||
|
||||
double distance = v3Norm(location);
|
||||
if (distance > 1.0)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
else if (distance < 0.8)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (1.0 - distance) / 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
void cloudsPreviewMaterialBindLayer(Renderer* renderer, CloudsLayerDefinition* layer)
|
||||
{
|
||||
CloudsDefinition* definition = (CloudsDefinition*)CloudsDefinitionClass.create();
|
||||
layersAddLayer(definition->layers, layer);
|
||||
CloudsRendererClass.bind(renderer, definition);
|
||||
CloudsDefinitionClass.destroy(definition);
|
||||
|
||||
layer = layersGetLayer(renderer->clouds->definition->layers, 0);
|
||||
layer->lower_altitude = -1.0;
|
||||
layer->thickness = 2.0;
|
||||
|
||||
renderer->clouds->getLayerDensity = _getDensity;
|
||||
}
|
||||
|
||||
Color cloudsPreviewMaterialGetPixel(Renderer* renderer, double x, double y)
|
||||
{
|
||||
Vector3 start, end;
|
||||
double thickness = 0.5;
|
||||
double thickness = 2.0;
|
||||
|
||||
start.x = x * thickness * 0.5;
|
||||
start.y = -y * thickness * 0.5;
|
||||
start.z = thickness * 0.5;
|
||||
start.z = y * thickness * 0.5;
|
||||
start.y = thickness * 0.5;
|
||||
|
||||
end.x = start.x;
|
||||
end.y = start.y;
|
||||
end.z = -start.z;
|
||||
end.z = start.z;
|
||||
end.y = -start.y;
|
||||
|
||||
return renderer->clouds->getColor(renderer, COLOR_BLUE, start, end);
|
||||
}
|
||||
|
|
28
src/rendering/clouds/clo_preview.h
Normal file
28
src/rendering/clouds/clo_preview.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef _PAYSAGES_CLOUDS_PREVIEW_H_
|
||||
#define _PAYSAGES_CLOUDS_PREVIEW_H_
|
||||
|
||||
#include "public.h"
|
||||
#include "../tools/euclid.h"
|
||||
|
||||
/**
|
||||
* Cloud preview helpers.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
Renderer* cloudsPreviewCoverageCreateRenderer();
|
||||
void cloudsPreviewCoverageBindLayer(Renderer* renderer, CloudsLayerDefinition* layer);
|
||||
Color cloudsPreviewCoverageGetPixel(Renderer* renderer, double x, double y, double scaling, int perspective);
|
||||
|
||||
Renderer* cloudsPreviewMaterialCreateRenderer();
|
||||
void cloudsPreviewMaterialBindLayer(Renderer* renderer, CloudsLayerDefinition* layer);
|
||||
Color cloudsPreviewMaterialGetPixel(Renderer* renderer, double x, double y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,9 +1,11 @@
|
|||
#include "private.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "../tools.h"
|
||||
#include "../renderer.h"
|
||||
#include "clo_density.h"
|
||||
#include "clo_walking.h"
|
||||
|
||||
/******************** Fake ********************/
|
||||
static int _fakeAlterLight(Renderer* renderer, LightDefinition* light, Vector3 location)
|
||||
|
@ -25,24 +27,117 @@ static Color _fakeGetColor(Renderer* renderer, Color base, Vector3 start, Vector
|
|||
}
|
||||
|
||||
/******************** Real ********************/
|
||||
/*static int _cmpLayer(const void* layer1, const void* layer2)
|
||||
typedef struct
|
||||
{
|
||||
return (((CloudsLayerDefinition*)layer1)->lower_altitude > ((CloudsLayerDefinition*)layer2)->lower_altitude) ? -1 : 1;
|
||||
}*/
|
||||
double light_power;
|
||||
double out_scattering; /* Amount of light scattered away by heavy particles */
|
||||
} AccumulatedLightData;
|
||||
|
||||
static void _walkerFilterCallback(CloudsWalker* walker)
|
||||
{
|
||||
CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
|
||||
AccumulatedLightData* data = (AccumulatedLightData*)segment->data;
|
||||
|
||||
assert(data != NULL);
|
||||
|
||||
double density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
||||
|
||||
data->out_scattering += 0.3 * density_integral;
|
||||
|
||||
if (data->out_scattering > data->light_power)
|
||||
{
|
||||
cloudsWalkerOrderStop(walker);
|
||||
}
|
||||
}
|
||||
|
||||
static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location)
|
||||
{
|
||||
CloudsDefinition* definition = renderer->clouds->definition;
|
||||
int i, n;
|
||||
|
||||
AccumulatedLightData data;
|
||||
data.out_scattering = 0.0;
|
||||
data.light_power = colorGetPower(&light->color);
|
||||
|
||||
/* TODO Iter layers in sorted order */
|
||||
n = layersCount(definition->layers);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
light->color = cloudsLayerFilterLight(layersGetLayer(definition->layers, i), renderer, light->color, location, v3Add(location, v3Scale(light->direction, -10000.0)), v3Scale(light->direction, -1.0));
|
||||
/* TODO Reduce light->reflection too */
|
||||
CloudsLayerDefinition* layer = (CloudsLayerDefinition*)layersGetLayer(renderer->clouds->definition->layers, i);
|
||||
Vector3 ostart, oend;
|
||||
|
||||
ostart = location;
|
||||
oend = v3Add(location, v3Scale(light->direction, -10000.0));
|
||||
if (!cloudsOptimizeWalkingBounds(layer, &ostart, &oend))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
CloudsWalker* walker;
|
||||
|
||||
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
|
||||
cloudsWalkerSetStepSize(walker, -1.0);
|
||||
cloudsStartWalking(walker, _walkerFilterCallback, &data);
|
||||
cloudsDeleteWalker(walker);
|
||||
}
|
||||
}
|
||||
return n > 0;
|
||||
|
||||
double max_power = colorGetPower(&light->color) - data.out_scattering;
|
||||
if (max_power < 0.0)
|
||||
{
|
||||
light->color = COLOR_BLACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
colorLimitPower(&light->color, max_power);
|
||||
}
|
||||
|
||||
return data.out_scattering > 0.0;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double out_scattering; /* Amount of light scattered away by heavy particles */
|
||||
Color in_scattering; /* Amount of light redirected toward the viewer */
|
||||
} AccumulatedMaterialData;
|
||||
|
||||
static inline void _applyOutScattering(Color* col, double out_scattering)
|
||||
{
|
||||
if (out_scattering >= 1.0)
|
||||
{
|
||||
col->r = col->g = col->b = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
col->r *= (1.0 - out_scattering);
|
||||
col->g *= (1.0 - out_scattering);
|
||||
col->b *= (1.0 - out_scattering);
|
||||
}
|
||||
}
|
||||
|
||||
static void _walkerMaterialCallback(CloudsWalker* walker)
|
||||
{
|
||||
CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
|
||||
AccumulatedMaterialData* data = (AccumulatedMaterialData*)segment->data;
|
||||
Renderer* renderer = segment->renderer;
|
||||
CloudsLayerDefinition* layer = segment->layer;
|
||||
|
||||
assert(data != NULL);
|
||||
|
||||
double density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
||||
|
||||
data->out_scattering += 0.5 * density_integral;
|
||||
|
||||
Color in_scattering = renderer->applyLightingToSurface(renderer, segment->start.location, VECTOR_UP, &layer->material);
|
||||
in_scattering.r *= density_integral * 5.0;
|
||||
in_scattering.g *= density_integral * 5.0;
|
||||
in_scattering.b *= density_integral * 5.0;
|
||||
_applyOutScattering(&in_scattering, data->out_scattering);
|
||||
|
||||
data->in_scattering.r += in_scattering.r;
|
||||
data->in_scattering.g += in_scattering.g;
|
||||
data->in_scattering.b += in_scattering.b;
|
||||
}
|
||||
|
||||
static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end)
|
||||
|
@ -59,7 +154,39 @@ static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 en
|
|||
/* TODO Iter layers in sorted order */
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
base = cloudsApplyLayer(layersGetLayer(definition->layers, i), base, renderer, start, end);
|
||||
CloudsLayerDefinition* layer = (CloudsLayerDefinition*)layersGetLayer(renderer->clouds->definition->layers, i);
|
||||
Vector3 ostart, oend;
|
||||
|
||||
ostart = start;
|
||||
oend = end;
|
||||
if (!cloudsOptimizeWalkingBounds(layer, &ostart, &oend))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
CloudsWalker* walker;
|
||||
AccumulatedMaterialData data;
|
||||
data.out_scattering = 0.0;
|
||||
data.in_scattering = COLOR_BLACK;
|
||||
|
||||
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
|
||||
cloudsWalkerSetStepSize(walker, -1.0);
|
||||
cloudsStartWalking(walker, _walkerMaterialCallback, &data);
|
||||
cloudsDeleteWalker(walker);
|
||||
|
||||
/* Apply final out_scattering to base */
|
||||
_applyOutScattering(&base, data.out_scattering);
|
||||
|
||||
/* Apply in_scattering */
|
||||
base.r += data.in_scattering.r;
|
||||
base.g += data.in_scattering.g;
|
||||
base.b += data.in_scattering.b;
|
||||
|
||||
/* Apply aerial perspective approximation */
|
||||
/* TODO This should be done at cloud entry */
|
||||
base = renderer->atmosphere->applyAerialPerspective(renderer, ostart, base).final;
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
#include "private.h"
|
||||
|
||||
/*
|
||||
* Clouds tools.
|
||||
*/
|
||||
|
||||
#include "clo_walking.h"
|
||||
#include "../renderer.h"
|
||||
#include "../tools.h"
|
||||
|
||||
static inline Vector3 _getNormal(CloudsLayerDefinition* layer, Vector3 position, double detail)
|
||||
{
|
||||
Vector3 result = {0.0, 0.0, 0.0};
|
||||
/*Vector3 dposition;
|
||||
double val, dval;
|
||||
|
||||
val = _getDistanceToBorder(layer, position);
|
||||
|
||||
dposition.x = position.x + detail;
|
||||
dposition.y = position.y;
|
||||
dposition.z = position.z;
|
||||
dval = val - _getDistanceToBorder(layer, dposition);
|
||||
result.x += dval;
|
||||
|
||||
dposition.x = position.x - detail;
|
||||
dval = val - _getDistanceToBorder(layer, dposition);
|
||||
result.x -= dval;
|
||||
|
||||
dposition.x = position.x;
|
||||
dposition.y = position.y + detail;
|
||||
dval = val - _getDistanceToBorder(layer, dposition);
|
||||
result.y += dval;
|
||||
|
||||
dposition.y = position.y - detail;
|
||||
dval = val - _getDistanceToBorder(layer, dposition);
|
||||
result.y -= dval;
|
||||
|
||||
dposition.y = position.y;
|
||||
dposition.z = position.z + detail;
|
||||
dval = val - _getDistanceToBorder(layer, dposition);
|
||||
result.z += dval;
|
||||
|
||||
dposition.z = position.z - detail;
|
||||
dval = val - _getDistanceToBorder(layer, dposition);
|
||||
result.z -= dval;*/
|
||||
|
||||
return v3Normalize(result);
|
||||
}
|
||||
|
||||
static Color _applyLayerLighting(CloudsLayerDefinition* definition, Renderer* renderer, Vector3 location, double detail)
|
||||
{
|
||||
Vector3 normal;
|
||||
Color col1, col2;
|
||||
LightStatus* lighting;
|
||||
|
||||
normal = _getNormal(definition, location, 3.0);
|
||||
if (renderer->render_quality > 3)
|
||||
{
|
||||
normal = v3Add(normal, _getNormal(definition, location, 2.0));
|
||||
normal = v3Add(normal, _getNormal(definition, location, 1.0));
|
||||
}
|
||||
if (renderer->render_quality > 5)
|
||||
{
|
||||
normal = v3Add(normal, _getNormal(definition, location, 0.5));
|
||||
}
|
||||
if (renderer->render_quality > 8)
|
||||
{
|
||||
normal = v3Add(normal, _getNormal(definition, location, 0.75));
|
||||
normal = v3Add(normal, _getNormal(definition, location, 1.25));
|
||||
normal = v3Add(normal, _getNormal(definition, location, 2.5));
|
||||
}
|
||||
normal = v3Scale(v3Normalize(normal), definition->hardness);
|
||||
|
||||
return renderer->applyLightingToSurface(renderer, location, normal, &definition->material);
|
||||
|
||||
lighting = lightingCreateStatus(renderer->lighting, location, renderer->getCameraLocation(renderer, location));
|
||||
renderer->atmosphere->getLightingStatus(renderer, lighting, normal, 0);
|
||||
col1 = lightingApplyStatus(lighting, normal, &definition->material);
|
||||
col2 = lightingApplyStatus(lighting, v3Scale(normal, -1.0), &definition->material);
|
||||
lightingDeleteStatus(lighting);
|
||||
|
||||
col1.r = (col1.r + col2.r) / 2.0;
|
||||
col1.g = (col1.g + col2.g) / 2.0;
|
||||
col1.b = (col1.b + col2.b) / 2.0;
|
||||
col1.a = (col1.a + col2.a) / 2.0;
|
||||
|
||||
return col1;
|
||||
}
|
||||
|
||||
Color cloudsApplyLayer(CloudsLayerDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end)
|
||||
{
|
||||
int segment_count;
|
||||
Color col;
|
||||
CloudPrimarySegment segments[MAX_SEGMENT_COUNT];
|
||||
|
||||
segment_count = cloudsGetLayerPrimarySegments(renderer, definition, start, end, MAX_SEGMENT_COUNT, segments);
|
||||
/* TODO Crawl in segments for render */
|
||||
|
||||
col = definition->material.base;
|
||||
/*if (definition->transparencydepth == 0 || inside_length >= definition->transparencydepth)
|
||||
{
|
||||
col.a = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
col.a = inside_length / definition->transparencydepth;
|
||||
}*/
|
||||
|
||||
col = renderer->atmosphere->applyAerialPerspective(renderer, start, col).final;
|
||||
col.a = 0.0;
|
||||
|
||||
colorMask(&base, &col);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
Color cloudsLayerFilterLight(CloudsLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light)
|
||||
{
|
||||
/*double inside_depth, total_depth, factor;
|
||||
CloudSegment segments[MAX_SEGMENT_COUNT];
|
||||
|
||||
if (!cloudsOptimizeWalkingBounds(definition, &location, &light_location))
|
||||
{
|
||||
return light;
|
||||
}
|
||||
|
||||
_getPrimarySegments(definition, renderer, location, direction_to_light, MAX_SEGMENT_COUNT, definition->lighttraversal, v3Norm(v3Sub(light_location, location)), &inside_depth, &total_depth, segments);
|
||||
|
||||
if (definition->lighttraversal < 0.0001)
|
||||
{
|
||||
factor = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = inside_depth / definition->lighttraversal;
|
||||
if (factor > 1.0)
|
||||
{
|
||||
factor = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
factor = 1.0 - (1.0 - definition->minimumlight) * factor;
|
||||
|
||||
light.r = light.r * factor;
|
||||
light.g = light.g * factor;
|
||||
light.b = light.b * factor;*/
|
||||
|
||||
return light;
|
||||
}
|
|
@ -2,6 +2,47 @@
|
|||
|
||||
#include "../renderer.h"
|
||||
|
||||
/**
|
||||
* Control of the next walking order.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CLOUD_WALKING_CONTINUE,
|
||||
CLOUD_WALKING_STOP,
|
||||
CLOUD_WALKING_REFINE,
|
||||
CLOUD_WALKING_SUBDIVIDE
|
||||
} CloudWalkingOrder;
|
||||
|
||||
/**
|
||||
* Additional info for walking orders.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
CloudWalkingOrder order;
|
||||
double precision;
|
||||
int max_segments;
|
||||
} CloudWalkingNextAction;
|
||||
|
||||
/*
|
||||
* Private structure for the walker.
|
||||
*/
|
||||
struct CloudsWalker
|
||||
{
|
||||
Vector3 start;
|
||||
Vector3 end;
|
||||
Vector3 diff;
|
||||
|
||||
double cursor;
|
||||
double max_length;
|
||||
double step_size;
|
||||
|
||||
int started;
|
||||
CloudWalkerStepInfo last_segment;
|
||||
|
||||
CloudWalkingNextAction next_action;
|
||||
};
|
||||
|
||||
|
||||
int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Vector3* end)
|
||||
{
|
||||
Vector3 diff;
|
||||
|
@ -51,107 +92,176 @@ int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Ve
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO Limit the search length */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cloudsGetLayerPrimarySegments(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end, int max_segments, CloudPrimarySegment* out_segments)
|
||||
CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end)
|
||||
{
|
||||
int inside, segment_count;
|
||||
double step_length, segment_length;
|
||||
Vector3 diff, walker, segment_start;
|
||||
double render_precision, density;
|
||||
double diff_length, progress;
|
||||
CloudsWalker* result;
|
||||
|
||||
if (max_segments <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
result = (CloudsWalker*)malloc(sizeof (CloudsWalker));
|
||||
|
||||
if (!cloudsOptimizeWalkingBounds(layer, &start, &end))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
result->start = start;
|
||||
result->end = end;
|
||||
result->diff = v3Sub(end, start);
|
||||
result->max_length = v3Norm(result->diff);
|
||||
result->cursor = 0.0;
|
||||
result->step_size = 1.0;
|
||||
|
||||
diff = v3Sub(end, start);
|
||||
diff_length = v3Norm(diff);
|
||||
result->started = 0;
|
||||
result->last_segment.renderer = renderer;
|
||||
result->last_segment.layer = layer;
|
||||
|
||||
if (diff_length < 0.000001)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
result->next_action.order = CLOUD_WALKING_CONTINUE;
|
||||
|
||||
render_precision = 1.005 - 0.01 * (double)(renderer->render_quality * renderer->render_quality);
|
||||
/*if (render_precision > max_total_length / 10.0)
|
||||
{
|
||||
render_precision = max_total_length / 10.0;
|
||||
}
|
||||
else if (render_precision < max_total_length / 10000.0)
|
||||
{
|
||||
render_precision = max_total_length / 10000.0;
|
||||
}*/
|
||||
|
||||
segment_count = 0;
|
||||
segment_length = 0.0;
|
||||
density = renderer->clouds->getLayerDensity(renderer, layer, start);
|
||||
progress = 0.0;
|
||||
step_length = render_precision;
|
||||
inside = (density > 0.0);
|
||||
|
||||
do
|
||||
{
|
||||
progress += step_length;
|
||||
walker = v3Add(start, v3Scale(diff, progress / diff_length));
|
||||
|
||||
if (progress >= diff_length)
|
||||
{
|
||||
density = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
density = renderer->clouds->getLayerDensity(renderer, layer, walker);
|
||||
}
|
||||
|
||||
if (density > 0.0)
|
||||
{
|
||||
if (inside)
|
||||
{
|
||||
/* inside the cloud */
|
||||
segment_length += step_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* entering the cloud */
|
||||
segment_length = step_length;
|
||||
segment_start = v3Add(start, v3Scale(diff, (progress - step_length) / diff_length));
|
||||
/* TODO Refine entry position */
|
||||
|
||||
inside = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inside)
|
||||
{
|
||||
/* exiting the cloud */
|
||||
segment_length += step_length;
|
||||
|
||||
out_segments->enter = segment_start;
|
||||
out_segments->exit = walker;
|
||||
out_segments->length = segment_length;
|
||||
out_segments++;
|
||||
if (++segment_count >= max_segments)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* TODO Refine exit position */
|
||||
|
||||
inside = 0;
|
||||
}
|
||||
}
|
||||
/* step = v3Scale(direction, (info.distance_to_edge < render_precision) ? render_precision : info.distance_to_edge); */
|
||||
}
|
||||
while (inside || (walker.y <= layer->lower_altitude + layer->thickness + 0.001 && walker.y >= layer->lower_altitude - 0.001 && progress < diff_length));
|
||||
|
||||
return segment_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
void cloudsDeleteWalker(CloudsWalker* walker)
|
||||
{
|
||||
free(walker);
|
||||
}
|
||||
|
||||
void cloudsWalkerSetStepSize(CloudsWalker* walker, double step)
|
||||
{
|
||||
if (step > 0.0)
|
||||
{
|
||||
walker->step_size = step;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO Automatic settings (using rendering quality and cloud feature size) */
|
||||
walker->step_size = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _getPoint(CloudsWalker* walker, double cursor, CloudWalkerPoint* out_point)
|
||||
{
|
||||
out_point->distance_from_start = cursor;
|
||||
out_point->location = v3Add(walker->start, v3Scale(walker->diff, out_point->distance_from_start / walker->max_length));
|
||||
|
||||
Renderer* renderer = walker->last_segment.renderer;
|
||||
CloudsLayerDefinition* layer = walker->last_segment.layer;
|
||||
out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location);
|
||||
}
|
||||
|
||||
static void _refineSegment(CloudsWalker* walker, double start_cursor, double start_density, double end_cursor, double end_density, double precision, CloudWalkerPoint* result)
|
||||
{
|
||||
CloudWalkerPoint middle;
|
||||
|
||||
_getPoint(walker, (start_cursor + end_cursor) / 2.0, &middle);
|
||||
|
||||
if (start_density == 0.0)
|
||||
{
|
||||
/* Looking for entry */
|
||||
if (middle.distance_from_start - start_cursor < precision)
|
||||
{
|
||||
*result = middle;
|
||||
}
|
||||
else if (middle.global_density == 0.0)
|
||||
{
|
||||
_refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Looking for exit */
|
||||
if (end_cursor - middle.distance_from_start < precision)
|
||||
{
|
||||
*result = middle;
|
||||
}
|
||||
else if (middle.global_density == 0.0)
|
||||
{
|
||||
_refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cloudsWalkerPerformStep(CloudsWalker* walker)
|
||||
{
|
||||
if (!walker->started)
|
||||
{
|
||||
_getPoint(walker, 0.0, &walker->last_segment.end);
|
||||
walker->started = 1;
|
||||
}
|
||||
|
||||
if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length)
|
||||
{
|
||||
walker->next_action.order = CLOUD_WALKING_STOP;
|
||||
return 0;
|
||||
}
|
||||
else if (walker->next_action.order == CLOUD_WALKING_CONTINUE)
|
||||
{
|
||||
/* TODO Limit to end */
|
||||
walker->last_segment.start = walker->last_segment.end;
|
||||
|
||||
walker->cursor += walker->step_size;
|
||||
|
||||
_getPoint(walker, walker->cursor, &walker->last_segment.end);
|
||||
walker->last_segment.length = walker->step_size;
|
||||
walker->last_segment.refined = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (walker->next_action.order == CLOUD_WALKING_REFINE)
|
||||
{
|
||||
/* Refine segment with dichotomy */
|
||||
_refineSegment(walker,
|
||||
walker->last_segment.start.distance_from_start,
|
||||
walker->last_segment.start.global_density,
|
||||
walker->last_segment.end.distance_from_start,
|
||||
walker->last_segment.end.global_density,
|
||||
walker->next_action.precision,
|
||||
(walker->last_segment.start.global_density == 0.0) ? (&walker->last_segment.start) : (&walker->last_segment.end));
|
||||
walker->last_segment.length = walker->last_segment.end.distance_from_start - walker->last_segment.start.distance_from_start;
|
||||
walker->last_segment.refined = 1;
|
||||
|
||||
walker->next_action.order = CLOUD_WALKING_CONTINUE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cloudsWalkerOrderStop(CloudsWalker* walker)
|
||||
{
|
||||
walker->next_action.order = CLOUD_WALKING_STOP;
|
||||
}
|
||||
|
||||
void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision)
|
||||
{
|
||||
walker->next_action.order = CLOUD_WALKING_REFINE;
|
||||
walker->next_action.precision = precision;
|
||||
}
|
||||
|
||||
void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments)
|
||||
{
|
||||
walker->next_action.order = CLOUD_WALKING_SUBDIVIDE;
|
||||
walker->next_action.max_segments = max_segments;
|
||||
}
|
||||
|
||||
CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker)
|
||||
{
|
||||
return &walker->last_segment;
|
||||
}
|
||||
|
||||
void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data)
|
||||
{
|
||||
walker->last_segment.data = data;
|
||||
while (cloudsWalkerPerformStep(walker))
|
||||
{
|
||||
callback(walker);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,33 @@ extern "C"
|
|||
|
||||
typedef struct
|
||||
{
|
||||
Vector3 enter;
|
||||
Vector3 exit;
|
||||
double distance_from_start;
|
||||
Vector3 location;
|
||||
double global_density;
|
||||
} CloudWalkerPoint;
|
||||
|
||||
/**
|
||||
* Information on a segment yielded by walking.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Renderer* renderer;
|
||||
CloudsLayerDefinition* layer;
|
||||
|
||||
CloudWalkerPoint start;
|
||||
CloudWalkerPoint end;
|
||||
double length;
|
||||
} CloudPrimarySegment;
|
||||
|
||||
int refined;
|
||||
/*int subdivision_level;
|
||||
double precision_asked;*/
|
||||
|
||||
void* data;
|
||||
} CloudWalkerStepInfo;
|
||||
|
||||
typedef struct CloudsWalker CloudsWalker;
|
||||
|
||||
typedef void (*FuncCloudsWalkingCallback)(CloudsWalker* walker);
|
||||
|
||||
/**
|
||||
* Optimize the search limits in a layer.
|
||||
|
@ -31,17 +54,81 @@ typedef struct
|
|||
int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Vector3* end);
|
||||
|
||||
/**
|
||||
* Go through the cloud layer to find segments (parts of the lookup that are likely to contain cloud).
|
||||
* Create a cloud walker.
|
||||
*
|
||||
* @param renderer The renderer environment
|
||||
* @param layer The cloud layer
|
||||
* @param start Start position of the lookup
|
||||
* @param end End position of the lookup
|
||||
* @param max_segments Maximum number of segments to collect
|
||||
* @param out_segments Allocated space to fill found segments
|
||||
* @return Number of segments found
|
||||
* For better performance, the segment should by optimized using cloudsOptimizeWalkingBounds.
|
||||
* @param renderer Renderer context
|
||||
* @param layer The cloud layer to traverse
|
||||
* @param start Start of the walk
|
||||
* @param end End of the walk
|
||||
*/
|
||||
int cloudsGetLayerPrimarySegments(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end, int max_segments, CloudPrimarySegment* out_segments);
|
||||
CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end);
|
||||
|
||||
/**
|
||||
* Delete a cloud walker.
|
||||
*
|
||||
* @param walker The walker to free
|
||||
*/
|
||||
void cloudsDeleteWalker(CloudsWalker* walker);
|
||||
|
||||
/**
|
||||
* Define the segment size for next steps.
|
||||
*
|
||||
* @param walker The walker to configure
|
||||
* @param step The step length, negative for automatic
|
||||
*/
|
||||
void cloudsWalkerSetStepSize(CloudsWalker* walker, double step);
|
||||
|
||||
/**
|
||||
* Perform a single step.
|
||||
*
|
||||
* @param walker The walker to use
|
||||
* @return 1 to continue the loop, 0 to stop
|
||||
*/
|
||||
int cloudsWalkerPerformStep(CloudsWalker* walker);
|
||||
|
||||
/**
|
||||
* Order the walker to stop.
|
||||
*
|
||||
* @param walker The walker to use
|
||||
*/
|
||||
void cloudsWalkerOrderStop(CloudsWalker* walker);
|
||||
|
||||
/**
|
||||
* Order the walker to refine the search for cloud entry or exit.
|
||||
*
|
||||
* The refinement will next yield a shorter version of the segment, containing only the cloud-inside portion, with a
|
||||
* tolerance fixed by precision. For an entry point, this will discard the part before cloud entry. For en exit point,
|
||||
* the portion after this point will be part of the next step, as normal walking resumes.
|
||||
* @param walker The walker to use
|
||||
* @param precision Precision wanted for the refinement
|
||||
*/
|
||||
void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision);
|
||||
|
||||
/**
|
||||
* Order the walker to subdivide the previous segment in smaller segments.
|
||||
*
|
||||
* @param walker The walker to use
|
||||
* @param max_segments Maximal number of segments
|
||||
*/
|
||||
void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments);
|
||||
|
||||
/**
|
||||
* Get the last segment information.
|
||||
*
|
||||
* @param walker The walker to use
|
||||
*/
|
||||
CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker);
|
||||
|
||||
/**
|
||||
* Start walking automatically through a segment.
|
||||
*
|
||||
* The callback will be called with each segment found, giving info and asking for desired alteration on walking.
|
||||
* @param walker The walker to use
|
||||
* @param callback Callback to be called with each found segment
|
||||
* @param data User data that will be passed back in the callback
|
||||
*/
|
||||
void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -80,12 +80,6 @@ LayerType cloudsGetLayerType();
|
|||
void cloudsAutoPreset(CloudsDefinition* definition, CloudsPreset preset);
|
||||
void cloudsLayerAutoPreset(CloudsLayerDefinition* definition, CloudsLayerPreset preset);
|
||||
|
||||
Renderer* cloudsCreatePreviewCoverageRenderer();
|
||||
Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling, int perspective);
|
||||
|
||||
Renderer* cloudsCreatePreviewColorRenderer();
|
||||
Color cloudsGetPreviewColor(Renderer* renderer, double x, double y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,11 @@ static inline void _add_methods_to_case(TCase* tc, ...)
|
|||
suite_add_tcase(s, tc); \
|
||||
}
|
||||
|
||||
/***** Boolean assertions *****/
|
||||
#define ck_assert_true(_X_) ck_assert_int_ne((_X_), 0)
|
||||
#define ck_assert_false(_X_) ck_assert_int_eq((_X_), 0)
|
||||
|
||||
/***** Floating point assertions *****/
|
||||
static inline int _double_equals(double x, double y)
|
||||
{
|
||||
return fabs(x - y) < 0.00000000001;
|
||||
|
|
|
@ -200,11 +200,9 @@ static double _getLayerDensitySinX(Renderer* renderer, CloudsLayerDefinition* la
|
|||
return (density > 0.0) ? density : 0.0;
|
||||
}
|
||||
|
||||
START_TEST(test_clouds_primary_segments)
|
||||
START_TEST(test_clouds_walking)
|
||||
{
|
||||
int segment_count, i;
|
||||
CloudPrimarySegment segments[10];
|
||||
|
||||
/* Init */
|
||||
CloudsLayerDefinition* layer;
|
||||
layer = cloudsGetLayerType().callback_create();
|
||||
layer->lower_altitude = -1.0;
|
||||
|
@ -217,36 +215,88 @@ START_TEST(test_clouds_primary_segments)
|
|||
renderer->render_quality = 8;
|
||||
renderer->clouds->getLayerDensity = _getLayerDensitySinX;
|
||||
|
||||
segment_count = cloudsGetLayerPrimarySegments(renderer, layer, v3(-0.4, 0.0, 0.0), v3(1.9, 0.0, 0.0), 10, segments);
|
||||
ck_assert_int_eq(segment_count, 2);
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
ck_assert_double_eq(segments[i].enter.y, 0.0);
|
||||
ck_assert_double_eq(segments[i].enter.z, 0.0);
|
||||
ck_assert_double_eq(segments[i].exit.y, 0.0);
|
||||
ck_assert_double_eq(segments[i].exit.z, 0.0);
|
||||
}
|
||||
ck_assert_double_in_range(segments[0].enter.x, -0.5, 0.0);
|
||||
ck_assert_double_in_range(segments[0].exit.x, 0.5, 1.0);
|
||||
ck_assert_double_in_range(segments[0].length, 0.5, 1.5);
|
||||
ck_assert_double_gte(segments[1].enter.x, segments[0].exit.x);
|
||||
ck_assert_double_in_range(segments[1].enter.x, 0.5, 1.0);
|
||||
ck_assert_double_in_range(segments[1].exit.x, 1.5, 2.0);
|
||||
ck_assert_double_in_range(segments[1].length, 0.5, 1.5);
|
||||
CloudsWalker* walker = cloudsCreateWalker(renderer, layer, v3(-0.4, 0.0, 0.0), v3(10.0, 0.0, 0.0));
|
||||
CloudWalkerStepInfo* segment;
|
||||
int result;
|
||||
|
||||
/* First step */
|
||||
cloudsWalkerSetStepSize(walker, 0.3);
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_false(segment->refined);
|
||||
ck_assert_double_eq(segment->length, 0.3);
|
||||
ck_assert_double_eq(segment->start.distance_from_start, 0.0);
|
||||
ck_assert_vector_values(segment->start.location, -0.4, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->start.global_density, 0.0);
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 0.3);
|
||||
ck_assert_vector_values(segment->end.location, -0.1, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->end.global_density, 0.0);
|
||||
|
||||
/* Second step */
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_false(segment->refined);
|
||||
ck_assert_double_eq(segment->length, 0.3);
|
||||
ck_assert_double_eq(segment->start.distance_from_start, 0.3);
|
||||
ck_assert_vector_values(segment->start.location, -0.1, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->start.global_density, 0.0);
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 0.6);
|
||||
ck_assert_vector_values(segment->end.location, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_gt(segment->end.global_density, 0.9);
|
||||
|
||||
/* Order to refine second step around the entry point */
|
||||
cloudsWalkerOrderRefine(walker, 0.01);
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_true(segment->refined);
|
||||
ck_assert_double_in_range(segment->length, 0.19, 0.20);
|
||||
ck_assert_double_in_range(segment->start.distance_from_start, 0.40, 0.41);
|
||||
ck_assert_double_in_range(segment->start.location.x, 0.0, 0.01);
|
||||
ck_assert_double_gt(segment->start.global_density, 0.0);
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 0.6);
|
||||
ck_assert_vector_values(segment->end.location, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_gt(segment->end.global_density, 0.9);
|
||||
|
||||
/* Third step, change step size */
|
||||
cloudsWalkerSetStepSize(walker, 0.4);
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_false(segment->refined);
|
||||
ck_assert_double_eq(segment->length, 0.4);
|
||||
ck_assert_double_eq(segment->start.distance_from_start, 0.6);
|
||||
ck_assert_vector_values(segment->start.location, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_gt(segment->start.global_density, 0.9);
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 1.0);
|
||||
ck_assert_vector_values(segment->end.location, 0.6, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->end.global_density, 0.0);
|
||||
|
||||
/* Refine exit point */
|
||||
cloudsWalkerOrderRefine(walker, 0.001);
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_true(segment->refined);
|
||||
ck_assert_double_in_range(segment->length, 0.3, 0.301);
|
||||
ck_assert_double_eq(segment->start.distance_from_start, 0.6);
|
||||
ck_assert_vector_values(segment->start.location, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_gt(segment->start.global_density, 0.9);
|
||||
ck_assert_double_in_range(segment->end.distance_from_start, 0.9, 0.901);
|
||||
ck_assert_double_in_range(segment->end.location.x, 0.5, 0.501);
|
||||
ck_assert_double_lt(segment->end.global_density, 0.1);
|
||||
|
||||
/* Clean up */
|
||||
cloudsDeleteWalker(walker);
|
||||
|
||||
cloudsGetLayerType().callback_delete(layer);
|
||||
rendererDelete(renderer);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_clouds_preview_color)
|
||||
{
|
||||
Renderer* renderer = cloudsCreatePreviewColorRenderer();
|
||||
|
||||
/* TODO Test the density overriding */
|
||||
|
||||
rendererDelete(renderer);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_CASE(clouds, test_clouds_density, test_clouds_walking_boundaries, test_clouds_primary_segments, test_clouds_preview_color)
|
||||
TEST_CASE(clouds,
|
||||
test_clouds_density,
|
||||
test_clouds_walking_boundaries,
|
||||
test_clouds_walking)
|
||||
|
|
Loading…
Reference in a new issue