From 5c7ba1d4fc2668aa5c1142d2b81f5f2d01a206a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 22 Jan 2013 20:50:37 +0000 Subject: [PATCH] paysages : Clouds refactoring (WIP). git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@505 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- gui_qt/formclouds.cpp | 134 +----- gui_qt/formclouds.h | 7 +- gui_qt/formtextures.cpp | 21 - lib_paysages/Makefile | 4 +- lib_paysages/atmosphere/bruneton.c | 7 +- lib_paysages/atmosphere/main.c | 7 - lib_paysages/atmosphere/raster.c | 2 +- lib_paysages/auto.c | 10 +- lib_paysages/camera.c | 1 + lib_paysages/clouds.c | 685 ----------------------------- lib_paysages/clouds.h | 83 ---- lib_paysages/clouds/definition.c | 205 +++++++++ lib_paysages/clouds/presets.c | 83 ++++ lib_paysages/clouds/preview.c | 65 +++ lib_paysages/clouds/private.h | 21 + lib_paysages/clouds/public.h | 85 ++++ lib_paysages/clouds/rendering.c | 100 +++++ lib_paysages/clouds/tools.c | 374 ++++++++++++++++ lib_paysages/renderer.c | 8 +- lib_paysages/renderer.h | 3 +- lib_paysages/scenery.c | 25 +- lib_paysages/scenery.h | 2 +- lib_paysages/terrain/main.c | 4 +- lib_paysages/tools/color.c | 21 +- lib_paysages/tools/lighting.c | 3 +- lib_paysages/tools/lighting.h | 2 +- lib_paysages/water.c | 2 +- 27 files changed, 1007 insertions(+), 957 deletions(-) delete mode 100644 lib_paysages/clouds.c delete mode 100644 lib_paysages/clouds.h create mode 100644 lib_paysages/clouds/definition.c create mode 100644 lib_paysages/clouds/presets.c create mode 100644 lib_paysages/clouds/preview.c create mode 100644 lib_paysages/clouds/private.h create mode 100644 lib_paysages/clouds/public.h create mode 100644 lib_paysages/clouds/rendering.c create mode 100644 lib_paysages/clouds/tools.c diff --git a/gui_qt/formclouds.cpp b/gui_qt/formclouds.cpp index 38792fb..650fbfc 100644 --- a/gui_qt/formclouds.cpp +++ b/gui_qt/formclouds.cpp @@ -1,6 +1,5 @@ #include "formclouds.h" -#include "../lib_paysages/clouds.h" #include "../lib_paysages/tools/color.h" #include "../lib_paysages/tools/euclid.h" #include "../lib_paysages/scenery.h" @@ -13,48 +12,34 @@ class PreviewCloudsCoverage:public BasePreview public: PreviewCloudsCoverage(QWidget* parent, CloudsLayerDefinition* layer):BasePreview(parent) { - _renderer = rendererCreate(); - _renderer->render_quality = 5; - //_renderer.applyLightStatus = _applyLightStatus; + _renderer = cloudsCreatePreviewCoverageRenderer(); _original_layer = layer; - _preview_layer = cloudsLayerCreateDefinition(); + _preview_definition = (CloudsDefinition*)CloudsDefinitionClass.create(); configScaling(100.0, 1000.0, 20.0, 200.0); } ~PreviewCloudsCoverage() { - cloudsLayerDeleteDefinition(_preview_layer); + CloudsDefinitionClass.destroy(_preview_definition); rendererDelete(_renderer); } protected: Color getColor(double x, double y) { - Vector3 eye, look; - - eye.x = 0.0; - eye.y = scaling; - eye.z = -10.0 * scaling; - look.x = x * 0.01 / scaling; - look.y = -y * 0.01 / scaling - 0.3; - look.z = 1.0; - look = v3Normalize(look); - - return cloudsApplyLayer(_preview_layer, COLOR_BLUE, _renderer, eye, v3Add(eye, v3Scale(look, 1000.0))); + return cloudsGetPreviewCoverage(_renderer, x, y, scaling); } void updateData() { - cloudsLayerCopyDefinition(_original_layer, _preview_layer); - } - static Color _applyLightStatus(Renderer*, LightStatus*, Vector3, Vector3, SurfaceMaterial) - { - return COLOR_WHITE; + layersDeleteLayer(_preview_definition->layers, 0); + layersAddLayer(_preview_definition->layers, _original_layer); + CloudsRendererClass.bind(_renderer, _preview_definition); } private: Renderer* _renderer; CloudsLayerDefinition* _original_layer; - CloudsLayerDefinition* _preview_layer; + CloudsDefinition* _preview_definition; }; class PreviewCloudsColor:public BasePreview @@ -62,92 +47,28 @@ class PreviewCloudsColor:public BasePreview public: PreviewCloudsColor(QWidget* parent, CloudsLayerDefinition* layer):BasePreview(parent) { - LightDefinition light; - _original_layer = layer; - _preview_layer = cloudsLayerCreateDefinition(); + _preview_definition = (CloudsDefinition*)CloudsDefinitionClass.create(); - /*_lighting = lightingCreateDefinition(); - light.color = COLOR_WHITE; - light.direction.x = -1.0; - light.direction.y = -1.0; - light.direction.z = 1.0; - light.direction = v3Normalize(light.direction); - light.filtered = 0; - light.masked = 1; - light.reflection = 1.0; - lightingAddLight(&_lighting, light); - lightingValidateDefinition(&_lighting);*/ - - _renderer = rendererCreate(); - _renderer->render_quality = 8; - /*_renderer.alterLight = _alterLight; - _renderer.getLightStatus = _getLightStatus;*/ - _renderer->customData[0] = _preview_layer; - //_renderer.customData[1] = &_lighting; + _renderer = cloudsCreatePreviewColorRenderer(); configScaling(0.5, 2.0, 0.1, 2.0); } protected: Color getColor(double x, double y) { - Vector3 start, end; - - start.x = x * _preview_layer->thickness * 0.5; - start.y = -y * _preview_layer->thickness * 0.5; - start.z = _preview_layer->thickness * 0.5; - - end.x = x * _preview_layer->thickness * 0.5; - end.y = -y * _preview_layer->thickness * 0.5; - end.z = -_preview_layer->thickness * 0.5; - - return cloudsApplyLayer(_preview_layer, COLOR_BLUE, _renderer, start, end); + return cloudsGetPreviewColor(_renderer, x, y); } void updateData() { - cloudsLayerCopyDefinition(_original_layer, _preview_layer); - //noiseForceValue(_preview_layer->shape_noise, 1.0); - _preview_layer->lower_altitude = -_preview_layer->thickness * 0.5; - //curveClear(_preview_layer->coverage_by_altitude); - _preview_layer->base_coverage = 1.0; - _preview_layer->_custom_coverage = _coverageFunc; + layersDeleteLayer(_preview_definition->layers, 0); + layersAddLayer(_preview_definition->layers, _original_layer); + CloudsRendererClass.bind(_renderer, _preview_definition); } private: Renderer* _renderer; CloudsLayerDefinition* _original_layer; - CloudsLayerDefinition* _preview_layer; - //LightingDefinition _lighting; - - static double _coverageFunc(CloudsLayerDefinition* layer, Vector3 position) - { - double coverage = curveGetValue(layer->_coverage_by_altitude, position.y / layer->thickness + 0.5); - position.y = 0.0; - double dist = v3Norm(position); - - if (dist >= layer->thickness * 0.5) - { - return 0.0; - } - else if (dist < layer->thickness * 0.4) - { - return coverage; - } - else - { - double density = 1.0 - (dist - (layer->thickness * 0.4)) / (layer->thickness * 0.1); - return (density < coverage) ? density : coverage; - } - } - - /*static void _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) - { - light->color = cloudsLayerFilterLight((CloudsLayerDefinition*)renderer->customData[0], renderer, light->color, location, v3Scale(light->direction, -1000.0), v3Scale(light->direction, -1.0)); - } - - static void _getLightStatus(Renderer* renderer, LightStatus* status, Vector3 location) - { - lightingGetStatus((LightingDefinition*)renderer->customData[1], renderer, location, status); - }*/ + CloudsDefinition* _preview_definition; }; /**************** Form ****************/ @@ -159,8 +80,8 @@ FormClouds::FormClouds(QWidget *parent): addAutoPreset(tr("Stratocumulus")); addAutoPreset(tr("Stratus")); - _definition = cloudsCreateDefinition(); - _layer = cloudsLayerCreateDefinition(); + _definition = (CloudsDefinition*)CloudsDefinitionClass.create(); + _layer = (CloudsLayerDefinition*)cloudsGetLayerType().callback_create(); _previewCoverage = new PreviewCloudsCoverage(parent, _layer); _previewColor = new PreviewCloudsColor(parent, _layer); @@ -171,10 +92,7 @@ FormClouds::FormClouds(QWidget *parent): addInputDouble(tr("Lower altitude"), &_layer->lower_altitude, -10.0, 50.0, 0.5, 5.0); addInputDouble(tr("Layer thickness"), &_layer->thickness, 0.0, 20.0, 0.1, 1.0); addInputDouble(tr("Max coverage"), &_layer->base_coverage, 0.0, 1.0, 0.01, 0.1); -// addInputCurve(tr("Coverage by altitude"), _layer->_coverage_by_altitude, 0.0, 1.0, 0.0, 1.0, tr("Altitude in cloud layer"), tr("Coverage value")); -// addInputNoise(tr("Shape noise"), _layer->_shape_noise); addInputDouble(tr("Shape scaling"), &_layer->shape_scaling, 3.0, 30.0, 0.3, 3.0); -// addInputNoise(tr("Edge noise"), _layer->_edge_noise); addInputDouble(tr("Edge scaling"), &_layer->edge_scaling, 0.5, 5.0, 0.05, 0.5); addInputDouble(tr("Edge length"), &_layer->edge_length, 0.0, 1.0, 0.01, 0.1); addInputMaterial(tr("Material"), &_layer->material); @@ -183,40 +101,34 @@ FormClouds::FormClouds(QWidget *parent): addInputDouble(tr("Light traversal depth"), &_layer->lighttraversal, 0.0, 10.0, 0.1, 1.0); addInputDouble(tr("Minimum lighting"), &_layer->minimumlight, 0.0, 1.0, 0.01, 0.1); - setLayers(_definition.layers); + setLayers(_definition->layers); } void FormClouds::revertConfig() { - sceneryGetClouds(&_definition); + sceneryGetClouds(_definition); BaseFormLayer::revertConfig(); } void FormClouds::applyConfig() { BaseFormLayer::applyConfig(); - scenerySetClouds(&_definition); -} - -void FormClouds::configChangeEvent() -{ - cloudsLayerValidateDefinition(_layer); - BaseFormLayer::configChangeEvent(); + scenerySetClouds(_definition); } void FormClouds::layerReadCurrentFrom(void* layer_definition) { - cloudsLayerCopyDefinition((CloudsLayerDefinition*)layer_definition, _layer); + cloudsGetLayerType().callback_copy((CloudsLayerDefinition*)layer_definition, _layer); } void FormClouds::layerWriteCurrentTo(void* layer_definition) { - cloudsLayerCopyDefinition(_layer, (CloudsLayerDefinition*)layer_definition); + cloudsGetLayerType().callback_copy(_layer, (CloudsLayerDefinition*)layer_definition); } void FormClouds::autoPresetSelected(int preset) { - cloudsLayerAutoPreset(_layer, (CloudsPreset)preset); + cloudsAutoPreset(_layer, (CloudsPreset)preset); BaseForm::autoPresetSelected(preset); } diff --git a/gui_qt/formclouds.h b/gui_qt/formclouds.h index 5a64018..73e100c 100644 --- a/gui_qt/formclouds.h +++ b/gui_qt/formclouds.h @@ -4,7 +4,7 @@ #include #include "basepreview.h" #include "baseformlayer.h" -#include "../lib_paysages/clouds.h" +#include "../lib_paysages/clouds/public.h" class FormClouds : public BaseFormLayer { @@ -22,11 +22,8 @@ protected: virtual void layerWriteCurrentTo(void* layer_definition); virtual void autoPresetSelected(int preset); -protected slots: - virtual void configChangeEvent(); - private: - CloudsDefinition _definition; + CloudsDefinition* _definition; CloudsLayerDefinition* _layer; BasePreview* _previewCoverage; BasePreview* _previewColor; diff --git a/gui_qt/formtextures.cpp b/gui_qt/formtextures.cpp index 5e1c529..cecb501 100644 --- a/gui_qt/formtextures.cpp +++ b/gui_qt/formtextures.cpp @@ -65,26 +65,11 @@ class PreviewTexturesColor:public BasePreview public: PreviewTexturesColor(QWidget* parent, TextureLayerDefinition* layer):BasePreview(parent) { - LightDefinition light; - _original_layer = layer; _preview_layer = texturesLayerCreateDefinition(); - /*_lighting = lightingCreateDefinition(); - light.color = COLOR_WHITE; - light.direction.x = 0.0; - light.direction.y = -0.4794; - light.direction.z = 0.8776; - light.filtered = 0; - light.masked = 0; - light.reflection = 1.0; - lightingAddLight(&_lighting, light); - lightingValidateDefinition(&_lighting);*/ - _renderer = rendererCreate(); _renderer->render_quality = 3; - /*_renderer->getLightStatus = _getLightStatus; - _renderer->customData[0] = &_lighting;*/ _renderer->camera_location.x = 0.0; _renderer->camera_location.y = 20.0; _renderer->camera_location.z = 0.0; @@ -117,12 +102,6 @@ private: Renderer* _renderer; TextureLayerDefinition* _original_layer; TextureLayerDefinition* _preview_layer; - //LightingDefinition _lighting; - - /*static void _getLightStatus(Renderer* renderer, LightStatus* status, Vector3 location) - { - lightingGetStatus((LightingDefinition*)renderer->customData[0], renderer, location, status); - }*/ }; /**************** Form ****************/ diff --git a/lib_paysages/Makefile b/lib_paysages/Makefile index f06c8f4..4df0092 100644 --- a/lib_paysages/Makefile +++ b/lib_paysages/Makefile @@ -1,9 +1,9 @@ BUILDMODE = debug BUILDPATH = ../build/${BUILDMODE} OBJPATH = ./obj/${BUILDMODE} -SOURCES = $(wildcard *.c atmosphere/*.c terrain/*.c tools/*.c) +SOURCES = $(wildcard *.c atmosphere/*.c clouds/*.c terrain/*.c tools/*.c) OBJECTS = ${SOURCES:%.c=${OBJPATH}/%.o} -HEADERS = $(wildcard *.h atmosphere/*.h terrain/*.h tools/*.h shared/*.h) +HEADERS = $(wildcard *.h atmosphere/*.h clouds/*.h terrain/*.h tools/*.h shared/*.h) RESULT = ${BUILDPATH}/libpaysages.so LIBS = glib-2.0 gthread-2.0 IL ILU CC_FLAGS = -Wall -fPIC -DHAVE_GLIB=1 diff --git a/lib_paysages/atmosphere/bruneton.c b/lib_paysages/atmosphere/bruneton.c index 23c26ea..bc757cf 100644 --- a/lib_paysages/atmosphere/bruneton.c +++ b/lib_paysages/atmosphere/bruneton.c @@ -19,7 +19,7 @@ /*********************** Constants ***********************/ #define WORLD_SCALING 0.05 -#define GROUND_OFFSET 10.0 +#define GROUND_OFFSET 0.5 static const double Rg = 6360.0; static const double Rt = 6420.0; static const double RL = 6421.0; @@ -27,7 +27,7 @@ static const double exposure = 0.4; static const double ISun = 100.0; static const double AVERAGE_GROUND_REFLECTANCE = 0.1; -#if 0 +#if 1 #define RES_MU 128 #define RES_MU_S 32 #define RES_R 32 @@ -825,6 +825,7 @@ static Color _getInscatterColor(Vector3* _x, double* _t, Vector3 v, Vector3 s, d double r = v3Norm(*_x); double mu = v3Dot(*_x, v) / r; double d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt); + attenuation->x = attenuation->y = attenuation->z = 0.0; if (d > 0.0) { /* if x in space and ray intersects atmosphere @@ -1218,7 +1219,7 @@ void brunetonGetLightingStatus(Renderer* renderer, LightStatus* status, Vector3 /*irradiance.color.r *= 100.0; irradiance.color.g *= 100.0; irradiance.color.b *= 100.0;*/ - irradiance.direction = v3Scale(normal, -1.0); + irradiance.direction = VECTOR_DOWN; irradiance.reflection = 0.0; irradiance.altered = 0; diff --git a/lib_paysages/atmosphere/main.c b/lib_paysages/atmosphere/main.c index b845617..a176c04 100644 --- a/lib_paysages/atmosphere/main.c +++ b/lib_paysages/atmosphere/main.c @@ -116,13 +116,6 @@ static Color _fakeGetSkyColor(Renderer* renderer, Vector3 direction) UNUSED(direction); return COLOR_WHITE; } -static int _fakeGetSkydomeLights(Renderer* renderer, LightDefinition* lights, int max_lights) -{ - UNUSED(renderer); - UNUSED(lights); - UNUSED(max_lights); - return 0; -} static Color _getSkyColor(Renderer* renderer, Vector3 direction) { diff --git a/lib_paysages/atmosphere/raster.c b/lib_paysages/atmosphere/raster.c index f9f26ad..432a603 100644 --- a/lib_paysages/atmosphere/raster.c +++ b/lib_paysages/atmosphere/raster.c @@ -17,7 +17,7 @@ static Color _postProcessFragment(Renderer* renderer, Vector3 location, void* da /* TODO Don't compute result->color if it's fully covered by clouds */ result = renderer->atmosphere->getSkyColor(renderer, v3Normalize(direction)); - result = renderer->applyClouds(renderer, result, renderer->camera_location, v3Add(renderer->camera_location, v3Scale(direction, 10.0))); + result = renderer->clouds->getColor(renderer, result, renderer->camera_location, v3Add(renderer->camera_location, v3Scale(direction, 10.0))); return result; } diff --git a/lib_paysages/auto.c b/lib_paysages/auto.c index f7b96d9..c2a915a 100644 --- a/lib_paysages/auto.c +++ b/lib_paysages/auto.c @@ -4,7 +4,6 @@ #include #include -#include "clouds.h" #include "render.h" #include "textures.h" #include "scenery.h" @@ -15,7 +14,6 @@ void autoGenRealisticLandscape(int seed) { WaterDefinition water; - CloudsDefinition clouds; TexturesDefinition textures; TextureLayerDefinition* texture; int layer; @@ -27,10 +25,10 @@ void autoGenRealisticLandscape(int seed) srand(seed); /* Cloud layer */ - clouds = cloudsCreateDefinition(); - layersAddLayer(clouds.layers, NULL); - scenerySetClouds(&clouds); - cloudsDeleteDefinition(&clouds); + CloudsDefinition* clouds = CloudsDefinitionClass.create(); + layer = layersAddLayer(clouds->layers, NULL); + scenerySetClouds(clouds); + CloudsDefinitionClass.destroy(clouds); /* Water */ water = waterCreateDefinition(); diff --git a/lib_paysages/camera.c b/lib_paysages/camera.c index d757b70..a515577 100644 --- a/lib_paysages/camera.c +++ b/lib_paysages/camera.c @@ -49,6 +49,7 @@ CameraDefinition cameraCreateDefinition() void cameraDeleteDefinition(CameraDefinition* definition) { + UNUSED(definition); } void cameraCopyDefinition(CameraDefinition* source, CameraDefinition* destination) diff --git a/lib_paysages/clouds.c b/lib_paysages/clouds.c deleted file mode 100644 index 9d02263..0000000 --- a/lib_paysages/clouds.c +++ /dev/null @@ -1,685 +0,0 @@ -#include "clouds.h" - -#include -#include -#include -#include "tools/color.h" -#include "tools/euclid.h" -#include "tools.h" - -#define CLOUDS_MAX_LAYERS 6 -#define MAX_SEGMENT_COUNT 30 - -typedef struct -{ - Vector3 start; - Vector3 end; - double length; -} CloudSegment; - -CloudsDefinition cloudsCreateDefinition() -{ - CloudsDefinition result; - - result.layers = layersCreate(cloudsGetLayerType(), CLOUDS_MAX_LAYERS); - - return result; -} - -void cloudsDeleteDefinition(CloudsDefinition* definition) -{ - layersDelete(definition->layers); -} - -void cloudsCopyDefinition(CloudsDefinition* source, CloudsDefinition* destination) -{ - layersCopy(source->layers, destination->layers); -} - -void cloudsValidateDefinition(CloudsDefinition* definition) -{ - layersValidate(definition->layers); -} - -void cloudsSave(PackStream* stream, CloudsDefinition* definition) -{ - layersSave(stream, definition->layers); -} - -void cloudsLoad(PackStream* stream, CloudsDefinition* definition) -{ - layersLoad(stream, definition->layers); -} - -static double _standardCoverageFunc(CloudsLayerDefinition* layer, Vector3 position) -{ - if (position.y < layer->lower_altitude || position.y >= layer->lower_altitude + layer->thickness) - { - return 0.0; - } - else - { - return layer->base_coverage * curveGetValue(layer->_coverage_by_altitude, (position.y - layer->lower_altitude) / layer->thickness); - } -} - -CloudsLayerDefinition* cloudsLayerCreateDefinition() -{ - CloudsLayerDefinition* result; - - result = malloc(sizeof(CloudsLayerDefinition)); - result->_coverage_by_altitude = curveCreate(); - result->_shape_noise = noiseCreateGenerator(); - result->_edge_noise = noiseCreateGenerator(); - - result->_custom_coverage = _standardCoverageFunc; - - cloudsLayerAutoPreset(result, CLOUDS_PRESET_CIRRUS); - - return result; -} - -void cloudsLayerDeleteDefinition(CloudsLayerDefinition* definition) -{ - curveDelete(definition->_coverage_by_altitude); - noiseDeleteGenerator(definition->_shape_noise); - noiseDeleteGenerator(definition->_edge_noise); - free(definition); -} - -void cloudsLayerAutoPreset(CloudsLayerDefinition* definition, CloudsPreset preset) -{ - definition->material.base.r = 0.7; - definition->material.base.g = 0.7; - definition->material.base.b = 0.7; - definition->material.base.a = 1.0; - - switch (preset) - { - case CLOUDS_PRESET_CIRRUS: - definition->type = CLOUDS_TYPE_CIRRUS; - definition->lower_altitude = 25.0; - definition->thickness = 2.0; - definition->material.reflection = 0.4; - definition->material.shininess = 0.5; - definition->hardness = 0.0; - definition->transparencydepth = 3.0; - definition->lighttraversal = 10.0; - definition->minimumlight = 0.6; - definition->shape_scaling = 8.0; - definition->edge_scaling = 2.0; - definition->edge_length = 0.8; - definition->base_coverage = 0.6; - break; - case CLOUDS_PRESET_CUMULUS: - definition->type = CLOUDS_TYPE_CUMULUS; - definition->lower_altitude = 15.0; - definition->thickness = 15.0; - definition->material.reflection = 0.5; - definition->material.shininess = 1.2; - definition->hardness = 0.25; - definition->transparencydepth = 1.5; - definition->lighttraversal = 8.0; - definition->minimumlight = 0.4; - definition->shape_scaling = 20.0; - definition->edge_scaling = 2.0; - definition->edge_length = 0.0; - definition->base_coverage = 0.7; - break; - case CLOUDS_PRESET_STRATOCUMULUS: - definition->type = CLOUDS_TYPE_STRATOCUMULUS; - definition->lower_altitude = 5.0; - definition->thickness = 6.0; - definition->material.reflection = 0.3; - definition->material.shininess = 0.8; - definition->hardness = 0.25; - definition->transparencydepth = 1.5; - definition->lighttraversal = 7.0; - definition->minimumlight = 0.4; - definition->shape_scaling = 10.0; - definition->edge_scaling = 0.8; - definition->edge_length = 0.3; - definition->base_coverage = 0.4; - break; - case CLOUDS_PRESET_STRATUS: - definition->type = CLOUDS_TYPE_STRATUS; - definition->lower_altitude = 3.0; - definition->thickness = 4.0; - definition->material.reflection = 0.1; - definition->material.shininess = 0.8; - definition->hardness = 0.1; - definition->transparencydepth = 3.0; - definition->lighttraversal = 10.0; - definition->minimumlight = 0.6; - definition->shape_scaling = 8.0; - definition->edge_scaling = 2.0; - definition->edge_length = 1.0; - definition->base_coverage = 0.4; - break; - default: - break; - } - - cloudsLayerValidateDefinition(definition); -} - -void cloudsLayerCopyDefinition(CloudsLayerDefinition* source, CloudsLayerDefinition* destination) -{ - CloudsLayerDefinition temp; - - temp = *destination; - *destination = *source; - - destination->_shape_noise = temp._shape_noise; - noiseCopy(source->_shape_noise, destination->_shape_noise); - - destination->_edge_noise = temp._edge_noise; - noiseCopy(source->_edge_noise, destination->_edge_noise); - - destination->_coverage_by_altitude = temp._coverage_by_altitude; - curveCopy(source->_coverage_by_altitude, destination->_coverage_by_altitude); -} - -void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition) -{ - if (definition->shape_scaling < 0.0001) - { - definition->shape_scaling = 0.00001; - } - if (definition->edge_scaling < 0.0001) - { - definition->edge_scaling = 0.00001; - } - if (definition->_custom_coverage == NULL) - { - definition->_custom_coverage = _standardCoverageFunc; - } - - curveClear(definition->_coverage_by_altitude); - noiseClearLevels(definition->_shape_noise); - noiseClearLevels(definition->_edge_noise); - - switch (definition->type) - { - case CLOUDS_TYPE_CIRRUS: - curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.5, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); - noiseAddLevelsSimple(definition->_shape_noise, 3, 1.0, 1.0); - noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.0); - noiseAddLevelsSimple(definition->_edge_noise, 4, 1.0, 1.0); - noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, -0.2); - break; - case CLOUDS_TYPE_CUMULUS: - curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.1, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.4, 0.8); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.7, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); - noiseAddLevelsSimple(definition->_shape_noise, 7, 1.0, 1.0); - noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.4); - break; - case CLOUDS_TYPE_STRATOCUMULUS: - curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.2, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.5, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); - noiseAddLevelsSimple(definition->_shape_noise, 2, 1.0, 1.0); - noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.3); - noiseAddLevelsSimple(definition->_edge_noise, 8, 1.0, 1.0); - noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.5); - break; - case CLOUDS_TYPE_STRATUS: - curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.2, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 0.8, 1.0); - curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); - noiseAddLevelsSimple(definition->_shape_noise, 3, 1.0, 1.0); - noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, -0.3); - noiseAddLevelsSimple(definition->_edge_noise, 4, 1.0, 1.0); - noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, -0.5); - break; - default: - break; - } -} - -void _cloudsLayerSave(PackStream* stream, CloudsLayerDefinition* layer) -{ - int clouds_type = (int)layer->type; - - packWriteInt(stream, &clouds_type); - packWriteDouble(stream, &layer->lower_altitude); - packWriteDouble(stream, &layer->thickness); - curveSave(stream, layer->_coverage_by_altitude); - noiseSaveGenerator(stream, layer->_shape_noise); - noiseSaveGenerator(stream, layer->_edge_noise); - materialSave(stream, &layer->material); - packWriteDouble(stream, &layer->hardness); - packWriteDouble(stream, &layer->transparencydepth); - packWriteDouble(stream, &layer->lighttraversal); - packWriteDouble(stream, &layer->minimumlight); - packWriteDouble(stream, &layer->shape_scaling); - packWriteDouble(stream, &layer->edge_scaling); - packWriteDouble(stream, &layer->edge_length); - packWriteDouble(stream, &layer->base_coverage); -} - -void _cloudsLayerLoad(PackStream* stream, CloudsLayerDefinition* layer) -{ - int clouds_type; - - packReadInt(stream, &clouds_type); - layer->type = (CloudsType)clouds_type; - packReadDouble(stream, &layer->lower_altitude); - packReadDouble(stream, &layer->thickness); - materialLoad(stream, &layer->material); - packReadDouble(stream, &layer->hardness); - packReadDouble(stream, &layer->transparencydepth); - packReadDouble(stream, &layer->lighttraversal); - packReadDouble(stream, &layer->minimumlight); - packReadDouble(stream, &layer->shape_scaling); - packReadDouble(stream, &layer->edge_scaling); - packReadDouble(stream, &layer->edge_length); - packReadDouble(stream, &layer->base_coverage); - - cloudsLayerValidateDefinition(layer); -} - -LayerType cloudsGetLayerType() -{ - LayerType result; - - result.callback_create = (LayerCallbackCreate)cloudsLayerCreateDefinition; - result.callback_delete = (LayerCallbackDelete)cloudsLayerDeleteDefinition; - result.callback_copy = (LayerCallbackCopy)cloudsLayerCopyDefinition; - result.callback_validate = (LayerCallbackValidate)cloudsLayerValidateDefinition; - result.callback_save = (LayerCallbackSave)_cloudsLayerSave; - result.callback_load = (LayerCallbackLoad)_cloudsLayerLoad; - - return result; -} - -static inline double _getDistanceToBorder(CloudsLayerDefinition* layer, Vector3 position) -{ - double density, coverage, val; - - val = noiseGet3DTotal(layer->_shape_noise, position.x / layer->shape_scaling, position.y / layer->shape_scaling, position.z / layer->shape_scaling) / noiseGetMaxValue(layer->_shape_noise); - coverage = layer->_custom_coverage(layer, position); - density = 0.5 * val - 0.5 + coverage; - - if (density <= 0.0) - { - /* outside the main shape */ - return density * layer->shape_scaling; - } - else - { - /* inside the main shape, using edge noise */ - density /= coverage; - if (density < layer->edge_length) - { - density /= layer->edge_length; - - val = 0.5 * noiseGet3DTotal(layer->_edge_noise, position.x / layer->edge_scaling, position.y / layer->edge_scaling, position.z / layer->edge_scaling) / noiseGetMaxValue(layer->_edge_noise); - val = val - 0.5 + density; - - return val * (density * coverage * layer->shape_scaling + (1.0 - density) * layer->edge_scaling); - } - else - { - return density * coverage * layer->shape_scaling; - } - } -} - -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); -} - -/** - * Optimize the search limits in a layer. - * - * @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 - */ -static int _optimizeSearchLimits(CloudsLayerDefinition* layer, Vector3* start, Vector3* end) -{ - Vector3 diff; - - if (start->y > layer->lower_altitude + layer->thickness) - { - if (end->y >= layer->lower_altitude + layer->thickness) - { - return 0; - } - else - { - diff = v3Sub(*end, *start); - *start = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y)); - if (end->y < layer->lower_altitude) - { - *end = v3Add(*end, v3Scale(diff, (layer->lower_altitude - end->y) / diff.y)); - } - } - } - else if (start->y < layer->lower_altitude) - { - if (end->y <= layer->lower_altitude) - { - return 0; - } - else - { - diff = v3Sub(*end, *start); - *start = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y)); - if (end->y >= layer->lower_altitude + layer->thickness) - { - *end = v3Add(*end, v3Scale(diff, (layer->lower_altitude + layer->thickness - end->y) / diff.y)); - } - } - } - else /* start is inside layer */ - { - diff = v3Sub(*end, *start); - if (end->y > layer->lower_altitude + layer->thickness) - { - *end = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y)); - } - else if (end->y < layer->lower_altitude) - { - *end = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y)); - } - } - - /* TODO Limit the search length */ - return 1; -} - -/** - * Go through the cloud layer to find segments (parts of the lookup that are inside the cloud). - * - * @param definition The cloud layer - * @param renderer The renderer environment - * @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 - */ -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) -{ - 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; - double render_precision; - - if (max_segments <= 0) - { - return 0; - } - - 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; - current_total_length = 0.0; - current_inside_length = 0.0; - segment_length = 0.0; - walker = start; - noise_distance = _getDistanceToBorder(definition, start) * render_precision; - inside = (noise_distance > 0.0) ? 1 : 0; - step = v3Scale(direction, render_precision); - - do - { - walker = v3Add(walker, step); - step_length = v3Norm(step); - last_noise_distance = noise_distance; - noise_distance = _getDistanceToBorder(definition, walker) * render_precision; - current_total_length += step_length; - - if (current_total_length >= max_total_length || current_inside_length > max_inside_length) - { - noise_distance = 0.0; - } - - if (noise_distance > 0.0) - { - if (inside) - { - // inside the cloud - segment_length += step_length; - current_inside_length += step_length; - step = v3Scale(direction, (noise_distance < render_precision) ? render_precision : noise_distance); - } - 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; - step = v3Scale(direction, render_precision); - } - } - 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; - - 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; - } - - inside = 0; - step = v3Scale(direction, render_precision); - } - else - { - // searching for a cloud - step = v3Scale(direction, (noise_distance > -render_precision) ? render_precision : -noise_distance); - } - } - } while (inside || (walker.y <= definition->lower_altitude + definition->thickness + 0.001 && walker.y >= definition->lower_altitude - 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length)); - - *total_length = current_total_length; - *inside_length = current_inside_length; - return segment_count; -} - -static Color _applyLayerLighting(CloudsLayerDefinition* definition, Renderer* renderer, Vector3 position, double detail) -{ - Vector3 normal; - Color col1, col2; - LightStatus* lighting; - - normal = _getNormal(definition, position, 3.0); - if (renderer->render_quality > 5) - { - normal = v3Add(normal, _getNormal(definition, position, 2.0)); - normal = v3Add(normal, _getNormal(definition, position, 1.0)); - } - if (renderer->render_quality > 5) - { - normal = v3Add(normal, _getNormal(definition, position, 0.5)); - } - normal = v3Scale(v3Normalize(normal), definition->hardness); - - lighting = lightingCreateStatus(renderer->lighting, position, renderer->camera_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 i, segment_count; - double max_length, detail, total_length, inside_length; - Vector3 direction; - Color col; - CloudSegment segments[MAX_SEGMENT_COUNT]; - - if (!_optimizeSearchLimits(definition, &start, &end)) - { - return base; - } - - direction = v3Sub(end, start); - max_length = v3Norm(direction); - direction = v3Normalize(direction); - - detail = renderer->getPrecision(renderer, start) / definition->shape_scaling; - - segment_count = _findSegments(definition, renderer, start, direction, detail, MAX_SEGMENT_COUNT, definition->transparencydepth * (double)renderer->render_quality, max_length, &inside_length, &total_length, segments); - for (i = segment_count - 1; i >= 0; i--) - { - col = _applyLayerLighting(definition, renderer, segments[i].start, detail); - col.a = 1.0; - col = renderer->atmosphere->applyAerialPerspective(renderer, start, col); - col.a = (segments[i].length >= definition->transparencydepth) ? 1.0 : (segments[i].length / definition->transparencydepth); - colorMask(&base, &col); - } - if (inside_length >= definition->transparencydepth) - { - col.a = 1.0; - } - - return base; -} - -/*static int _cmpLayer(const void* layer1, const void* layer2) -{ - return (((CloudsLayerDefinition*)layer1)->lower_altitude > ((CloudsLayerDefinition*)layer2)->lower_altitude) ? -1 : 1; -}*/ - -Color cloudsApply(CloudsDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end) -{ - int i, n; - - n = layersCount(definition->layers); - if (n < 1) - { - return base; - } - - /* TODO Iter layers in sorted order */ - for (i = 0; i < n; i++) - { - base = cloudsApplyLayer(layersGetLayer(definition->layers, i), base, renderer, start, end); - } - - 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]; - - _optimizeSearchLimits(definition, &location, &light_location); - - _findSegments(definition, renderer, location, direction_to_light, 0.1, 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; -} - -Color cloudsFilterLight(CloudsDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light) -{ - int i, n; - - /* TODO Iter layers in sorted order */ - n = layersCount(definition->layers); - for (i = 0; i < n; i++) - { - light = cloudsLayerFilterLight(layersGetLayer(definition->layers, i), renderer, light, location, light_location, direction_to_light); - } - return light; -} diff --git a/lib_paysages/clouds.h b/lib_paysages/clouds.h deleted file mode 100644 index b52c451..0000000 --- a/lib_paysages/clouds.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _PAYSAGES_CLOUDS_H_ -#define _PAYSAGES_CLOUDS_H_ - -#include "shared/types.h" -#include "layers.h" -#include "noise.h" -#include "renderer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum -{ - CLOUDS_TYPE_CIRRUS, - CLOUDS_TYPE_CUMULUS, - CLOUDS_TYPE_STRATOCUMULUS, - CLOUDS_TYPE_STRATUS -} CloudsType; - -typedef enum -{ - CLOUDS_PRESET_CIRRUS, - CLOUDS_PRESET_CUMULUS, - CLOUDS_PRESET_STRATOCUMULUS, - CLOUDS_PRESET_STRATUS -} CloudsPreset; - -typedef struct CloudsLayerDefinition CloudsLayerDefinition; - -typedef double (*CloudCoverageFunc)(CloudsLayerDefinition* definition, Vector3 position); - -struct CloudsLayerDefinition -{ - CloudsType type; - double lower_altitude; - double thickness; - double base_coverage; - double shape_scaling; - double edge_scaling; - double edge_length; - SurfaceMaterial material; - double hardness; - double transparencydepth; - double lighttraversal; - double minimumlight; - - CloudCoverageFunc _custom_coverage; - Curve* _coverage_by_altitude; - NoiseGenerator* _shape_noise; - NoiseGenerator* _edge_noise; -}; - -typedef struct -{ - Layers* layers; -} CloudsDefinition; - -CloudsDefinition cloudsCreateDefinition(); -void cloudsDeleteDefinition(CloudsDefinition* definition); -void cloudsCopyDefinition(CloudsDefinition* source, CloudsDefinition* destination); -void cloudsValidateDefinition(CloudsDefinition* definition); -void cloudsSave(PackStream* stream, CloudsDefinition* definition); -void cloudsLoad(PackStream* stream, CloudsDefinition* definition); - -CloudsLayerDefinition* cloudsLayerCreateDefinition(); -void cloudsLayerDeleteDefinition(CloudsLayerDefinition* definition); -void cloudsLayerAutoPreset(CloudsLayerDefinition* definition, CloudsPreset preset); -void cloudsLayerCopyDefinition(CloudsLayerDefinition* source, CloudsLayerDefinition* destination); -void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition); -void cloudsLayerSetName(CloudsLayerDefinition* definition, const char* name); -LayerType cloudsGetLayerType(); - -Color cloudsApplyLayer(CloudsLayerDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end); -Color cloudsApply(CloudsDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end); -Color cloudsLayerFilterLight(CloudsLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light); -Color cloudsFilterLight(CloudsDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib_paysages/clouds/definition.c b/lib_paysages/clouds/definition.c new file mode 100644 index 0000000..2eab022 --- /dev/null +++ b/lib_paysages/clouds/definition.c @@ -0,0 +1,205 @@ +#include "private.h" + +#include + +/******************** Global definition ********************/ +static void _validateDefinition(CloudsDefinition* definition) +{ + layersValidate(definition->layers); +} + +static CloudsDefinition* _createDefinition() +{ + CloudsDefinition* definition = malloc(sizeof(CloudsDefinition)); + + definition->layers = layersCreate(cloudsGetLayerType(), CLOUDS_MAX_LAYERS); + + return definition; +} + +static void _deleteDefinition(CloudsDefinition* definition) +{ + layersDelete(definition->layers); + free(definition); +} + +static void _copyDefinition(CloudsDefinition* source, CloudsDefinition* destination) +{ + layersCopy(source->layers, destination->layers); +} + +static void _saveDefinition(PackStream* stream, CloudsDefinition* definition) +{ + layersSave(stream, definition->layers); +} + +static void _loadDefinition(PackStream* stream, CloudsDefinition* definition) +{ + layersLoad(stream, definition->layers); +} + +StandardDefinition CloudsDefinitionClass = { + (FuncObjectCreate)_createDefinition, + (FuncObjectDelete)_deleteDefinition, + (FuncObjectCopy)_copyDefinition, + (FuncObjectValidate)_validateDefinition, + (FuncObjectSave)_saveDefinition, + (FuncObjectLoad)_loadDefinition +}; + +/*** Layer definition ***/ + +void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition) +{ + if (definition->shape_scaling < 0.0001) + { + definition->shape_scaling = 0.00001; + } + if (definition->edge_scaling < 0.0001) + { + definition->edge_scaling = 0.00001; + } + + curveClear(definition->_coverage_by_altitude); + noiseClearLevels(definition->_shape_noise); + noiseClearLevels(definition->_edge_noise); + + switch (definition->type) + { + case CLOUDS_TYPE_CIRRUS: + curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.5, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); + noiseAddLevelsSimple(definition->_shape_noise, 3, 1.0, 1.0); + noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.0); + noiseAddLevelsSimple(definition->_edge_noise, 4, 1.0, 1.0); + noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, -0.2); + break; + case CLOUDS_TYPE_CUMULUS: + curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.1, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.4, 0.8); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.7, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); + noiseAddLevelsSimple(definition->_shape_noise, 7, 1.0, 1.0); + noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.4); + break; + case CLOUDS_TYPE_STRATOCUMULUS: + curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.2, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.5, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); + noiseAddLevelsSimple(definition->_shape_noise, 2, 1.0, 1.0); + noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.3); + noiseAddLevelsSimple(definition->_edge_noise, 8, 1.0, 1.0); + noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.5); + break; + case CLOUDS_TYPE_STRATUS: + curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.2, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 0.8, 1.0); + curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0); + noiseAddLevelsSimple(definition->_shape_noise, 3, 1.0, 1.0); + noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, -0.3); + noiseAddLevelsSimple(definition->_edge_noise, 4, 1.0, 1.0); + noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, -0.5); + break; + default: + break; + } +} + +CloudsLayerDefinition* cloudsLayerCreateDefinition() +{ + CloudsLayerDefinition* result; + + result = malloc(sizeof(CloudsLayerDefinition)); + result->_coverage_by_altitude = curveCreate(); + result->_shape_noise = noiseCreateGenerator(); + result->_edge_noise = noiseCreateGenerator(); + + cloudsAutoPreset(result, CLOUDS_PRESET_CIRRUS); + + return result; +} + +void cloudsLayerDeleteDefinition(CloudsLayerDefinition* definition) +{ + curveDelete(definition->_coverage_by_altitude); + noiseDeleteGenerator(definition->_shape_noise); + noiseDeleteGenerator(definition->_edge_noise); + free(definition); +} + +void cloudsLayerCopyDefinition(CloudsLayerDefinition* source, CloudsLayerDefinition* destination) +{ + CloudsLayerDefinition temp; + + temp = *destination; + *destination = *source; + + destination->_shape_noise = temp._shape_noise; + noiseCopy(source->_shape_noise, destination->_shape_noise); + + destination->_edge_noise = temp._edge_noise; + noiseCopy(source->_edge_noise, destination->_edge_noise); + + destination->_coverage_by_altitude = temp._coverage_by_altitude; + curveCopy(source->_coverage_by_altitude, destination->_coverage_by_altitude); +} + +void _cloudsLayerSave(PackStream* stream, CloudsLayerDefinition* layer) +{ + int clouds_type = (int)layer->type; + + packWriteInt(stream, &clouds_type); + packWriteDouble(stream, &layer->lower_altitude); + packWriteDouble(stream, &layer->thickness); + curveSave(stream, layer->_coverage_by_altitude); + noiseSaveGenerator(stream, layer->_shape_noise); + noiseSaveGenerator(stream, layer->_edge_noise); + materialSave(stream, &layer->material); + packWriteDouble(stream, &layer->hardness); + packWriteDouble(stream, &layer->transparencydepth); + packWriteDouble(stream, &layer->lighttraversal); + packWriteDouble(stream, &layer->minimumlight); + packWriteDouble(stream, &layer->shape_scaling); + packWriteDouble(stream, &layer->edge_scaling); + packWriteDouble(stream, &layer->edge_length); + packWriteDouble(stream, &layer->base_coverage); +} + +void _cloudsLayerLoad(PackStream* stream, CloudsLayerDefinition* layer) +{ + int clouds_type; + + packReadInt(stream, &clouds_type); + layer->type = (CloudsType)clouds_type; + packReadDouble(stream, &layer->lower_altitude); + packReadDouble(stream, &layer->thickness); + materialLoad(stream, &layer->material); + packReadDouble(stream, &layer->hardness); + packReadDouble(stream, &layer->transparencydepth); + packReadDouble(stream, &layer->lighttraversal); + packReadDouble(stream, &layer->minimumlight); + packReadDouble(stream, &layer->shape_scaling); + packReadDouble(stream, &layer->edge_scaling); + packReadDouble(stream, &layer->edge_length); + packReadDouble(stream, &layer->base_coverage); + + cloudsLayerValidateDefinition(layer); +} + +LayerType cloudsGetLayerType() +{ + LayerType result; + + result.callback_create = (LayerCallbackCreate)cloudsLayerCreateDefinition; + result.callback_delete = (LayerCallbackDelete)cloudsLayerDeleteDefinition; + result.callback_copy = (LayerCallbackCopy)cloudsLayerCopyDefinition; + result.callback_validate = (LayerCallbackValidate)cloudsLayerValidateDefinition; + result.callback_save = (LayerCallbackSave)_cloudsLayerSave; + result.callback_load = (LayerCallbackLoad)_cloudsLayerLoad; + + return result; +} diff --git a/lib_paysages/clouds/presets.c b/lib_paysages/clouds/presets.c new file mode 100644 index 0000000..4f007d4 --- /dev/null +++ b/lib_paysages/clouds/presets.c @@ -0,0 +1,83 @@ +#include "private.h" + +#include + +/* + * Clouds presets. + */ + +void cloudsAutoPreset(CloudsLayerDefinition* definition, CloudsPreset preset) +{ + definition->material.base.r = 0.7; + definition->material.base.g = 0.7; + definition->material.base.b = 0.7; + definition->material.base.a = 1.0; + + switch (preset) + { + case CLOUDS_PRESET_CIRRUS: + definition->type = CLOUDS_TYPE_CIRRUS; + definition->lower_altitude = 25.0; + definition->thickness = 2.0; + definition->material.reflection = 0.4; + definition->material.shininess = 0.5; + definition->hardness = 0.0; + definition->transparencydepth = 3.0; + definition->lighttraversal = 10.0; + definition->minimumlight = 0.6; + definition->shape_scaling = 8.0; + definition->edge_scaling = 2.0; + definition->edge_length = 0.8; + definition->base_coverage = 0.6; + break; + case CLOUDS_PRESET_CUMULUS: + definition->type = CLOUDS_TYPE_CUMULUS; + definition->lower_altitude = 15.0; + definition->thickness = 15.0; + definition->material.reflection = 0.5; + definition->material.shininess = 1.2; + definition->hardness = 0.25; + definition->transparencydepth = 1.5; + definition->lighttraversal = 8.0; + definition->minimumlight = 0.4; + definition->shape_scaling = 20.0; + definition->edge_scaling = 2.0; + definition->edge_length = 0.0; + definition->base_coverage = 0.7; + break; + case CLOUDS_PRESET_STRATOCUMULUS: + definition->type = CLOUDS_TYPE_STRATOCUMULUS; + definition->lower_altitude = 5.0; + definition->thickness = 6.0; + definition->material.reflection = 0.3; + definition->material.shininess = 0.8; + definition->hardness = 0.25; + definition->transparencydepth = 1.5; + definition->lighttraversal = 7.0; + definition->minimumlight = 0.4; + definition->shape_scaling = 10.0; + definition->edge_scaling = 0.8; + definition->edge_length = 0.3; + definition->base_coverage = 0.4; + break; + case CLOUDS_PRESET_STRATUS: + definition->type = CLOUDS_TYPE_STRATUS; + definition->lower_altitude = 3.0; + definition->thickness = 4.0; + definition->material.reflection = 0.1; + definition->material.shininess = 0.8; + definition->hardness = 0.1; + definition->transparencydepth = 3.0; + definition->lighttraversal = 10.0; + definition->minimumlight = 0.6; + definition->shape_scaling = 8.0; + definition->edge_scaling = 2.0; + definition->edge_length = 1.0; + definition->base_coverage = 0.4; + break; + default: + break; + } + + cloudsLayerValidateDefinition(definition); +} diff --git a/lib_paysages/clouds/preview.c b/lib_paysages/clouds/preview.c new file mode 100644 index 0000000..3d45bed --- /dev/null +++ b/lib_paysages/clouds/preview.c @@ -0,0 +1,65 @@ +#include "private.h" + +#include "../tools/euclid.h" +#include "../renderer.h" +#include "../tools.h" + +/* + * Clouds previews. + */ + +Color _fakeApplyLightingToSurface(Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial* material) +{ + UNUSED(renderer); + UNUSED(location); + UNUSED(normal); + UNUSED(material); + + return COLOR_WHITE; +} + +Renderer* cloudsCreatePreviewCoverageRenderer() +{ + Renderer* result = rendererCreate(); + result->render_quality = 5; + result->applyLightingToSurface = _fakeApplyLightingToSurface; + return result; +} + +Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling) +{ + Vector3 eye, look; + + eye.x = 0.0; + eye.y = scaling; + eye.z = -10.0 * scaling; + look.x = x * 0.01 / scaling; + look.y = -y * 0.01 / scaling - 0.3; + look.z = 1.0; + look = v3Normalize(look); + + return renderer->clouds->getColor(renderer, COLOR_BLUE, eye, v3Add(eye, v3Scale(look, 1000.0))); +} + +Renderer* cloudsCreatePreviewColorRenderer() +{ + Renderer* result = rendererCreate(); + result->render_quality = 8; + return result; +} + +Color cloudsGetPreviewColor(Renderer* renderer, double x, double y) +{ + Vector3 start, end; + double thickness = 0.5; + + start.x = x * thickness * 0.5; + start.y = -y * thickness * 0.5; + start.z = thickness * 0.5; + + end.x = start.x; + end.y = start.y; + end.z = -start.z; + + return renderer->clouds->getColor(renderer, COLOR_BLUE, start, end); +} diff --git a/lib_paysages/clouds/private.h b/lib_paysages/clouds/private.h new file mode 100644 index 0000000..52dda41 --- /dev/null +++ b/lib_paysages/clouds/private.h @@ -0,0 +1,21 @@ +#ifndef _PAYSAGES_CLOUDS_PRIVATE_H_ +#define _PAYSAGES_CLOUDS_PRIVATE_H_ + +#include "public.h" + +#define CLOUDS_MAX_LAYERS 6 +#define MAX_SEGMENT_COUNT 30 + +typedef struct +{ + Vector3 start; + Vector3 end; + double length; +} CloudSegment; + +void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition); + +Color cloudsLayerFilterLight(CloudsLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light); +Color cloudsApplyLayer(CloudsLayerDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end); + +#endif diff --git a/lib_paysages/clouds/public.h b/lib_paysages/clouds/public.h new file mode 100644 index 0000000..024676f --- /dev/null +++ b/lib_paysages/clouds/public.h @@ -0,0 +1,85 @@ +#ifndef _PAYSAGES_CLOUDS_PUBLIC_H_ +#define _PAYSAGES_CLOUDS_PUBLIC_H_ + +#include "../shared/types.h" +#include "../tools/lighting.h" +#include "../tools/curve.h" +#include "../tools/euclid.h" +#include "../noise.h" +#include "../layers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + CLOUDS_TYPE_CIRRUS, + CLOUDS_TYPE_CUMULUS, + CLOUDS_TYPE_STRATOCUMULUS, + CLOUDS_TYPE_STRATUS +} CloudsType; + +typedef enum +{ + CLOUDS_PRESET_CIRRUS, + CLOUDS_PRESET_CUMULUS, + CLOUDS_PRESET_STRATOCUMULUS, + CLOUDS_PRESET_STRATUS +} CloudsPreset; + +typedef struct +{ + CloudsType type; + double lower_altitude; + double thickness; + double base_coverage; + double shape_scaling; + double edge_scaling; + double edge_length; + SurfaceMaterial material; + double hardness; + double transparencydepth; + double lighttraversal; + double minimumlight; + + Curve* _coverage_by_altitude; + NoiseGenerator* _shape_noise; + NoiseGenerator* _edge_noise; +} CloudsLayerDefinition; + +typedef struct +{ + Layers* layers; +} CloudsDefinition; + + +typedef Color (*FuncCloudsGetColor)(Renderer* renderer, Color base, Vector3 start, Vector3 end); + +typedef struct +{ + CloudsDefinition* definition; + + FuncCloudsGetColor getColor; + FuncLightingAlterLight alterLight; +} CloudsRenderer; + + +extern StandardDefinition CloudsDefinitionClass; +extern StandardRenderer CloudsRendererClass; + + +LayerType cloudsGetLayerType(); +void cloudsAutoPreset(CloudsLayerDefinition* definition, CloudsPreset preset); + +Renderer* cloudsCreatePreviewCoverageRenderer(); +Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling); + +Renderer* cloudsCreatePreviewColorRenderer(); +Color cloudsGetPreviewColor(Renderer* renderer, double x, double y); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_paysages/clouds/rendering.c b/lib_paysages/clouds/rendering.c new file mode 100644 index 0000000..7c7c287 --- /dev/null +++ b/lib_paysages/clouds/rendering.c @@ -0,0 +1,100 @@ +#include "private.h" + +#include +#include "../tools.h" +#include "../renderer.h" + +/******************** Fake ********************/ +static int _fakeAlterLight(Renderer* renderer, LightDefinition* light, Vector3 location) +{ + UNUSED(renderer); + UNUSED(light); + UNUSED(location); + + return 0; +} + +static Color _fakeGetColor(Renderer* renderer, Color base, Vector3 start, Vector3 end) +{ + UNUSED(renderer); + UNUSED(start); + UNUSED(end); + + return base; +} + +/******************** Real ********************/ +/*static int _cmpLayer(const void* layer1, const void* layer2) +{ + return (((CloudsLayerDefinition*)layer1)->lower_altitude > ((CloudsLayerDefinition*)layer2)->lower_altitude) ? -1 : 1; +}*/ + +static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) +{ + CloudsDefinition* definition = renderer->clouds->definition; + int i, n; + + /* 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)); + } + return n > 0; +} + +static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end) +{ + CloudsDefinition* definition = renderer->clouds->definition; + int i, n; + + n = layersCount(definition->layers); + if (n < 1) + { + return base; + } + + /* TODO Iter layers in sorted order */ + for (i = 0; i < n; i++) + { + base = cloudsApplyLayer(layersGetLayer(definition->layers, i), base, renderer, start, end); + } + + return base; +} + +/******************** Renderer ********************/ +static CloudsRenderer* _createRenderer() +{ + CloudsRenderer* result; + + result = malloc(sizeof(CloudsRenderer)); + result->definition = CloudsDefinitionClass.create(); + + result->getColor = _fakeGetColor; + result->alterLight = (FuncLightingAlterLight)_fakeAlterLight; + + return result; +} + +static void _deleteRenderer(CloudsRenderer* renderer) +{ + CloudsDefinitionClass.destroy(renderer->definition); + free(renderer); +} + +static void _bindRenderer(Renderer* renderer, CloudsDefinition* definition) +{ + CloudsDefinitionClass.copy(definition, renderer->clouds->definition); + + renderer->clouds->getColor = _getColor; + renderer->clouds->alterLight = (FuncLightingAlterLight)_alterLight; + + lightingManagerRegisterFilter(renderer->lighting, (FuncLightingAlterLight)_alterLight, renderer); +} + +StandardRenderer CloudsRendererClass = { + (FuncObjectCreate)_createRenderer, + (FuncObjectDelete)_deleteRenderer, + (FuncObjectBind)_bindRenderer +}; diff --git a/lib_paysages/clouds/tools.c b/lib_paysages/clouds/tools.c new file mode 100644 index 0000000..22f4fd2 --- /dev/null +++ b/lib_paysages/clouds/tools.c @@ -0,0 +1,374 @@ +#include "private.h" + +/* + * Clouds tools. + */ + +#include "../renderer.h" + +static double _standardCoverageFunc(CloudsLayerDefinition* layer, Vector3 position) +{ + if (position.y < layer->lower_altitude || position.y >= layer->lower_altitude + layer->thickness) + { + return 0.0; + } + else + { + return layer->base_coverage * curveGetValue(layer->_coverage_by_altitude, (position.y - layer->lower_altitude) / layer->thickness); + } +} + +static inline double _getDistanceToBorder(CloudsLayerDefinition* layer, Vector3 position) +{ + double density, coverage, val; + + val = noiseGet3DTotal(layer->_shape_noise, position.x / layer->shape_scaling, position.y / layer->shape_scaling, position.z / layer->shape_scaling) / noiseGetMaxValue(layer->_shape_noise); + coverage = _standardCoverageFunc(layer, position); + density = 0.5 * val - 0.5 + coverage; + + if (density <= 0.0) + { + /* outside the main shape */ + return density * layer->shape_scaling; + } + else + { + /* inside the main shape, using edge noise */ + density /= coverage; + if (density < layer->edge_length) + { + density /= layer->edge_length; + + val = 0.5 * noiseGet3DTotal(layer->_edge_noise, position.x / layer->edge_scaling, position.y / layer->edge_scaling, position.z / layer->edge_scaling) / noiseGetMaxValue(layer->_edge_noise); + val = val - 0.5 + density; + + return val * (density * coverage * layer->shape_scaling + (1.0 - density) * layer->edge_scaling); + } + else + { + return density * coverage * layer->shape_scaling; + } + } +} + +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); +} + +/** + * Optimize the search limits in a layer. + * + * @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 + */ +static int _optimizeSearchLimits(CloudsLayerDefinition* layer, Vector3* start, Vector3* end) +{ + Vector3 diff; + + if (start->y > layer->lower_altitude + layer->thickness) + { + if (end->y >= layer->lower_altitude + layer->thickness) + { + return 0; + } + else + { + diff = v3Sub(*end, *start); + *start = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y)); + if (end->y < layer->lower_altitude) + { + *end = v3Add(*end, v3Scale(diff, (layer->lower_altitude - end->y) / diff.y)); + } + } + } + else if (start->y < layer->lower_altitude) + { + if (end->y <= layer->lower_altitude) + { + return 0; + } + else + { + diff = v3Sub(*end, *start); + *start = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y)); + if (end->y >= layer->lower_altitude + layer->thickness) + { + *end = v3Add(*end, v3Scale(diff, (layer->lower_altitude + layer->thickness - end->y) / diff.y)); + } + } + } + else /* start is inside layer */ + { + diff = v3Sub(*end, *start); + if (end->y > layer->lower_altitude + layer->thickness) + { + *end = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y)); + } + else if (end->y < layer->lower_altitude) + { + *end = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y)); + } + } + + /* TODO Limit the search length */ + return 1; +} + +/** + * Go through the cloud layer to find segments (parts of the lookup that are inside the cloud). + * + * @param definition The cloud layer + * @param renderer The renderer environment + * @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 + */ +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) +{ + 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; + double render_precision; + + if (max_segments <= 0) + { + return 0; + } + + 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; + current_total_length = 0.0; + current_inside_length = 0.0; + segment_length = 0.0; + walker = start; + noise_distance = _getDistanceToBorder(definition, start) * render_precision; + inside = (noise_distance > 0.0) ? 1 : 0; + step = v3Scale(direction, render_precision); + + do + { + walker = v3Add(walker, step); + step_length = v3Norm(step); + last_noise_distance = noise_distance; + noise_distance = _getDistanceToBorder(definition, walker) * render_precision; + current_total_length += step_length; + + if (current_total_length >= max_total_length || current_inside_length > max_inside_length) + { + noise_distance = 0.0; + } + + if (noise_distance > 0.0) + { + if (inside) + { + // inside the cloud + segment_length += step_length; + current_inside_length += step_length; + step = v3Scale(direction, (noise_distance < render_precision) ? render_precision : noise_distance); + } + 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; + step = v3Scale(direction, render_precision); + } + } + 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; + + 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; + } + + inside = 0; + step = v3Scale(direction, render_precision); + } + else + { + // searching for a cloud + step = v3Scale(direction, (noise_distance > -render_precision) ? render_precision : -noise_distance); + } + } + } while (inside || (walker.y <= definition->lower_altitude + definition->thickness + 0.001 && walker.y >= definition->lower_altitude - 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length)); + + *total_length = current_total_length; + *inside_length = current_inside_length; + return segment_count; +} + +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->camera_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 i, segment_count; + double max_length, detail, total_length, inside_length; + Vector3 direction; + Color col; + CloudSegment segments[MAX_SEGMENT_COUNT]; + + if (!_optimizeSearchLimits(definition, &start, &end)) + { + return base; + } + + direction = v3Sub(end, start); + max_length = v3Norm(direction); + direction = v3Normalize(direction); + + detail = renderer->getPrecision(renderer, start) / definition->shape_scaling; + + segment_count = _findSegments(definition, renderer, start, direction, detail, MAX_SEGMENT_COUNT, definition->transparencydepth * (double)renderer->render_quality, max_length, &inside_length, &total_length, segments); + for (i = segment_count - 1; i >= 0; i--) + { + col = _applyLayerLighting(definition, renderer, segments[i].start, detail); + col.a = 1.0; + col = renderer->atmosphere->applyAerialPerspective(renderer, start, col); + col.a = (segments[i].length >= definition->transparencydepth) ? 1.0 : (segments[i].length / definition->transparencydepth); + colorMask(&base, &col); + } + if (inside_length >= definition->transparencydepth) + { + col.a = 1.0; + } + + 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]; + + _optimizeSearchLimits(definition, &location, &light_location); + + _findSegments(definition, renderer, location, direction_to_light, 0.1, 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; +} diff --git a/lib_paysages/renderer.c b/lib_paysages/renderer.c index 7bbaee4..48fffbb 100644 --- a/lib_paysages/renderer.c +++ b/lib_paysages/renderer.c @@ -69,11 +69,6 @@ static Color _applyTextures(Renderer* renderer, Vector3 location, double precisi return COLOR_TRANSPARENT; } -static Color _applyClouds(Renderer* renderer, Color base, Vector3 start, Vector3 end) -{ - return base; -} - Color _applyLightingToSurface(Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial* material) { LightStatus* light = lightingCreateStatus(renderer->lighting, location, renderer->camera_location); @@ -110,13 +105,13 @@ Renderer* rendererCreate() result->rayWalking = _rayWalking; result->getWaterHeightInfo = _getWaterHeightInfo; result->applyTextures = _applyTextures; - result->applyClouds = _applyClouds; result->applyLightingToSurface = _applyLightingToSurface; result->lighting = lightingManagerCreate(); result->atmosphere = AtmosphereRendererClass.create(); + result->clouds = CloudsRendererClass.create(); result->terrain = TerrainRendererClass.create(); return result; @@ -127,6 +122,7 @@ void rendererDelete(Renderer* renderer) lightingManagerDelete(renderer->lighting); AtmosphereRendererClass.destroy(renderer->atmosphere); + CloudsRendererClass.destroy(renderer->clouds); TerrainRendererClass.destroy(renderer->terrain); renderDeleteArea(renderer->render_area); diff --git a/lib_paysages/renderer.h b/lib_paysages/renderer.h index 06d6f8e..8a364de 100644 --- a/lib_paysages/renderer.h +++ b/lib_paysages/renderer.h @@ -3,6 +3,7 @@ #include "shared/types.h" #include "atmosphere/public.h" +#include "clouds/public.h" #include "terrain/public.h" #include "render.h" @@ -38,7 +39,6 @@ struct Renderer RayCastingResult (*rayWalking)(Renderer* renderer, Vector3 location, Vector3 direction, int terrain, int water, int sky, int clouds); HeightInfo (*getWaterHeightInfo)(Renderer* renderer); Color (*applyTextures)(Renderer* renderer, Vector3 location, double precision); - Color (*applyClouds)(Renderer* renderer, Color base, Vector3 start, Vector3 end); /* Autonomous tools */ LightingManager* lighting; @@ -46,6 +46,7 @@ struct Renderer /* Autonomous sub-renderers */ AtmosphereRenderer* atmosphere; TerrainRenderer* terrain; + CloudsRenderer* clouds; /* Custom data */ void* customData[10]; diff --git a/lib_paysages/scenery.c b/lib_paysages/scenery.c index cbb5f17..9988252 100644 --- a/lib_paysages/scenery.c +++ b/lib_paysages/scenery.c @@ -7,7 +7,7 @@ static AtmosphereDefinition* _atmosphere; static CameraDefinition _camera; -static CloudsDefinition _clouds; +static CloudsDefinition* _clouds; static TerrainDefinition* _terrain; static TexturesDefinition _textures; static WaterDefinition _water; @@ -22,7 +22,7 @@ void sceneryInit() _atmosphere = AtmosphereDefinitionClass.create(); _camera = cameraCreateDefinition(); - _clouds = cloudsCreateDefinition(); + _clouds = CloudsDefinitionClass.create(); _terrain = TerrainDefinitionClass.create(); _textures = texturesCreateDefinition(); _water = waterCreateDefinition(); @@ -35,7 +35,7 @@ void sceneryQuit() { AtmosphereDefinitionClass.destroy(_atmosphere); cameraDeleteDefinition(&_camera); - cloudsDeleteDefinition(&_clouds); + CloudsDefinitionClass.destroy(_clouds); TerrainDefinitionClass.destroy(_terrain); texturesDeleteDefinition(&_textures); waterDeleteDefinition(&_water); @@ -55,7 +55,7 @@ void scenerySave(PackStream* stream) noiseSave(stream); AtmosphereDefinitionClass.save(stream, _atmosphere); cameraSave(stream, &_camera); - cloudsSave(stream, &_clouds); + CloudsDefinitionClass.save(stream, _clouds); TerrainDefinitionClass.save(stream, _terrain); texturesSave(stream, &_textures); waterSave(stream, &_water); @@ -73,13 +73,12 @@ void sceneryLoad(PackStream* stream) noiseLoad(stream); AtmosphereDefinitionClass.load(stream, _atmosphere); cameraLoad(stream, &_camera); - cloudsLoad(stream, &_clouds); + CloudsDefinitionClass.load(stream, _clouds); TerrainDefinitionClass.load(stream, _terrain); texturesLoad(stream, &_textures); waterLoad(stream, &_water); cameraValidateDefinition(&_camera, 0); - cloudsValidateDefinition(&_clouds); texturesValidateDefinition(&_textures); waterValidateDefinition(&_water); @@ -112,13 +111,12 @@ void sceneryGetCamera(CameraDefinition* camera) void scenerySetClouds(CloudsDefinition* clouds) { - cloudsCopyDefinition(clouds, &_clouds); - cloudsValidateDefinition(&_clouds); + CloudsDefinitionClass.copy(clouds, _clouds); } void sceneryGetClouds(CloudsDefinition* clouds) { - cloudsCopyDefinition(&_clouds, clouds); + CloudsDefinitionClass.copy(_clouds, clouds); } void scenerySetTerrain(TerrainDefinition* terrain) @@ -182,7 +180,7 @@ static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector result.hit = 1; result.hit_location = v3Add(location, v3Scale(direction, 1000.0)); - result.hit_color = renderer->applyClouds(renderer, sky_color, location, result.hit_location); + result.hit_color = renderer->clouds->getColor(renderer, sky_color, location, result.hit_location); } return result; @@ -198,11 +196,6 @@ static Color _applyTextures(Renderer* renderer, Vector3 location, double precisi return texturesGetColor(&_textures, renderer, location.x, location.z, precision); } -static Color _applyClouds(Renderer* renderer, Color base, Vector3 start, Vector3 end) -{ - return cloudsApply(&_clouds, base, renderer, start, end); -} - static Vector3 _projectPoint(Renderer* renderer, Vector3 point) { return cameraProject(&renderer->render_camera, renderer, point); @@ -236,13 +229,13 @@ Renderer* sceneryCreateStandardRenderer() result->rayWalking = _rayWalking; result->getWaterHeightInfo = _getWaterHeightInfo; result->applyTextures = _applyTextures; - result->applyClouds = _applyClouds; result->projectPoint = _projectPoint; result->unprojectPoint = _unprojectPoint; result->getPrecision = _getPrecision; AtmosphereRendererClass.bind(result, _atmosphere); TerrainRendererClass.bind(result, _terrain); + CloudsRendererClass.bind(result, _clouds); return result; } diff --git a/lib_paysages/scenery.h b/lib_paysages/scenery.h index f5cbe87..31b2c50 100644 --- a/lib_paysages/scenery.h +++ b/lib_paysages/scenery.h @@ -10,9 +10,9 @@ #include "tools/pack.h" #include "atmosphere/public.h" +#include "clouds/public.h" #include "terrain/public.h" #include "camera.h" -#include "clouds.h" #include "textures.h" #include "water.h" #include "renderer.h" diff --git a/lib_paysages/terrain/main.c b/lib_paysages/terrain/main.c index b461c36..b0b4f46 100644 --- a/lib_paysages/terrain/main.c +++ b/lib_paysages/terrain/main.c @@ -120,7 +120,7 @@ static Color _getFinalColor(Renderer* renderer, Vector3 location, double precisi /* TODO Factorize this in scenery renderer */ color = renderer->atmosphere->applyAerialPerspective(renderer, location, color); - color = renderer->applyClouds(renderer, color, renderer->camera_location, location); + color = renderer->clouds->getColor(renderer, color, renderer->camera_location, location); return color; } @@ -193,7 +193,7 @@ static RayCastingResult _castRay(Renderer* renderer, Vector3 start, Vector3 dire return result; } -static int _alterLight(LightDefinition* light, Vector3 location, Renderer* renderer) +static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) { TerrainDefinition* definition = renderer->terrain->definition; Vector3 inc_vector, direction_to_light; diff --git a/lib_paysages/tools/color.c b/lib_paysages/tools/color.c index 4a0181f..ba6c688 100644 --- a/lib_paysages/tools/color.c +++ b/lib_paysages/tools/color.c @@ -120,6 +120,23 @@ void colorMask(Color* base, Color* mask) double colorNormalize(Color* col) { + assert(col->r >= 0.0); + assert(col->g >= 0.0); + assert(col->b >= 0.0); + assert(col->a >= 0.0); +#ifdef isnan + assert(!isnan(col->r)); + assert(!isnan(col->g)); + assert(!isnan(col->b)); + assert(!isnan(col->a)); +#endif +#ifdef isfinite + assert(isfinite(col->r)); + assert(isfinite(col->g)); + assert(isfinite(col->b)); + assert(isfinite(col->a)); +#endif + if (col->r > 1.0) { col->r = 1.0; @@ -136,10 +153,6 @@ double colorNormalize(Color* col) /*double max = colorGetValue(col); assert(max >= 0.0); - assert(col->r >= 0.0); - assert(col->g >= 0.0); - assert(col->b >= 0.0); - assert(col->a >= 0.0); if (max > 1.0) { diff --git a/lib_paysages/tools/lighting.c b/lib_paysages/tools/lighting.c index 276e6b9..d4bd245 100644 --- a/lib_paysages/tools/lighting.c +++ b/lib_paysages/tools/lighting.c @@ -97,7 +97,7 @@ void lightingPushLight(LightStatus* status, LightDefinition* light) { LightFilterCallback callback = manager->callbacks[i]; LightDefinition temp = final; - if (callback.filter(&temp, status->location, callback.data)) + if (callback.filter(callback.data, &temp, status->location)) { final = temp; } @@ -147,6 +147,7 @@ Color lightingApplyOneLight(LightDefinition* light, Vector3 eye, Vector3 locatio /* diffused light */ double diffuse = v3Dot(direction_inv, normal); + diffuse = (diffuse + (1.0 - normal_norm)) / (1.0 + (1.0 - normal_norm)); if (diffuse > 0.0) { result.r += diffuse * material->base.r * light_color.r; diff --git a/lib_paysages/tools/lighting.h b/lib_paysages/tools/lighting.h index 71587d3..901f7e1 100644 --- a/lib_paysages/tools/lighting.h +++ b/lib_paysages/tools/lighting.h @@ -24,7 +24,7 @@ typedef struct int altered; /* Should the light be filtered or masked (by atmosphere, water, ground, clouds...) */ } LightDefinition; -typedef int (*FuncLightingAlterLight)(LightDefinition* light, Vector3 at, void* data); +typedef int (*FuncLightingAlterLight)(void* data, LightDefinition* light, Vector3 at); typedef struct LightingManager LightingManager; typedef struct LightStatus LightStatus; diff --git a/lib_paysages/water.c b/lib_paysages/water.c index 9042b6e..259264d 100644 --- a/lib_paysages/water.c +++ b/lib_paysages/water.c @@ -352,7 +352,7 @@ WaterResult waterGetColorDetail(WaterDefinition* definition, Renderer* renderer, color = renderer->applyLightingToSurface(renderer, location, normal, &material); color = renderer->atmosphere->applyAerialPerspective(renderer, location, color); - color = renderer->applyClouds(renderer, color, renderer->camera_location, location); + color = renderer->clouds->getColor(renderer, color, renderer->camera_location, location); result.base = definition->material.base; result.final = color;