diff --git a/src/interface/desktop/formclouds.h b/src/interface/desktop/formclouds.h index c6560fc..de4118c 100644 --- a/src/interface/desktop/formclouds.h +++ b/src/interface/desktop/formclouds.h @@ -4,7 +4,6 @@ #include "desktop_global.h" #include "baseformlayer.h" -#include "clouds/public.h" class QWidget; class FormClouds : public BaseFormLayer diff --git a/src/interface/desktop/formrender.cpp b/src/interface/desktop/formrender.cpp index 05020ab..da69eaf 100644 --- a/src/interface/desktop/formrender.cpp +++ b/src/interface/desktop/formrender.cpp @@ -7,7 +7,6 @@ #include "tools.h" #include "render.h" #include "atmosphere/public.h" -#include "clouds/public.h" #include "terrain/public.h" #include "water/public.h" #include "RenderingScenery.h" diff --git a/src/render/preview/CloudsAspectPreviewRenderer.cpp b/src/render/preview/CloudsAspectPreviewRenderer.cpp index 53a662e..46fc362 100644 --- a/src/render/preview/CloudsAspectPreviewRenderer.cpp +++ b/src/render/preview/CloudsAspectPreviewRenderer.cpp @@ -1,11 +1,11 @@ #include "CloudsAspectPreviewRenderer.h" -#include "clouds/public.h" #include "atmosphere/public.h" #include "BasePreview.h" #include "Scenery.h" #include "CloudsDefinition.h" #include "CloudLayerDefinition.h" +#include "CloudsRenderer.h" static void _getLightingStatus(Renderer*, LightStatus* status, Vector3, int) { @@ -61,7 +61,6 @@ CloudsAspectPreviewRenderer::CloudsAspectPreviewRenderer(CloudLayerDefinition* l CloudsDefinition* clouds = getScenery()->getClouds(); clouds->clear(); clouds->addLayer(); - CloudsRendererClass.bind(this, clouds); render_quality = 6; } @@ -82,7 +81,7 @@ void CloudsAspectPreviewRenderer::updateEvent() prepare(); - clouds->getLayerDensity = _getDensity; + //clouds->getLayerDensity = _getDensity; atmosphere->getLightingStatus = _getLightingStatus; atmosphere->applyAerialPerspective = _fakeApplyAerialPerspective; } @@ -100,5 +99,5 @@ Color CloudsAspectPreviewRenderer::getColor2D(double x, double y, double) end.z = start.z; end.y = -start.y; - return clouds->getColor(this, COLOR_BLUE, start, end); + return getCloudsRenderer()->getColor(start, end, COLOR_BLUE); } diff --git a/src/render/preview/CloudsCoveragePreviewRenderer.cpp b/src/render/preview/CloudsCoveragePreviewRenderer.cpp index cac8d5f..8fbbe68 100644 --- a/src/render/preview/CloudsCoveragePreviewRenderer.cpp +++ b/src/render/preview/CloudsCoveragePreviewRenderer.cpp @@ -1,10 +1,10 @@ #include "CloudsCoveragePreviewRenderer.h" -#include "clouds/public.h" #include "BasePreview.h" #include "Scenery.h" #include "CloudsDefinition.h" #include "CloudLayerDefinition.h" +#include "CloudsRenderer.h" Color _fakeApplyLightingToSurface(Renderer*, Vector3, Vector3, SurfaceMaterial*) { @@ -19,7 +19,6 @@ CloudsCoveragePreviewRenderer::CloudsCoveragePreviewRenderer(CloudLayerDefinitio CloudsDefinition* clouds = getScenery()->getClouds(); clouds->clear(); clouds->addLayer(); - CloudsRendererClass.bind(this, clouds); } void CloudsCoveragePreviewRenderer::bindEvent(BasePreview* preview) @@ -49,7 +48,7 @@ Color CloudsCoveragePreviewRenderer::getColor2D(double x, double y, double scali look.z = 1.0; look = look.normalize(); - return clouds->getColor(this, COLOR_BLUE, eye, eye.add(look.scale(1000.0))); + return getCloudsRenderer()->getColor(eye, eye.add(look.scale(1000.0)), COLOR_BLUE); } else { @@ -60,7 +59,7 @@ Color CloudsCoveragePreviewRenderer::getColor2D(double x, double y, double scali start.y = 1000.0; end.y = -1000.0; - return clouds->getColor(this, COLOR_BLUE, start, end); + return getCloudsRenderer()->getColor(start, end, COLOR_BLUE); } } diff --git a/src/render/software/BaseCloudLayerRenderer.cpp b/src/render/software/BaseCloudLayerRenderer.cpp new file mode 100644 index 0000000..8b79a66 --- /dev/null +++ b/src/render/software/BaseCloudLayerRenderer.cpp @@ -0,0 +1,80 @@ +#include "BaseCloudLayerRenderer.h" + +#include "CloudLayerDefinition.h" + +BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer* parent): + parent(parent) +{ +} + +BaseCloudLayerRenderer::~BaseCloudLayerRenderer() +{ + +} + +double BaseCloudLayerRenderer::getDensity(CloudLayerDefinition *, const Vector3 &) +{ + return 0.0; +} + +Color BaseCloudLayerRenderer::getColor(CloudLayerDefinition *, const Vector3 &, const Vector3 &) +{ + return COLOR_TRANSPARENT; +} + +bool BaseCloudLayerRenderer::alterLight(CloudLayerDefinition *, LightDefinition *, const Vector3 &, const Vector3 &) +{ + return false; +} + +bool BaseCloudLayerRenderer::optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end) +{ + Vector3 diff; + + if (start->y > layer->lower_altitude + layer->thickness) + { + if (end->y >= layer->lower_altitude + layer->thickness) + { + return false; + } + 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 false; + } + 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)); + } + } + + return true; +} diff --git a/src/render/software/BaseCloudLayerRenderer.h b/src/render/software/BaseCloudLayerRenderer.h new file mode 100644 index 0000000..44d250c --- /dev/null +++ b/src/render/software/BaseCloudLayerRenderer.h @@ -0,0 +1,30 @@ +#ifndef BASECLOUDLAYERRENDERER_H +#define BASECLOUDLAYERRENDERER_H + +#include "software_global.h" + +#include "tools/lighting.h" + +namespace paysages { +namespace software { + +class BaseCloudLayerRenderer +{ +public: + BaseCloudLayerRenderer(SoftwareRenderer* parent); + virtual ~BaseCloudLayerRenderer(); + + virtual bool optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end); + + virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location); + virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location); + virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location); + +protected: + SoftwareRenderer* parent; +}; + +} +} + +#endif // BASECLOUDLAYERRENDERER_H diff --git a/src/render/software/CloudBasicLayerRenderer.cpp b/src/render/software/CloudBasicLayerRenderer.cpp new file mode 100644 index 0000000..5e2a56d --- /dev/null +++ b/src/render/software/CloudBasicLayerRenderer.cpp @@ -0,0 +1,305 @@ +#include "CloudBasicLayerRenderer.h" + +#include "CloudLayerDefinition.h" +#include "SoftwareRenderer.h" +#include "NoiseGenerator.h" +#include "Curve.h" +#include "AtmosphereRenderer.h" + +typedef struct +{ + Vector3 start; + Vector3 end; + double length; +} CloudSegment; + +CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer* parent): + BaseCloudLayerRenderer(parent) +{ +} + +static inline double _standardCoverageFunc(CloudLayerDefinition* layer, Vector3 position) +{ + if (position.y < layer->lower_altitude || position.y > (layer->lower_altitude + layer->thickness)) + { + return 0.0; + } + else + { + return layer->base_coverage * layer->_coverage_by_altitude->getValue((position.y - layer->lower_altitude) / layer->thickness); + } +} + +static inline double _getDistanceToBorder(CloudLayerDefinition* layer, Vector3 position) +{ + double val; + double minval, maxval; + + layer->_shape_noise->getRange(&minval, &maxval); + + val = 0.5 * layer->_shape_noise->get3DTotal(position.x / layer->shape_scaling, position.y / layer->shape_scaling, position.z / layer->shape_scaling) / maxval; + + return (val - 0.5 + _standardCoverageFunc(layer, position)) * layer->shape_scaling; +} + +static inline Vector3 _getNormal(CloudLayerDefinition* 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); +} + +/** + * 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(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 start, Vector3 direction, double, 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 = 15.2 - 1.5 * (double)renderer->render_quality; + render_precision = render_precision * definition->shape_scaling / 50.0; + if (render_precision > max_total_length / 10.0) + { + render_precision = max_total_length / 10.0; + } + else if (render_precision < max_total_length / 2000.0) + { + render_precision = max_total_length / 2000.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 (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 - 0.001 && walker.y <= (definition->lower_altitude + definition->thickness) + 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(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 position, double) +{ + Vector3 normal; + Color col1, col2; + + 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); + + // TODO Compute light filter only once + col1 = renderer->applyLightingToSurface(renderer, position, normal, definition->material); + col2 = renderer->applyLightingToSurface(renderer, position, v3Scale(normal, -1.0), definition->material); + + 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; +} + +double CloudBasicLayerRenderer::getDensity(CloudLayerDefinition* layer, const Vector3 &location) +{ + return 0.0; +} + +Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location) +{ + int i, segment_count; + double max_length, detail, total_length, inside_length; + Vector3 start, end, direction; + Color result, col; + CloudSegment segments[20]; + + start = eye; + end = location; + if (!optimizeSearchLimits(layer, &start, &end)) + { + return COLOR_TRANSPARENT; + } + + direction = end.sub(start); + max_length = direction.getNorm(); + direction = direction.normalize(); + result = COLOR_TRANSPARENT; + + detail = parent->getPrecision(parent, start) / layer->shape_scaling; + + segment_count = _findSegments(layer, parent, start, direction, detail, 20, layer->transparencydepth, max_length, &inside_length, &total_length, segments); + for (i = segment_count - 1; i >= 0; i--) + { + col = _applyLayerLighting(layer, parent, segments[i].start, detail); + col.a = (segments[i].length >= layer->transparencydepth) ? 1.0 : (segments[i].length / layer->transparencydepth); + colorMask(&result, &col); + } + if (inside_length >= layer->transparencydepth) + { + result.a = 1.0; + } + + double a = result.a; + result = parent->getAtmosphereRenderer()->applyAerialPerspective(start, result).final; + result.a = a; + + return result; +} + +bool CloudBasicLayerRenderer::alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &, const Vector3 &location) +{ + Vector3 start, end; + double inside_depth, total_depth, factor; + CloudSegment segments[20]; + + start = location; + end = location.add(light->direction.scale(10000.0)); + if (not optimizeSearchLimits(layer, &start, &end)) + { + return false; + } + + _findSegments(layer, parent, start, light->direction, 0.1, 20, layer->lighttraversal, end.sub(start).getNorm(), &inside_depth, &total_depth, segments); + + if (layer->lighttraversal < 0.0001) + { + factor = 0.0; + } + else + { + factor = inside_depth / layer->lighttraversal; + if (factor > 1.0) + { + factor = 1.0; + } + } + + factor = 1.0 - (1.0 - layer->minimumlight) * factor; + + light->color.r *= factor; + light->color.g *= factor; + light->color.b *= factor; + + return true; +} diff --git a/src/render/software/CloudBasicLayerRenderer.h b/src/render/software/CloudBasicLayerRenderer.h new file mode 100644 index 0000000..ad840ae --- /dev/null +++ b/src/render/software/CloudBasicLayerRenderer.h @@ -0,0 +1,26 @@ +#ifndef CLOUDBASICLAYERRENDERER_H +#define CLOUDBASICLAYERRENDERER_H + +#include "software_global.h" + +#include "BaseCloudLayerRenderer.h" + +#include "tools/lighting.h" + +namespace paysages { +namespace software { + +class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer: public BaseCloudLayerRenderer +{ +public: + CloudBasicLayerRenderer(SoftwareRenderer* parent); + + virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location) override; + virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location) override; + virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location) override; +}; + +} +} + +#endif // CLOUDBASICLAYERRENDERER_H diff --git a/src/render/software/CloudsRenderer.cpp b/src/render/software/CloudsRenderer.cpp new file mode 100644 index 0000000..4f5fb99 --- /dev/null +++ b/src/render/software/CloudsRenderer.cpp @@ -0,0 +1,81 @@ +#include "CloudsRenderer.h" + +#include "SoftwareRenderer.h" +#include "Scenery.h" +#include "CloudsDefinition.h" +#include "BaseCloudLayerRenderer.h" +#include "CloudBasicLayerRenderer.h" + +CloudsRenderer::CloudsRenderer(SoftwareRenderer* parent): + parent(parent) +{ + fake_renderer = new BaseCloudLayerRenderer(parent); +} + +CloudsRenderer::~CloudsRenderer() +{ + for (auto renderer : layer_renderers) + { + delete renderer; + } + delete fake_renderer; +} + +void CloudsRenderer::update() +{ + for (auto renderer : layer_renderers) + { + delete renderer; + } + layer_renderers.clear(); + + CloudsDefinition* clouds = parent->getScenery()->getClouds(); + int n = clouds->count(); + for (int i = 0; i < n; i++) + { + layer_renderers.push_back(new CloudBasicLayerRenderer(parent)); + } +} + +BaseCloudLayerRenderer* CloudsRenderer::getLayerRenderer(unsigned int layer) +{ + if (layer < layer_renderers.size()) + { + return layer_renderers[layer]; + } + else + { + return fake_renderer; + } +} + +Color CloudsRenderer::getColor(const Vector3 &eye, const Vector3 &location, const Color &base) +{ + CloudsDefinition* definition = parent->getScenery()->getClouds(); + + int n = definition->count(); + if (n < 1) + { + return base; + } + + /* TODO Iter layers in sorted order */ + Color cumul = base; + + for (int i = 0; i < n; i++) + { + CloudLayerDefinition* layer = definition->getCloudLayer(i); + BaseCloudLayerRenderer* layer_renderer = getLayerRenderer(i); + + Color layer_color = layer_renderer->getColor(layer, eye, location); + + colorMask(&cumul, &layer_color); + } + + return cumul; +} + +bool CloudsRenderer::alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location) +{ + return false; +} diff --git a/src/render/software/CloudsRenderer.h b/src/render/software/CloudsRenderer.h new file mode 100644 index 0000000..f938660 --- /dev/null +++ b/src/render/software/CloudsRenderer.h @@ -0,0 +1,52 @@ +#ifndef CLOUDSRENDERER_H +#define CLOUDSRENDERER_H + +#include "software_global.h" + +#include "tools/lighting.h" + +namespace paysages { +namespace software { + +/*! + * \brief Software renderer of a group of cloud layers. + */ +class SOFTWARESHARED_EXPORT CloudsRenderer +{ +public: + CloudsRenderer(SoftwareRenderer* parent); + virtual ~CloudsRenderer(); + + /*! + * Update the renderer with the bound scenery. + */ + void update(); + + /*! + * Get the layer renderer for a given layer. + * + * The returned renderer is managed by this object and should not be deleted. + */ + virtual BaseCloudLayerRenderer* getLayerRenderer(unsigned int layer); + + /*! + * Get the composited color, as applied on a base color and location. + */ + virtual Color getColor(const Vector3 &eye, const Vector3 &location, const Color &base); + + /*! + * Alter a light, as if passed through all layers. + * + * Return true if the light was altered. + */ + virtual bool alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location); +private: + SoftwareRenderer* parent; + std::vector layer_renderers; + BaseCloudLayerRenderer* fake_renderer; +}; + +} +} + +#endif // CLOUDSRENDERER_H diff --git a/src/rendering/atmosphere/atm_raster.cpp b/src/render/software/SkyRasterizer.cpp similarity index 79% rename from src/rendering/atmosphere/atm_raster.cpp rename to src/render/software/SkyRasterizer.cpp index be9d484..f829288 100644 --- a/src/rendering/atmosphere/atm_raster.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -1,12 +1,19 @@ -#include "public.h" -#include "private.h" +#include "SkyRasterizer.h" -#include -#include -#include "../renderer.h" -#include "clouds/public.h" +#include "Vector3.h" +#include "Color.h" +#include "SoftwareRenderer.h" +#include "AtmosphereRenderer.h" +#include "CloudsRenderer.h" -static Color _postProcessFragment(Renderer* renderer, Vector3 location, void*) +#define SPHERE_SIZE 20000.0 + +SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer): + renderer(renderer) +{ +} + +static Color _postProcessFragment(SoftwareRenderer* renderer, Vector3 location, void*) { Vector3 camera_location, direction; Color result; @@ -16,12 +23,12 @@ static Color _postProcessFragment(Renderer* renderer, Vector3 location, void*) /* TODO Don't compute result->color if it's fully covered by clouds */ result = renderer->atmosphere->getSkyColor(renderer, v3Normalize(direction)).final; - result = renderer->clouds->getColor(renderer, result, camera_location, v3Add(camera_location, v3Scale(direction, 10.0))); + result = renderer->getCloudsRenderer()->getColor(camera_location, v3Add(camera_location, v3Scale(direction, 10.0)), result); return result; } -void atmosphereRenderSkydome(Renderer* renderer) +void SkyRasterizer::rasterize() { int res_i, res_j; int i, j; @@ -71,7 +78,7 @@ void atmosphereRenderSkydome(Renderer* renderer) vertex4 = v3Add(camera_location, direction); /* TODO Triangles at poles */ - renderer->pushQuad(renderer, vertex1, vertex4, vertex3, vertex2, _postProcessFragment, NULL); + renderer->pushQuad(renderer, vertex1, vertex4, vertex3, vertex2, (f_RenderFragmentCallback)_postProcessFragment, NULL); } } } diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h new file mode 100644 index 0000000..1d03902 --- /dev/null +++ b/src/render/software/SkyRasterizer.h @@ -0,0 +1,22 @@ +#ifndef SKYRASTERIZER_H +#define SKYRASTERIZER_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +class SOFTWARESHARED_EXPORT SkyRasterizer +{ +public: + SkyRasterizer(SoftwareRenderer* renderer); + void rasterize(); + +private: + SoftwareRenderer* renderer; +}; + +} +} + +#endif // SKYRASTERIZER_H diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index 6fe122f..3732e27 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -5,12 +5,14 @@ #include "FluidMediumManager.h" #include "AtmosphereRenderer.h" #include "AtmosphereDefinition.h" +#include "CloudsRenderer.h" +#include "SkyRasterizer.h" // Legacy compatibility #include "renderer.h" #include "terrain/public.h" -#include "clouds/public.h" +#include "terrain/ter_raster.h" #include "textures/public.h" #include "water/public.h" static AtmosphereResult _legacyApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base) @@ -29,8 +31,9 @@ static Vector3 _legacyGetSunDirection(Renderer* renderer) { return ((SoftwareRenderer*)renderer)->getAtmosphereRenderer()->getSunDirection(); } -static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector3 direction, int, int, int, int) +static RayCastingResult _rayWalking(Renderer* renderer_, Vector3 location, Vector3 direction, int, int, int, int) { + SoftwareRenderer* renderer = (SoftwareRenderer*)renderer_; RayCastingResult result; Color sky_color; @@ -41,7 +44,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->clouds->getColor(renderer, sky_color, location, result.hit_location); + result.hit_color = renderer->getCloudsRenderer()->getColor(location, result.hit_location, sky_color); } return result; @@ -60,6 +63,7 @@ static double _getPrecision(Renderer* renderer, Vector3 location) SoftwareRenderer::SoftwareRenderer(Scenery* scenery) { atmosphere_renderer = new BaseAtmosphereRenderer(this); + clouds_renderer = new CloudsRenderer(this); fluid_medium = new FluidMediumManager(this); @@ -78,6 +82,7 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) SoftwareRenderer::~SoftwareRenderer() { delete atmosphere_renderer; + delete clouds_renderer; delete fluid_medium; @@ -103,6 +108,10 @@ void SoftwareRenderer::prepare() delete atmosphere_renderer; atmosphere_renderer = new SoftwareBrunetonAtmosphereRenderer(this); + delete clouds_renderer; + clouds_renderer = new CloudsRenderer(this); + clouds_renderer->update(); + // Setup transitional renderers (for C-legacy subsystems) rayWalking = _rayWalking; getPrecision = _getPrecision; @@ -116,7 +125,6 @@ void SoftwareRenderer::prepare() scenery->getCamera()->copy(render_camera); TerrainRendererClass.bind(this, scenery->getTerrain()); TexturesRendererClass.bind(this, scenery->getTextures()); - CloudsRendererClass.bind(this, scenery->getClouds()); WaterRendererClass.bind(this, scenery->getWater()); // Prepare global tools @@ -124,8 +132,21 @@ void SoftwareRenderer::prepare() //fluid_medium->registerMedium(water_renderer); } -/*Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color) +void SoftwareRenderer::rasterize() { - Vector3 eye = cameraGetLocation(scenery->getCamera()); - return fluid_medium->applyTraversal(eye, location, color); -}*/ + terrainRenderSurface(this); + waterRenderSurface(this); + + SkyRasterizer sky(this); + sky.rasterize(); +} + +Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color) +{ + color = atmosphere->applyAerialPerspective(this, location, color).final; + color = clouds_renderer->getColor(getCameraLocation(this, location), location, color); + return color; + + /*Vector3 eye = cameraGetLocation(scenery->getCamera()); + return fluid_medium->applyTraversal(eye, location, color);*/ +} diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 6eeaa35..7fef971 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -33,17 +33,26 @@ public: */ virtual void prepare() override; + /*! + * \brief Start the rasterization process. + */ + virtual void rasterize() override; + inline Scenery* getScenery() const {return scenery;} + inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;} + inline CloudsRenderer* getCloudsRenderer() const {return clouds_renderer;} + inline FluidMediumManager* getFluidMediumManager() const {return fluid_medium;} - //virtual Color applyMediumTraversal(Vector3 location, Color color) override; + virtual Color applyMediumTraversal(Vector3 location, Color color) override; private: Scenery* scenery; bool own_scenery; FluidMediumManager* fluid_medium; BaseAtmosphereRenderer* atmosphere_renderer; + CloudsRenderer* clouds_renderer; }; } diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 8bb3f04..88ed67a 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -16,13 +16,21 @@ include(../../common.pri) SOURCES += SoftwareRenderer.cpp \ FluidMediumInterface.cpp \ FluidMediumManager.cpp \ - AtmosphereRenderer.cpp + AtmosphereRenderer.cpp \ + CloudsRenderer.cpp \ + BaseCloudLayerRenderer.cpp \ + SkyRasterizer.cpp \ + CloudBasicLayerRenderer.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ FluidMediumInterface.h \ FluidMediumManager.h \ - AtmosphereRenderer.h + AtmosphereRenderer.h \ + CloudsRenderer.h \ + BaseCloudLayerRenderer.h \ + SkyRasterizer.h \ + CloudBasicLayerRenderer.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 1ce927d..1cb06aa 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -21,6 +21,9 @@ namespace software { class BaseAtmosphereRenderer; class SoftwareBrunetonAtmosphereRenderer; + + class CloudsRenderer; + class BaseCloudLayerRenderer; } } diff --git a/src/rendering/RenderingScenery.cpp b/src/rendering/RenderingScenery.cpp index 6a30fd4..cec9e62 100644 --- a/src/rendering/RenderingScenery.cpp +++ b/src/rendering/RenderingScenery.cpp @@ -55,13 +55,3 @@ void RenderingScenery::bindToRenderer(Renderer* renderer) renderer->setScenery(this); renderer->prepare(); } - - -// Transitional C-API - -void sceneryRenderFirstPass(Renderer* renderer) -{ - terrainRenderSurface(renderer); - waterRenderSurface(renderer); - atmosphereRenderSkydome(renderer); -} diff --git a/src/rendering/RenderingScenery.h b/src/rendering/RenderingScenery.h index 462c853..558b7a7 100644 --- a/src/rendering/RenderingScenery.h +++ b/src/rendering/RenderingScenery.h @@ -34,8 +34,4 @@ private: void* _custom_data; }; -// Transitional C-API - -RENDERINGSHARED_EXPORT void sceneryRenderFirstPass(Renderer* renderer); - #endif // SCENERY_H diff --git a/src/rendering/atmosphere/public.h b/src/rendering/atmosphere/public.h index c25e3ed..6125156 100644 --- a/src/rendering/atmosphere/public.h +++ b/src/rendering/atmosphere/public.h @@ -38,8 +38,6 @@ public: RENDERINGSHARED_EXPORT extern StandardRenderer AtmosphereRendererClass; -RENDERINGSHARED_EXPORT void atmosphereRenderSkydome(Renderer* renderer); - RENDERINGSHARED_EXPORT void atmosphereInitResult(AtmosphereResult* result); RENDERINGSHARED_EXPORT void atmosphereUpdateResult(AtmosphereResult* result); diff --git a/src/rendering/clouds/clo_density.cpp b/src/rendering/clouds/clo_density.cpp deleted file mode 100644 index 0c5fa74..0000000 --- a/src/rendering/clouds/clo_density.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "clo_density.h" - -#include "NoiseGenerator.h" -#include "CloudLayerDefinition.h" -#include "Curve.h" - -double cloudsGetLayerCoverage(CloudLayerDefinition* layer, Vector3 location) -{ - if (layer->base_coverage <= 0.0) - { - return 0.0; - } - else - { - double coverage = 0.5 + layer->_coverage_noise->get2DTotal(location.x / layer->shape_scaling, location.z / layer->shape_scaling); - coverage -= (1.0 - layer->base_coverage); - - coverage *= layer->_coverage_by_altitude->getValue((location.y - layer->lower_altitude) / layer->thickness); - - if (coverage < 0.0) - { - return 0.0; - } - else if (coverage >= 1.0) - { - return 1.0; - } - else - { - return coverage; - } - } -} - -double cloudsGetLayerDensity(CloudLayerDefinition* layer, Vector3 location, double coverage) -{ - if (coverage <= 0.0) - { - return 0.0; - } - else if (coverage >= 1.0) - { - return 1.0; - } - else - { - double density = layer->_shape_noise->get3DTotal(location.x / layer->shape_scaling, location.y / layer->shape_scaling, location.z / layer->shape_scaling); - density -= (0.5 - coverage); - return (density <= 0.0) ? 0.0 : density; - } -} - -double cloudsGetEdgeDensity(CloudLayerDefinition* layer, Vector3 location, double layer_density) -{ - if (layer_density <= 0.0) - { - return 0.0; - } - else if (layer_density >= 1.0) - { - return 1.0; - } - else - { - double density = layer->_edge_noise->get3DTotal(location.x / layer->edge_scaling, location.y / layer->edge_scaling, location.z / layer->edge_scaling); - density -= (0.5 - layer_density); - return (density <= 0.0) ? 0.0 : density; - } -} - -static double _fakeGetDensity(Renderer*, CloudLayerDefinition*, Vector3) -{ - return 0.0; -} - -static double _fakeGetEdgeDensity(Renderer*, CloudLayerDefinition*, Vector3, double) -{ - return 0.0; -} - -void cloudsBindFakeDensityToRenderer(CloudsRenderer* renderer) -{ - renderer->getLayerDensity = _fakeGetDensity; - renderer->getEdgeDensity = _fakeGetEdgeDensity; -} - -static double _realGetDensity(Renderer*, CloudLayerDefinition* layer, Vector3 location) -{ - double coverage = cloudsGetLayerCoverage(layer, location); - - return cloudsGetLayerDensity(layer, location, coverage); -} - -static double _realGetEdgeDensity(Renderer*, CloudLayerDefinition* layer, Vector3 location, double layer_density) -{ - return cloudsGetEdgeDensity(layer, location, layer_density); -} - -void cloudsBindRealDensityToRenderer(CloudsRenderer* renderer) -{ - renderer->getLayerDensity = _realGetDensity; - renderer->getEdgeDensity = _realGetEdgeDensity; -} diff --git a/src/rendering/clouds/clo_density.h b/src/rendering/clouds/clo_density.h deleted file mode 100644 index e0724dc..0000000 --- a/src/rendering/clouds/clo_density.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _PAYSAGES_CLOUDS_DENSITY_H_ -#define _PAYSAGES_CLOUDS_DENSITY_H_ - -#include "public.h" - -/** - * Coverage/density management in a cloud layer. - */ - -/** - * Get the coverage of a cloud layer [0.0;1.0] - * - * 0.0 means no cloud is present. - * 1.0 means full layer. - */ -RENDERINGSHARED_EXPORT double cloudsGetLayerCoverage(CloudLayerDefinition* layer, Vector3 location); - -/** - * Get the global density of a cloud layer at a given point [0.0;1.0]. - * - * 0.0 means no cloud is present. - * 1.0 means full density (deep inside cloud). - */ -RENDERINGSHARED_EXPORT double cloudsGetLayerDensity(CloudLayerDefinition* layer, Vector3 location, double coverage); - -/** - * Get the local density of a cloud layer at a given point inside an edge [0.0;1.0]. - */ -RENDERINGSHARED_EXPORT double cloudsGetEdgeDensity(CloudLayerDefinition* layer, Vector3 location, double layer_density); - -/* - * Bind fake density functions to a renderer. - */ -RENDERINGSHARED_EXPORT void cloudsBindFakeDensityToRenderer(CloudsRenderer* renderer); - -/* - * Bind real density functions to a renderer. - */ -RENDERINGSHARED_EXPORT void cloudsBindRealDensityToRenderer(CloudsRenderer* renderer); - -#endif diff --git a/src/rendering/clouds/clo_rendering.cpp b/src/rendering/clouds/clo_rendering.cpp deleted file mode 100644 index 2b81de0..0000000 --- a/src/rendering/clouds/clo_rendering.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "private.h" - -#include -#include -#include "../renderer.h" -#include "clo_density.h" -#include "clo_walking.h" -#include "atmosphere/public.h" -#include "CloudsDefinition.h" -#include "CloudLayerDefinition.h" - -/******************** Fake ********************/ -static int _fakeAlterLight(Renderer*, LightDefinition*, Vector3) -{ - return 0; -} - -static Color _fakeGetColor(Renderer*, Color base, Vector3, Vector3) -{ - return base; -} - -/******************** Real ********************/ -typedef struct -{ - double light_power; - double out_scattering; /* Amount of light scattered away by heavy particles */ -} AccumulatedLightData; - -static void _walkerFilterCallback(CloudsWalker* walker) -{ - CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker); - Renderer* renderer = segment->renderer; - AccumulatedLightData* data = (AccumulatedLightData*)segment->data; - - assert(data != NULL); - - double density_integral; - if (segment->subdivided) - { - density_integral = segment->length * (segment->start.local_density + segment->end.local_density) / 2.0; - } - else - { - if (!segment->refined && segment->start.global_density == 0.0 && segment->end.global_density > 0.0) - { - cloudsWalkerOrderRefine(walker, 1.0 / (double)renderer->render_quality); - return; - } - else if ((segment->start.global_density > 0.0 || segment->end.global_density > 0.0) && (segment->start.global_density < 1.0 || segment->end.global_density < 1.0)) - { - cloudsWalkerOrderSubdivide(walker, renderer->render_quality + 1); - return; - } - 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 = definition->count(); - for (i = 0; i < n; i++) - { - CloudLayerDefinition* layer = definition->getCloudLayer(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); - cloudsWalkerSetVoidSkipping(walker, 1); - cloudsStartWalking(walker, _walkerFilterCallback, &data); - cloudsDeleteWalker(walker); - } - } - - double max_power = data.light_power - 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 */ - int entry_found; /* 1 if a cloud entry has been found */ - Vector3 entry; /* Point of entry in the clouds */ -} 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; - CloudLayerDefinition* layer = segment->layer; - - assert(data != NULL); - - double density_integral; - if (segment->subdivided) - { - density_integral = segment->length * (segment->start.local_density + segment->end.local_density) / 2.0; - } - else - { - if (!segment->refined && segment->start.global_density == 0.0 && segment->end.global_density > 0.0) - { - cloudsWalkerOrderRefine(walker, 1.0 / (double)(renderer->render_quality * renderer->render_quality)); - return; - } - else if ((segment->start.global_density > 0.0 || segment->end.global_density > 0.0) && (segment->start.global_density < 1.0 || segment->end.global_density < 1.0)) - { - cloudsWalkerOrderSubdivide(walker, renderer->render_quality + 3); - return; - } - density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0; - } - - if (density_integral > 0.0) - { - data->out_scattering += 0.3 * density_integral; - - Color in_scattering = renderer->applyLightingToSurface(renderer, segment->start.location, VECTOR_ZERO, 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; - - if (!data->entry_found) - { - data->entry_found = 1; - data->entry = segment->start.location; - } - } -} - -static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end) -{ - CloudsDefinition* definition = renderer->clouds->definition; - int i, n; - - n = definition->count(); - if (n < 1) - { - return base; - } - - /* TODO Iter layers in sorted order */ - for (i = 0; i < n; i++) - { - CloudLayerDefinition* layer = definition->getCloudLayer(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; - data.entry = ostart; - data.entry_found = 0; - - walker = cloudsCreateWalker(renderer, layer, ostart, oend); - cloudsWalkerSetStepSize(walker, -1.0); - cloudsWalkerSetVoidSkipping(walker, 1); - 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 */ - base = renderer->atmosphere->applyAerialPerspective(renderer, data.entry, base).final; - } - } - - return base; -} - -/******************** Renderer ********************/ -static CloudsRenderer* _createRenderer() -{ - CloudsRenderer* result; - - result = new CloudsRenderer; - result->definition = new CloudsDefinition(NULL); - - result->getColor = _fakeGetColor; - result->alterLight = (FuncLightingAlterLight)_fakeAlterLight; - - cloudsBindFakeDensityToRenderer(result); - - return result; -} - -static void _deleteRenderer(CloudsRenderer* renderer) -{ - delete renderer->definition; - delete renderer; -} - -static void _bindRenderer(Renderer* renderer, CloudsDefinition* definition) -{ - definition->copy(renderer->clouds->definition); - - renderer->clouds->getColor = _getColor; - renderer->clouds->alterLight = (FuncLightingAlterLight)_alterLight; - - cloudsBindRealDensityToRenderer(renderer->clouds); - - lightingManagerRegisterFilter(renderer->lighting, (FuncLightingAlterLight)_alterLight, renderer); -} - -StandardRenderer CloudsRendererClass = { - (FuncObjectCreate)_createRenderer, - (FuncObjectDelete)_deleteRenderer, - (FuncObjectBind)_bindRenderer -}; diff --git a/src/rendering/clouds/clo_walking.cpp b/src/rendering/clouds/clo_walking.cpp deleted file mode 100644 index 9d70ebb..0000000 --- a/src/rendering/clouds/clo_walking.cpp +++ /dev/null @@ -1,364 +0,0 @@ -#include "clo_walking.h" - -#include "../renderer.h" -#include "CloudLayerDefinition.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 skip_void; - int local_density; - - int started; - CloudWalkerStepInfo last_segment; - - int subdivision_current; - int subdivision_count; - CloudWalkerStepInfo subdivision_parent; - - CloudWalkingNextAction next_action; -}; - - -int cloudsOptimizeWalkingBounds(CloudLayerDefinition* 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)); - } - } - - return 1; -} - -CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudLayerDefinition* layer, Vector3 start, Vector3 end) -{ - CloudsWalker* result; - - result = (CloudsWalker*)malloc(sizeof (CloudsWalker)); - - 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; - result->skip_void = 0; - result->local_density = -1; - - result->started = 0; - result->subdivision_count = 0; - result->last_segment.renderer = renderer; - result->last_segment.layer = layer; - - result->next_action.order = CLOUD_WALKING_CONTINUE; - - 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 = 5.0 / (double)walker->last_segment.renderer->render_quality; - } -} - -void cloudsWalkerToggleLocalDensity(CloudsWalker* walker, int enabled) -{ - walker->local_density = enabled; -} - -void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled) -{ - walker->skip_void = enabled; -} - -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; - CloudLayerDefinition* layer = walker->last_segment.layer; - out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location); - - if (walker->local_density > 0 || (walker->local_density < 0 && walker->subdivision_count > 0)) - { - out_point->local_density = renderer->clouds->getEdgeDensity(renderer, layer, out_point->location, out_point->global_density); - } - else - { - out_point->local_density = 0.0; - } -} - -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) -{ - int result = -1; - - if (!walker->started) - { - _getPoint(walker, 0.0, &walker->last_segment.end); - walker->started = 1; - } - - while (result < 0) - { - if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length) - { - walker->next_action.order = CLOUD_WALKING_STOP; - result = 0; - } - else if (walker->subdivision_count > 0) - { - if (walker->subdivision_current >= walker->subdivision_count) - { - /* Exit subdivision */ - walker->subdivision_count = 0; - walker->last_segment = walker->subdivision_parent; - walker->next_action.order = CLOUD_WALKING_CONTINUE; - walker->cursor = walker->subdivision_parent.end.distance_from_start; - - /* Recursive call to progress */ - result = cloudsWalkerPerformStep(walker); - } - else - { - /* Continue subdivision */ - walker->last_segment.start = walker->last_segment.end; - - walker->cursor += walker->subdivision_parent.length / (double)walker->subdivision_count; - - _getPoint(walker, walker->cursor, &walker->last_segment.end); - walker->last_segment.length = walker->subdivision_parent.length / (double)walker->subdivision_count; - walker->last_segment.refined = 0; - walker->last_segment.subdivided = walker->subdivision_count; - - walker->subdivision_current++; - - result = 1; - } - } - else if (walker->next_action.order == CLOUD_WALKING_CONTINUE) - { - /* TODO Limit to lookup 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; - walker->last_segment.subdivided = 0; - - result = 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->last_segment.subdivided = 0; - - walker->next_action.order = CLOUD_WALKING_CONTINUE; - - result = 1; - } - else if (walker->next_action.order == CLOUD_WALKING_SUBDIVIDE) - { - /* Starting subdivision */ - walker->subdivision_count = walker->next_action.max_segments; - walker->subdivision_current = 0; - walker->subdivision_parent = walker->last_segment; - walker->cursor = walker->subdivision_parent.start.distance_from_start; - - /* Copy parent segment start, to be used as first subdivided segment start */ - walker->last_segment.end = walker->subdivision_parent.start; - - /* Recursive call to get first subdivided segment */ - cloudsWalkerPerformStep(walker); - - result = 1; - } - else - { - /* Unknown order... */ - result = 0; - } - - /* Check if we need to loop */ - if (result > 0 && walker->skip_void && walker->last_segment.start.global_density == 0.0 && walker->last_segment.end.global_density == 0.0) - { - /* Last segment is considered void, and skipping is enabled */ - result = -1; - } - } - - return result; -} - -void cloudsWalkerOrderStop(CloudsWalker* walker) -{ - walker->next_action.order = CLOUD_WALKING_STOP; -} - -void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision) -{ - if (walker->subdivision_count == 0) - { - walker->next_action.order = CLOUD_WALKING_REFINE; - walker->next_action.precision = precision; - } -} - -void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments) -{ - if (walker->subdivision_count == 0) - { - 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); - } -} diff --git a/src/rendering/clouds/clo_walking.h b/src/rendering/clouds/clo_walking.h deleted file mode 100644 index a355f66..0000000 --- a/src/rendering/clouds/clo_walking.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef _PAYSAGES_CLOUDS_WALKING_H_ -#define _PAYSAGES_CLOUDS_WALKING_H_ - -#include "public.h" - -#include "Vector3.h" - -/** - * Functions to walk through a cloud layer. - */ - -typedef struct -{ - double distance_from_start; - Vector3 location; - double global_density; - double local_density; -} CloudWalkerPoint; - -/** - * Information on a segment yielded by walking. - */ -typedef struct -{ - Renderer* renderer; - CloudLayerDefinition* layer; - - CloudWalkerPoint start; - CloudWalkerPoint end; - double length; - - int refined; - int subdivided; - - void* data; -} CloudWalkerStepInfo; - -typedef struct CloudsWalker CloudsWalker; - -typedef void (*FuncCloudsWalkingCallback)(CloudsWalker* walker); - -/** - * 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 - */ -RENDERINGSHARED_EXPORT int cloudsOptimizeWalkingBounds(CloudLayerDefinition* layer, Vector3* start, Vector3* end); - -/** - * Create a cloud walker. - * - * 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 - */ -RENDERINGSHARED_EXPORT CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudLayerDefinition* layer, Vector3 start, Vector3 end); - -/** - * Delete a cloud walker. - * - * @param walker The walker to free - */ -RENDERINGSHARED_EXPORT 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 - */ -RENDERINGSHARED_EXPORT void cloudsWalkerSetStepSize(CloudsWalker* walker, double step); - -/** - * Set the void skipping mode. - * - * @param walker The walker to configure - * @param enabled 1 to enable the void skipping, 0 to disable - */ -RENDERINGSHARED_EXPORT void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled); - -/** - * Toggle the local density computing. - * - * When this option is set, the CloudWalkerStepInfo will contain information about local density. - * The automatic setting will set to 1 on subdivided steps, and 0 elsewhere. - * @param walker The walker to configure - * @param enabled 1 to enable local density, 0 to disable it, -1 for automatic setting. - */ -RENDERINGSHARED_EXPORT void cloudsWalkerToggleLocalDensity(CloudsWalker* walker, int enabled); - -/** - * Perform a single step. - * - * @param walker The walker to use - * @return 1 to continue the loop, 0 to stop - */ -RENDERINGSHARED_EXPORT int cloudsWalkerPerformStep(CloudsWalker* walker); - -/** - * Order the walker to stop. - * - * @param walker The walker to use - */ -RENDERINGSHARED_EXPORT 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 - */ -RENDERINGSHARED_EXPORT void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision); - -/** - * Order the walker to subdivide the previous segment in smaller segments. - * - * Next steps will yield subdivided segments. Once subdivided segments have been processed, normal walking - * will resume automatically. - * @param walker The walker to use - * @param max_segments Maximal number of segments - */ -RENDERINGSHARED_EXPORT void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments); - -/** - * Get the last segment information. - * - * @param walker The walker to use - */ -RENDERINGSHARED_EXPORT 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 - */ -RENDERINGSHARED_EXPORT void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data); - -#endif diff --git a/src/rendering/clouds/private.h b/src/rendering/clouds/private.h deleted file mode 100644 index 3abf0b9..0000000 --- a/src/rendering/clouds/private.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _PAYSAGES_CLOUDS_PRIVATE_H_ -#define _PAYSAGES_CLOUDS_PRIVATE_H_ - -#include "public.h" - -#define CLOUDS_MAX_LAYERS 6 -#define MAX_SEGMENT_COUNT 100 - -void cloudsLayerValidateDefinition(CloudLayerDefinition* definition); - -Color cloudsLayerFilterLight(CloudLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light); -Color cloudsApplyLayer(CloudLayerDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end); - -#endif diff --git a/src/rendering/clouds/public.h b/src/rendering/clouds/public.h deleted file mode 100644 index 45b2f3a..0000000 --- a/src/rendering/clouds/public.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _PAYSAGES_CLOUDS_PUBLIC_H_ -#define _PAYSAGES_CLOUDS_PUBLIC_H_ - -#include "../rendering_global.h" - -#include "../shared/types.h" -#include "../tools/lighting.h" -#include "SurfaceMaterial.h" - -typedef Color (*FuncCloudsGetColor)(Renderer* renderer, Color base, Vector3 start, Vector3 end); -typedef double (*FuncCloudsGetLayerDensity)(Renderer* renderer, CloudLayerDefinition* layer, Vector3 location); -typedef double (*FuncCloudsGetEdgeDensity)(Renderer* renderer, CloudLayerDefinition* layer, Vector3 location, double layer_density); - -class CloudsRenderer -{ -public: - CloudsDefinition* definition; - - FuncCloudsGetColor getColor; - FuncLightingAlterLight alterLight; - FuncCloudsGetLayerDensity getLayerDensity; - FuncCloudsGetEdgeDensity getEdgeDensity; -}; - - -RENDERINGSHARED_EXPORT extern StandardRenderer CloudsRendererClass; - -#endif diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 67cee67..bcaf07b 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -7,7 +7,6 @@ #include "RenderingScenery.h" #include "CameraDefinition.h" #include "atmosphere/public.h" -#include "clouds/public.h" #include "terrain/public.h" #include "textures/public.h" #include "water/public.h" @@ -18,7 +17,7 @@ static void* _renderFirstPass(void* data) { Renderer* renderer = (Renderer*)data; - sceneryRenderFirstPass(renderer); + renderer->rasterize(); renderer->is_rendering = 0; return NULL; } @@ -139,7 +138,6 @@ Renderer::Renderer() lighting = lightingManagerCreate(); atmosphere = (AtmosphereRenderer*)AtmosphereRendererClass.create(); - clouds = (CloudsRenderer*)CloudsRendererClass.create(); terrain = (TerrainRenderer*)TerrainRendererClass.create(); textures = (TexturesRenderer*)TexturesRendererClass.create(); water = (WaterRenderer*)WaterRendererClass.create(); @@ -151,7 +149,6 @@ Renderer::~Renderer() lightingManagerDelete(lighting); AtmosphereRendererClass.destroy(atmosphere); - CloudsRendererClass.destroy(clouds); TerrainRendererClass.destroy(terrain); TexturesRendererClass.destroy(textures); WaterRendererClass.destroy(water); @@ -159,10 +156,8 @@ Renderer::~Renderer() renderDeleteArea(render_area); } -Color Renderer::applyMediumTraversal(Vector3 location, Color color) +Color Renderer::applyMediumTraversal(Vector3, Color color) { - color = atmosphere->applyAerialPerspective(this, location, color).final; - color = clouds->getColor(this, color, getCameraLocation(this, location), location); return color; } diff --git a/src/rendering/renderer.h b/src/rendering/renderer.h index 718ea01..145cd57 100644 --- a/src/rendering/renderer.h +++ b/src/rendering/renderer.h @@ -9,7 +9,6 @@ class LightingManager; class AtmosphereRenderer; class TerrainRenderer; class TexturesRenderer; -class CloudsRenderer; class WaterRenderer; class Renderer @@ -19,6 +18,7 @@ public: virtual ~Renderer(); virtual void prepare() {} + virtual void rasterize() {} virtual void setScenery(Scenery*) {} /* Render base configuration */ @@ -57,7 +57,6 @@ public: AtmosphereRenderer* atmosphere; TerrainRenderer* terrain; TexturesRenderer* textures; - CloudsRenderer* clouds; WaterRenderer* water; /* Custom data */ diff --git a/src/rendering/rendering.pro b/src/rendering/rendering.pro index bfa5c47..5e93cc9 100644 --- a/src/rendering/rendering.pro +++ b/src/rendering/rendering.pro @@ -12,11 +12,7 @@ SOURCES += main.cpp \ renderer.cpp \ render.cpp \ atmosphere/atm_render.cpp \ - atmosphere/atm_raster.cpp \ atmosphere/atm_bruneton.cpp \ - clouds/clo_walking.cpp \ - clouds/clo_rendering.cpp \ - clouds/clo_density.cpp \ terrain/ter_render.cpp \ terrain/ter_raster.cpp \ terrain/ter_painting.cpp \ @@ -38,10 +34,6 @@ HEADERS += \ main.h \ atmosphere/public.h \ atmosphere/private.h \ - clouds/public.h \ - clouds/private.h \ - clouds/clo_walking.h \ - clouds/clo_density.h \ shared/types.h \ terrain/ter_raster.h \ terrain/public.h \ diff --git a/src/tests/Clouds_Test.cpp b/src/tests/Clouds_Test.cpp index 6b6d7af..c554a45 100644 --- a/src/tests/Clouds_Test.cpp +++ b/src/tests/Clouds_Test.cpp @@ -1,13 +1,12 @@ #include "BaseTestCase.h" #include -#include "renderer.h" -#include "clouds/public.h" -#include "clouds/clo_density.h" -#include "clouds/clo_walking.h" +#include "SoftwareRenderer.h" #include "CloudLayerDefinition.h" #include "NoiseGenerator.h" +#if 0 + TEST(Clouds, Density) { /* Setup */ @@ -448,3 +447,5 @@ TEST(Clouds, WalkingLocal) ASSERT_DOUBLE_EQ(segment->end.global_density, 0.809016994375); ASSERT_DOUBLE_EQ(segment->end.local_density, 0.654508497187); } + +#endif