diff --git a/gui_qt/formclouds.cpp b/gui_qt/formclouds.cpp index 7c907c6..186ff72 100644 --- a/gui_qt/formclouds.cpp +++ b/gui_qt/formclouds.cpp @@ -51,6 +51,89 @@ private: CloudsLayerDefinition _preview_layer; }; +class PreviewCloudsColor:public Preview +{ +public: + PreviewCloudsColor(QWidget* parent):Preview(parent) + { + LightDefinition light; + + _preview_layer = cloudsLayerCreateDefinition(); + + _lighting = lightingCreateDefinition(); + light.color = COLOR_WHITE; + light.amplitude = 0.0; + light.direction.x = 0.0; + light.direction.y = -0.4794; + light.direction.z = 0.8776; + light.filtered = 0; + light.masked = 1; + light.reflection = 1.0; + lightingAddLight(&_lighting, light); + lightingValidateDefinition(&_lighting); + + _renderer = rendererCreate(); + _renderer.render_quality = 3; + _renderer.applyLightingToSurface = _applyLightingToSurface; + _renderer.maskLight = _maskLight; + _renderer.customData[0] = &_preview_layer; + _renderer.customData[1] = &_lighting; + } +protected: + QColor getColor(double x, double y) + { + Vector3 start, end; + Color color_layer, result; + + start.x = x; + start.y = y; + start.z = -100.0; + + end.x = x; + end.y = y; + end.z = 100.0; + + result = COLOR_BLUE; + color_layer = cloudsGetLayerColor(&_preview_layer, &_renderer, start, end); + colorMask(&result, &color_layer); + return colorToQColor(result); + } + void updateData() + { + cloudsLayerCopyDefinition(&_layer, &_preview_layer); + _preview_layer.ymin = -100.0; + _preview_layer.ycenter = 0.0; + _preview_layer.ymax = 100.0; + _preview_layer.customcoverage = _coverageFunc; + } +private: + Renderer _renderer; + CloudsLayerDefinition _preview_layer; + LightingDefinition _lighting; + + static double _coverageFunc(CloudsLayerDefinition* layer, Vector3 position) + { + double dist = v3Norm(position); + + if (dist >= 100.0) + { + return 0.0; + } + else + { + return 1.0 - dist / 100.0; + } + } + static Color _applyLightingToSurface(Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material) + { + return lightingApplyToSurface((LightingDefinition*)renderer->customData[1], renderer, location, normal, material); + } + static Color _maskLight(Renderer* renderer, Color light_color, Vector3 at_location, Vector3 light_location, Vector3 direction_to_light) + { + return cloudsLayerFilterLight((CloudsLayerDefinition*)renderer->customData[0], renderer, light_color, at_location, light_location, direction_to_light); + } +}; + /**************** Form ****************/ FormClouds::FormClouds(QWidget *parent): BaseForm(parent, false, true) @@ -59,6 +142,7 @@ FormClouds::FormClouds(QWidget *parent): _layer = cloudsLayerCreateDefinition(); addPreview(new PreviewCloudsCoverage(parent), "Layer coverage (no lighting)"); + addPreview(new PreviewCloudsColor(parent), "Color and lighting"); addInputDouble("Start altitude", &_layer.ymin, -10.0, 250.0, 0.5, 5.0); addInputDouble("Max density altitude", &_layer.ycenter, -10.0, 250.0, 0.5, 5.0); diff --git a/lib_paysages/clouds.c b/lib_paysages/clouds.c index 5bb3c33..bb60cbb 100644 --- a/lib_paysages/clouds.c +++ b/lib_paysages/clouds.c @@ -117,6 +117,29 @@ void cloudsValidateDefinition(CloudsDefinition* definition) } } +static double _standardCoverageFunc(CloudsLayerDefinition* layer, Vector3 position) +{ + double inside; + + if (position.y > layer->ycenter) + { + inside = 1.0 - (position.y - layer->ycenter) / (layer->ymax - layer->ycenter); + } + else + { + inside = 1.0 - (layer->ycenter - position.y) / (layer->ycenter - layer->ymin); + } + + if (inside <= 0.0) + { + return 0.0; + } + else + { + return layer->coverage * inside; + } +} + CloudsLayerDefinition cloudsLayerCreateDefinition() { CloudsLayerDefinition result; @@ -133,6 +156,8 @@ CloudsLayerDefinition cloudsLayerCreateDefinition() result.ymin = 50.0; result.ycenter = 100.0; result.ymax = 200.0; + + result.customcoverage = _standardCoverageFunc; return result; } @@ -188,8 +213,7 @@ int cloudsAddLayer(CloudsDefinition* definition) if (definition->nblayers < CLOUDS_MAX_LAYERS) { layer = definition->layers + definition->nblayers; - layer->noise = noiseCreateGenerator(); - layer->coverage = 0.0; + *layer = cloudsLayerCreateDefinition(); return definition->nblayers++; } @@ -214,45 +238,47 @@ void cloudsDeleteLayer(CloudsDefinition* definition, int layer) static inline double _getDistanceToBorder(CloudsLayerDefinition* layer, Vector3 position) { - double val, min; - - if (position.y > layer->ycenter) - { - min = (position.y - layer->ycenter) / (layer->ymax - layer->ycenter); - } - else - { - min = (layer->ycenter - position.y) / (layer->ycenter - layer->ymin); - } + double val; val = 0.5 * noiseGet3DTotal(layer->noise, position.x / layer->scaling, position.y / layer->scaling, position.z / layer->scaling) / noiseGetMaxValue(layer->noise); - return (val - 0.5 - min + layer->coverage) * layer->scaling; + return (val - 0.5 + layer->customcoverage(layer, position)) * layer->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 = noiseGet3DDetail(layer->noise, position.x / layer->scaling, position.y / layer->scaling, position.z / layer->scaling, detail); + val = _getDistanceToBorder(layer, position); - dval = val - noiseGet3DDetail(layer->noise, (position.x + detail) / layer->scaling, position.y / layer->scaling, position.z / layer->scaling, detail); + dposition.x = position.x + detail; + dposition.y = position.y; + dposition.z = position.z; + dval = val - _getDistanceToBorder(layer, dposition); result.x += dval; - dval = val - noiseGet3DDetail(layer->noise, (position.x - detail) / layer->scaling, position.y / layer->scaling, position.z / layer->scaling, detail); + dposition.x = position.x - detail; + dval = val - _getDistanceToBorder(layer, dposition); result.x -= dval; - dval = val - noiseGet3DDetail(layer->noise, position.x / layer->scaling, (position.y + detail) / layer->scaling, position.z / layer->scaling, detail); + dposition.x = position.x; + dposition.y = position.y + detail; + dval = val - _getDistanceToBorder(layer, dposition); result.y += dval; - dval = val - noiseGet3DDetail(layer->noise, position.x / layer->scaling, (position.y - detail) / layer->scaling, position.z / layer->scaling, detail); + dposition.y = position.y - detail; + dval = val - _getDistanceToBorder(layer, dposition); result.y -= dval; - dval = val - noiseGet3DDetail(layer->noise, position.x / layer->scaling, position.y / layer->scaling, (position.z + detail) / layer->scaling, detail); + dposition.y = position.y; + dposition.z = position.z + detail; + dval = val - _getDistanceToBorder(layer, dposition); result.z += dval; - dval = val - noiseGet3DDetail(layer->noise, position.x / layer->scaling, position.y / layer->scaling, (position.z - detail) / layer->scaling, detail); + dposition.z = position.z - detail; + dval = val - _getDistanceToBorder(layer, dposition); result.z -= dval; return v3Normalize(result); diff --git a/lib_paysages/clouds.h b/lib_paysages/clouds.h index f9371da..f8ed0dd 100644 --- a/lib_paysages/clouds.h +++ b/lib_paysages/clouds.h @@ -12,7 +12,11 @@ extern "C" { #define CLOUDS_MAX_LAYERS 6 -typedef struct +typedef struct CloudsLayerDefinition CloudsLayerDefinition; + +typedef double (*CloudCoverageFunc)(CloudsLayerDefinition* definition, Vector3 position); + +struct CloudsLayerDefinition { double ycenter; double ymin; @@ -24,7 +28,8 @@ typedef struct double minimumlight; double scaling; double coverage; -} CloudsLayerDefinition; + CloudCoverageFunc customcoverage; +}; typedef struct {